Skip to content
This repository was archived by the owner on Jan 5, 2024. It is now read-only.

Commit c5302d0

Browse files
committed
HumanFunctions tweaks and comment formatting, squad dynamics
1 parent a52f92c commit c5302d0

File tree

3 files changed

+122
-101
lines changed

3 files changed

+122
-101
lines changed

Base.rte/AI/HumanAI.lua

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
dofile("Base.rte/Constants.lua")
22
require("AI/NativeHumanAI")
3-
require("AI/HumanFunctions");
3+
require("AI/HumanFunctions")
44

55
function Create(self)
66
self.AI = NativeHumanAI:Create(self);
7-
-- You can turn features on and off here
7+
--You can turn features on and off here
88
self.armSway = true;
99
self.automaticEquip = true;
1010
self.alternativeGib = true;
@@ -21,10 +21,10 @@ function Update(self)
2121
HumanFunctions.DoAutomaticEquip(self);
2222
end
2323
if self.armSway then
24-
HumanFunctions.DoArmSway(self, 10); -- Argument: shove strength
24+
HumanFunctions.DoArmSway(self, (self.Health / self.MaxHealth)); --Argument: shove strength
2525
end
2626
if self.visibleInventory then
27-
HumanFunctions.DoVisibleInventory(self, false); -- Argument: whether to show all items
27+
HumanFunctions.DoVisibleInventory(self, false); --Argument: whether to show all items
2828
end
2929
end
3030
function UpdateAI(self)

Base.rte/AI/HumanFunctions.lua

Lines changed: 54 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
HumanFunctions = {};
22

33
function HumanFunctions.DoAlternativeGib(actor)
4-
-- Detach limbs instead of regular gibbing
4+
--Detach limbs instead of regular gibbing
55
if not actor.detachLimit then
66
actor.detachLimit = actor.GibWoundLimit;
77
actor.GibWoundLimit = actor.GibWoundLimit * 1.5;
88
end
99
if actor.WoundCount > actor.detachLimit then
1010
actor.detachLimit = actor.WoundCount + 1;
11-
local parts = {actor.BGArm, actor.BGLeg, actor.FGArm, actor.FGLeg, actor.Head}; -- Piority order
11+
local parts = {actor.BGArm, actor.BGLeg, actor.FGArm, actor.FGLeg, actor.Head}; --Piority order
1212
local mostWounds = -1;
1313
local detachLimb;
14-
-- Pick the limb with most wounds and detach it
14+
--Pick the limb with most wounds and detach it
1515
for i = 1, #parts do
1616
local limb = parts[i];
1717
if limb and limb.WoundCount > mostWounds then
@@ -26,87 +26,101 @@ function HumanFunctions.DoAlternativeGib(actor)
2626
end
2727

2828
function HumanFunctions.DoAutomaticEquip(actor)
29-
-- Equip a weapon automatically if the one held by a player is destroyed
29+
--Equip a weapon automatically if the one held by a player is destroyed
3030
if actor:IsPlayerControlled() and actor.EquippedItem == nil and actor.InventorySize > 0 and not actor.controller:IsState(Controller.WEAPON_FIRE) then
3131
actor:EquipFirearm(true);
3232
end
3333
end
3434

3535
function HumanFunctions.DoArmSway(actor, pushStrength)
36-
-- Control arm movements
37-
if not actor.lastHandPos then
38-
actor.lastAngle = actor:GetAimAngle(false);
36+
--Control arm movements
37+
local aimAngle = actor:GetAimAngle(false);
38+
if not actor.lastHandPos then --Initialize
39+
actor.lastAngle = aimAngle;
3940
actor.lastHandPos = {actor.Pos, actor.Pos};
4041
end
4142
if actor.controller:IsMouseControlled() then
42-
-- Flail around if moving mouse too fast
43+
--Flail around if moving mouse too fast
4344
local mouseVec = Vector(actor.controller.MouseMovement.X, actor.controller.MouseMovement.Y):SetMagnitude(math.sqrt(actor.controller.MouseMovement.Magnitude));
44-
local ang = actor.lastAngle - actor:GetAimAngle(false);
45+
local ang = actor.lastAngle - aimAngle;
4546

4647
actor.AngularVel = actor.AngularVel - (2 * ang * actor.FlipFactor + mouseVec.Y * actor.FlipFactor /10) /math.sqrt(math.abs(actor.AngularVel) + 1);
4748

48-
actor.lastAngle = actor:GetAimAngle(false);
49+
actor.lastAngle = aimAngle;
4950
end
50-
-- Shove when unarmed
51+
--Shove when unarmed
5152
if actor.controller:IsState(Controller.WEAPON_FIRE) and (actor.FGArm or actor.BGArm) and not (actor.EquippedItem or actor.EquippedBGItem) and actor.Status == Actor.STABLE then
52-
actor.AngularVel = actor.AngularVel /(actor.shoved and 1.5 or 3) + (actor:GetAimAngle(false) - actor.RotAngle * actor.FlipFactor - 1.57) * (actor.shoved and 0.5 or 3) * actor.FlipFactor /(1 + math.abs(actor.RotAngle));
53+
actor.AngularVel = actor.AngularVel /(actor.shoved and 1.3 or 3) + (aimAngle - actor.RotAngle * actor.FlipFactor - 1.57) * (actor.shoved and 0.3 or 3) * actor.FlipFactor /(1 + math.abs(actor.RotAngle));
5354
if not actor.shoved then
54-
actor.Vel = actor.Vel + Vector(3 /(1 + actor.Vel.Magnitude), 0):RadRotate(actor:GetAimAngle(true)) * math.abs(math.cos(actor:GetAimAngle(true)));
55+
actor.Vel = actor.Vel + Vector(2 /(1 + actor.Vel.Magnitude), 0):RadRotate(actor:GetAimAngle(true)) * math.abs(math.cos(actor:GetAimAngle(true)));
5556
actor.shoved = true;
5657
end
5758
else
5859
actor.shoved = false;
5960
end
60-
local arms = {{actor.FGArm, actor.FGLeg, actor.BGLeg}, {actor.BGArm, actor.BGLeg, actor.FGLeg}};
61-
for i = 1, #arms do
62-
local arm = arms[i][1];
61+
local armPairs = {{actor.FGArm, actor.FGLeg, actor.BGLeg}, {actor.BGArm, actor.BGLeg, actor.FGLeg}};
62+
for i = 1, #armPairs do
63+
local arm = armPairs[i][1];
6364
if arm then
64-
local arm = ToArm(arms[i][1]);
65+
arm = ToArm(arm);
66+
6567
local armLength = ToMOSprite(arm):GetSpriteWidth();
6668
local rotAng = actor.RotAngle - (1.57 * actor.FlipFactor);
67-
local legMain = arms[i][2];
68-
local legAlt = arms[i][3];
69+
local legMain = armPairs[i][2];
70+
local legAlt = armPairs[i][3];
6971

7072
if actor.controller:IsState(Controller.MOVE_LEFT) or actor.controller:IsState(Controller.MOVE_RIGHT) then
71-
if legAlt then
72-
rotAng = legAlt.RotAngle;
73-
elseif legMain then
74-
rotAng = -legMain.RotAngle + math.pi;
75-
end
73+
rotAng = (legAlt and legAlt.RotAngle) or (legMain and (-legMain.RotAngle + math.pi) or rotAng);
7674
elseif legMain then
7775
rotAng = legMain.RotAngle;
7876
end
79-
-- Flail arms in tandem with leg movement
80-
ToArm(arm).IdleOffset = Vector(0, armLength * 0.7):RadRotate(rotAng * actor.FlipFactor + 1.5 + (i /5));
81-
77+
--Flail arms in tandem with leg movement or raise them them up for a push if aiming
78+
if actor.controller:IsState(Controller.AIM_SHARP) then
79+
arm.IdleOffset = Vector(0, 1):RadRotate(aimAngle);
80+
else
81+
arm.IdleOffset = Vector(0, (armLength + arm.SpriteOffset.X) * 1.1):RadRotate(rotAng * actor.FlipFactor + 1.5 + (i /5));
82+
end
8283
if actor.shoved or (actor.EquippedItem and IsTDExplosive(actor.EquippedItem) and actor.controller:IsState(Controller.WEAPON_FIRE)) then
83-
arm.IdleOffset = Vector(armLength, 0):RadRotate(actor:GetAimAngle(false));
84-
local dist = SceneMan:ShortestDistance(actor.lastHandPos[i], arm.HandPos, SceneMan.SceneWrapsX);
85-
86-
local dots = math.sqrt(arm.Radius) * (arm.Frame /arm.FrameCount);
87-
84+
arm.IdleOffset = Vector(armLength + (pushStrength * armLength), 0):RadRotate(aimAngle);
85+
local handVector = SceneMan:ShortestDistance(actor.lastHandPos[i], arm.HandPos, SceneMan.SceneWrapsX);
86+
--Diminish hand relocation vector to potentially prevent post-superhuman pushing powers
87+
handVector:SetMagnitude(handVector.Magnitude / (1 + handVector.Magnitude / 100));
88+
--Emphasize the first frames that signify contracted arm = highest potential energy
89+
local dots = math.sqrt(arm.Radius) / (1 + arm.Frame /arm.FrameCount);
90+
local armStrength = (arm.Mass + arm.Material.StructuralIntegrity) * pushStrength;
8891
for i = 1, dots do
8992
local part = CreateMOPixel("Smack Particle Light");
9093
part.Pos = arm.HandPos;
91-
part.Vel = (actor.Vel + dist):SetMagnitude(math.sqrt(dist.Magnitude * pushStrength + math.abs(actor.AngularVel) * actor.Vel.Magnitude)):RadRotate(0.8 /dots * i) + Vector(0, -0.5);
92-
part.Mass = (arm.Mass + arm.Material.StructuralIntegrity) * pushStrength; part.Sharpness = math.random() * 0.1;
94+
part.Vel = Vector(handVector.X, handVector.Y):RadRotate(RangeRand(-0.1, 0.1)) * pushStrength + Vector(0, -0.5);
95+
part.Mass = armStrength; part.Sharpness = math.random() * 0.1;
9396
part.Team = actor.Team; part.IgnoresTeamHits = true;
9497
MovableMan:AddParticle(part);
9598
end
99+
--Apply some additional forces if the travel vector of the moving hand is half an arms length
100+
if handVector.Magnitude > (armLength /2) then
101+
local moCheck = SceneMan:GetMOIDPixel(arm.HandPos.X, arm.HandPos.Y)
102+
if moCheck ~= rte.NoMOID then
103+
local mo = MovableMan:GetMOFromID(MovableMan:GetMOFromID(moCheck).RootID);
104+
if mo and mo.Team ~= actor.Team and IsActor(mo) and actor.Mass > (mo.Mass / 2) then
105+
mo:AddForce(handVector * (actor.Mass / 2), Vector());
106+
ToActor(mo).Status = Actor.UNSTABLE;
107+
end
108+
end
109+
end
96110
end
97111
actor.lastHandPos[i] = arm.HandPos;
98112
end
99113
end
100114
end
101115

102116
function HumanFunctions.DoVisibleInventory(actor, showAll)
103-
-- Visualize inventory with primitive bitmaps
117+
--Visualize inventory with primitive bitmaps
104118
if actor.Status < Actor.DYING and not actor:IsInventoryEmpty() then
105119
local heldCount, thrownCount, largestItem = 0, 0, 0;
106120
for i = 1, actor.InventorySize do
107121
local item = actor:Inventory();
108122
if item then
109-
local fixNum = actor.HFlipped and -1 or 0; -- Fix offsets slightly when facing left
123+
local fixNum = actor.HFlipped and -1 or 0; --Fix offsets slightly when facing left
110124
if item.ClassName == "TDExplosive" then
111125
thrownCount = thrownCount + 1;
112126
elseif item.ClassName == "HDFirearm" or item.ClassName == "HeldDevice" then
@@ -119,16 +133,13 @@ function HumanFunctions.DoVisibleInventory(actor, showAll)
119133

120134
fixNum = fixNum + item.Radius * 0.2 + math.sqrt(heldCount);
121135

122-
-- Bigger actors carry weapons higher up, smaller weapons are carried lower down
136+
--Bigger actors carry weapons higher up, smaller weapons are carried lower down
123137
local drawPos = actor.Pos + Vector((-actorSize - fixNum) * actor.FlipFactor, -actorSize - itemSize + 1 + isFirearm * 3):RadRotate(actor.RotAngle);
124138

125139
local itemCount = math.sqrt(math.abs(actor.InventorySize - thrownCount));
126-
127-
-- Display tall objects upright
128-
local tallAng = 1.57;
129-
if ToMOSprite(item):GetSpriteWidth() < ToMOSprite(item):GetSpriteHeight() then
130-
tallAng = 0;
131-
end
140+
--Display tall objects upright
141+
local tallAng = ToMOSprite(item):GetSpriteWidth() > ToMOSprite(item):GetSpriteHeight() and 1.57 or 0;
142+
132143
local tilt = 0.3;
133144
local rotAng = actor.RotAngle + tallAng + (heldCount * tilt - itemCount * tilt + isFirearm /itemSize) /itemCount * actor.FlipFactor;
134145

Base.rte/AI/NativeHumanAI.lua

Lines changed: 64 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -341,74 +341,78 @@ function NativeHumanAI:Update(Owner)
341341
end
342342
end
343343

344-
if Leader and Leader.EquippedItem and SceneMan:ShortestDistance(Owner.Pos, Leader.Pos, false).Largest < (Leader.Height + Owner.Height) * 0.5 then
345-
346-
if IsHDFirearm(Leader.EquippedItem) then
347-
348-
local LeaderWeapon = ToHDFirearm(Leader.EquippedItem)
349-
if LeaderWeapon:IsWeapon() then
350-
local AimDelta = SceneMan:ShortestDistance(Leader.Pos, Leader.ViewPoint, false)
351-
self.Ctrl.AnalogAim = SceneMan:ShortestDistance(Owner.Pos, Leader.ViewPoint+AimDelta, false).Normalized
352-
self.deviceState = AHuman.POINTING
353-
354-
-- check if the SL is shooting and if we have a similar weapon
355-
if Owner.FirearmIsReady then
356-
self.deviceState = AHuman.AIMING
357-
358-
if IsHDFirearm(Owner.EquippedItem) and Leader:GetController():IsState(Controller.WEAPON_FIRE) then
359-
local OwnerWeapon = ToHDFirearm(Owner.EquippedItem)
360-
if OwnerWeapon:IsTool() then
361-
-- try equipping a weapon
362-
if Owner.InventorySize > 0 and not Owner:EquipDeviceInGroup("Weapons - Primary", true) then
363-
Owner:EquipFirearm(true)
364-
end
365-
elseif LeaderWeapon:GetAIBlastRadius() >= OwnerWeapon:GetAIBlastRadius() * 0.5 and
366-
OwnerWeapon:CompareTrajectories(LeaderWeapon) < math.max(100, OwnerWeapon:GetAIBlastRadius())
367-
then
368-
-- slightly displace full-auto shots to diminish stacking sounds and create a more dense fire rate
369-
if OwnerWeapon.FullAuto then
370-
if math.random() < 0.3 then
344+
if Leader then
345+
if Leader.EquippedItem and SceneMan:ShortestDistance(Owner.Pos, Leader.Pos, false).Largest < (Leader.Height + Owner.Height) * 0.5 then
346+
347+
if IsHDFirearm(Leader.EquippedItem) then
348+
349+
local LeaderWeapon = ToHDFirearm(Leader.EquippedItem)
350+
if LeaderWeapon:IsWeapon() then
351+
local AimDelta = SceneMan:ShortestDistance(Leader.Pos, Leader.ViewPoint, false)
352+
self.Ctrl.AnalogAim = SceneMan:ShortestDistance(Owner.Pos, Leader.ViewPoint+AimDelta, false).Normalized
353+
self.deviceState = AHuman.POINTING
354+
355+
-- check if the SL is shooting and if we have a similar weapon
356+
if Owner.FirearmIsReady then
357+
self.deviceState = AHuman.AIMING
358+
359+
if IsHDFirearm(Owner.EquippedItem) and Leader:GetController():IsState(Controller.WEAPON_FIRE) then
360+
local OwnerWeapon = ToHDFirearm(Owner.EquippedItem)
361+
if OwnerWeapon:IsTool() then
362+
-- try equipping a weapon
363+
if Owner.InventorySize > 0 and not Owner:EquipDeviceInGroup("Weapons - Primary", true) then
364+
Owner:EquipFirearm(true)
365+
end
366+
elseif LeaderWeapon:GetAIBlastRadius() >= OwnerWeapon:GetAIBlastRadius() * 0.5 and
367+
OwnerWeapon:CompareTrajectories(LeaderWeapon) < math.max(100, OwnerWeapon:GetAIBlastRadius())
368+
then
369+
-- slightly displace full-auto shots to diminish stacking sounds and create a more dense fire rate
370+
if OwnerWeapon.FullAuto then
371+
if math.random() < 0.3 then
372+
self.Target = nil
373+
self.squadShoot = true
374+
end
375+
else
371376
self.Target = nil
372377
self.squadShoot = true
373378
end
374-
else
375-
self.Target = nil
376-
self.squadShoot = true
377379
end
380+
else
381+
self.squadShoot = false
378382
end
379383
else
380-
self.squadShoot = false
381-
end
382-
else
383-
if Owner.FirearmIsEmpty then
384-
Owner:ReloadFirearm()
385-
elseif Owner.InventorySize > 0 and not Owner:EquipDeviceInGroup("Weapons - Primary", true) then
386-
Owner:EquipFirearm(true)
384+
if Owner.FirearmIsEmpty then
385+
Owner:ReloadFirearm()
386+
elseif Owner.InventorySize > 0 and not Owner:EquipDeviceInGroup("Weapons - Primary", true) then
387+
Owner:EquipFirearm(true)
388+
end
387389
end
388390
end
389-
end
390-
elseif IsTDExplosive(Leader.EquippedItem) and Leader:IsPlayerControlled() then
391-
-- throw grenades in unison with squad
392-
if ToTDExplosive(Leader.EquippedItem):HasObjectInGroup("Bombs - Grenades") and Owner:HasObjectInGroup("Bombs - Grenades") then
391+
elseif IsTDExplosive(Leader.EquippedItem) and Leader:IsPlayerControlled() then
392+
-- throw grenades in unison with squad
393+
if ToTDExplosive(Leader.EquippedItem):HasObjectInGroup("Bombs - Grenades") and Owner:HasObjectInGroup("Bombs - Grenades") then
393394

394-
self.Ctrl.AnalogAim = SceneMan:ShortestDistance(Leader.Pos, Leader.ViewPoint, false).Normalized
395-
self.deviceState = AHuman.POINTING
395+
self.Ctrl.AnalogAim = SceneMan:ShortestDistance(Leader.Pos, Leader.ViewPoint, false).Normalized
396+
self.deviceState = AHuman.POINTING
396397

397-
if Leader:GetController():IsState(Controller.WEAPON_FIRE) then
398+
if Leader:GetController():IsState(Controller.WEAPON_FIRE) then
398399

399-
Owner:EquipDeviceInGroup("Bombs - Grenades", true)
400+
Owner:EquipDeviceInGroup("Bombs - Grenades", true)
400401

401-
self.Target = nil
402-
self.squadShoot = true
403-
else
404-
self.squadShoot = false
402+
self.Target = nil
403+
self.squadShoot = true
404+
else
405+
self.squadShoot = false
406+
end
405407
end
406408
end
407409
end
408-
end
409-
if Leader and Leader.AIMode == Actor.AIMODE_GOLDDIG then
410-
Owner.AIMode = Actor.AIMODE_GOLDDIG
411-
Owner:ClearMovePath()
410+
if Leader.AIMode == Actor.AIMODE_GOTO then
411+
Owner.leaderWaypoint = Leader:GetLastAIWaypoint()
412+
elseif Leader.AIMode ~= Actor.AIMODE_SENTRY then
413+
Owner.AIMode = Leader.AIMode
414+
Owner:ClearMovePath()
415+
end
412416
end
413417
end
414418
end
@@ -419,8 +423,14 @@ function NativeHumanAI:Update(Owner)
419423

420424
-- if we are in AIMODE_SQUAD the leader just got killed
421425
if Owner.AIMode == Actor.AIMODE_SQUAD then
422-
Owner.AIMode = Actor.AIMODE_SENTRY
423426
Owner:ClearMovePath()
427+
if Owner.leaderWaypoint then
428+
Owner.AIMode = Actor.AIMODE_GOTO
429+
Owner:AddAISceneWaypoint(Owner.leaderWaypoint)
430+
Owner.leaderWaypoint = nil
431+
else
432+
Owner.AIMode = Actor.AIMODE_SENTRY
433+
end
424434
end
425435
end
426436
elseif Owner.AIMode == Actor.AIMODE_SQUAD then -- if we are in AIMODE_SQUAD the leader just got killed

0 commit comments

Comments
 (0)