Advertisement
Guest User

Untitled

a guest
Jun 6th, 2018
72
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 27.73 KB | None | 0 0
  1.  
  2.  
  3. AddCSLuaFile()
  4.  
  5. ENT.Base            = "base_nextbot"
  6. ENT.Spawnable       = false
  7.  
  8.  
  9.  
  10. ENT.backuptime = 0;
  11. ENT.liveframes = 0;
  12. ENT.aiframes = 0;
  13. ENT.lastdoortimeout = 0;
  14. ENT.fallvel = 0;
  15. ENT.strafevec = Vector(0, 0, 0);
  16. ENT.backupgoal = Vector(0, 0, 0);
  17. ENT.pathTime = 0;
  18. ENT.searchtime = 0;
  19. ENT.wakeuptime = 0;
  20.  
  21. --Behavior information
  22. --When should we next update our behavior?
  23. ENT.nextbtime = 0.01;
  24.  
  25. --Should we animate through BodyMove?
  26. ENT.useBodyMove = false;
  27.  
  28. --Pathing and locomotion information
  29. ENT.goal = Vector(0, 0, 0);
  30. --Where are we trying to path to right now? Of type PathSegment
  31. --Such a big hack, but PathFollower's update is too limiting.
  32. ENT.pathGoal = nil;
  33. ENT.curNode = 0;
  34. --What should we face while moving? nil=current goal, other=that target is faced
  35. ENT.faceTarget = nil;
  36.  
  37. --Vision information
  38. --When can we look for a new target?
  39. ENT.targetTime = 0.01;
  40. --Can we see our current target right now?
  41. ENT.canSeeTarget = false;
  42. --Where did we last see our target?
  43. ENT.lastSeenPos = Vector(0, 0, 0);
  44. --When can we next check if we can see the target?
  45. ENT.checkVisTime = 0.01;
  46. --For ambushing, should we look all around?
  47. ENT.ambushMode = false;
  48.  
  49. --Spawn in animations
  50. local BEHAVIOR_SPAWN = 0;
  51. --Stand, looking for target. Patrol on occasion
  52. local BEHAVIOR_STAND = 1;
  53. --Looking for target while moving to patrol point
  54. local BEHAVIOR_PATROL = 2;
  55. --Running straight to the target
  56. local BEHAVIOR_CHASE = 3;
  57. --Attempting to pick up a health kit while tracking target
  58. local BEHAVIOR_FINDHEALTH = 4;
  59. --For ranged attackers, found and looking for a point to engage
  60. local BEHAVIOR_FINDENGAGE = 5;
  61. --For ranged attackers, at our engaging point and attempting to shoot the target
  62. local BEHAVIOR_ENGAGING = 6;
  63. --I lost sight of my target, go check out the last visibile point
  64. local BEHAVIOR_LOSTVIS = 7;
  65. --I cannot see my target at the new point, I'm going to patrol for them
  66. local BEHAVIOR_TARGETPATROL = 8;
  67. --I cannot see my target at the new point, I'm going to lay in ambush
  68. local BEHAVIOR_FINDAMBUSH = 9;
  69. --I have decided on an amubsh point, and will stay here until I find vis
  70. local BEHAVIOR_AMBUSH = 10;
  71.  
  72. function ENT:Initialize()
  73.  
  74.     self:SetModel( "models/player/charple.mdl" );
  75.     self:SetSolid(SOLID_BBOX);
  76.     self:PhysicsInitShadow(false, false);
  77.    
  78.     --self:SetMaxHealth(40);
  79.     self:SetHealth(40);
  80.     --self:SetTarget(Entity(1));
  81.    
  82.     --wait a bit before doing a thing
  83.     self.pathtime = CurTime() + 0.1;
  84.     self.searchtime = CurTime() + 0.1;
  85.    
  86.     self:SetAIPhase(0);
  87.     if (SERVER) then
  88.         self:NewBehavior(BEHAVIOR_SPAWN);
  89.        
  90.         self.loco:SetMaxYawRate(180);
  91.         self.loco:SetAcceleration(2400);
  92.         self.loco:SetJumpHeight(58);
  93.         self.loco:SetStepHeight(32);
  94.     end
  95. end
  96.  
  97. function ENT:Classify()
  98.     return CLASS_ZOMBIE;
  99. end
  100.  
  101. function ENT:SetupDataTables()
  102.     self:NetworkVar( "Int", 0, "AIPhase" )
  103.     self:NetworkVar( "Int", 0, "Behavior" )
  104. end
  105.  
  106. function ENT:SetTarget(ent)
  107.     self.target = ent;
  108.     self.lastSeenPos = self.target:GetPos();
  109. end
  110.  
  111. function ENT:InvalidateTarget()
  112.     self.targetTime = 0.01;
  113.     self.target = nil;
  114. end
  115.  
  116. function ENT:GetTargetGoal()
  117.     if (self.canSeeTarget) then
  118.         --print("Going to target");
  119.         return self.target;
  120.     end
  121.     --print("Going to last seen");
  122.     return self.lastSeenPos;
  123. end
  124.  
  125. function ENT:UpdateTargetVis()
  126. --tr = util.TraceLine({start = self:EyePos(), endpos = testnode.pos, mask = MASK_SOLID_BRUSHONLY});
  127.     if (CurTime() < self.checkVisTime) then
  128.         return;
  129.     end
  130.     if (self.target == nil) then
  131.         return;
  132.     end
  133.    
  134.     --Do a trace to our target
  135.     local vis = self:Visible(self.target);
  136.    
  137.     if (vis) then
  138.         print("I can see target");
  139.         self.canSeeTarget = true;
  140.         self.lastSeenPos = self.target:GetPos();
  141.     else
  142.         self.canSeeTarget = false;
  143.         print("I cannot see you");
  144.     end
  145.    
  146.     self.checkVisTime = CurTime() + 0.5;
  147. end
  148.  
  149. ----------------------------------------------------
  150. -- ENT:FindEnemy()
  151. -- Returns true and sets our enemy if we find one
  152. ----------------------------------------------------
  153. function ENT:FindTarget()
  154.     --Do we like our target?
  155.     if (CurTime() < self.targetTime) then
  156.         return;
  157.     end
  158.    
  159.     local testent;
  160.     -- Search around us for entities
  161.     -- This can be done any way you want eg. ents.FindInCone() to replicate eyesight
  162.     --print(self:GetForward().x .. " " .. self:GetForward().y .. " " .. self:GetForward().z);
  163.     --local _ents = ents.FindInCone(self:GetPos() + Vector(0, 0, 32), self:GetForward(), 1000, 45); --this doesn't work?
  164.     local _ents = ents.FindInSphere(self:GetPos(), 768);
  165.     -- Here we loop through every entity the above search finds and see if it's the one we want
  166.     for k, v in pairs( _ents ) do
  167.         --print(v:GetClass());
  168.         if (v:GetClass() == "npc_metropolice" || v:GetClass() == "npc_barney" || v:GetClass() == "npc_kleiner") then
  169.             targetvec = v:GetPos() - self:GetPos();
  170.             targetvec:Normalize();
  171.             ldot = targetvec:Dot(self:GetForward())
  172.             if (ldot > 0.70 || self.ambushMode) then
  173.                 testent = v;
  174.                 break;
  175.             end
  176.         elseif (v:GetClass() == "doom_npc_vile") then
  177.             testent = v;
  178.             break;
  179.         --try targeting other CharPles
  180.         elseif (v:GetClass() == "npc_ibbot" && v != self) then
  181.             testent = v;
  182.             break;
  183.         --elseif ( v:IsPlayer() ) then
  184.         --  if (self:GetAIPhase() == 0) then
  185.         --      targetvec = self:GetPos() - v:GetPos();
  186.         --      targetvec:Normalize();
  187.         --      ldot = targetvec:Dot(v:GetForward())
  188.         --      if (ldot > 0.9) then
  189.         --          self:SetAIPhase(1);
  190.         --          self:SetTarget( v )
  191.         --          return true
  192.         --      end
  193.         --  end
  194.         end
  195.     end
  196.    
  197.     if (testent == nil) then
  198.         --Keep our current target and just look again later
  199.         --print("no target");
  200.         self.targetTime = CurTime() + 0.2;
  201.         return
  202.     end
  203.     --print("we found a dude");
  204.     --Otherwise set the new entity
  205.     self:SetTarget(testent);
  206.     self.ambushMode = false;
  207.     --Follow this target exclusively for 7 seconds
  208.     self.targetTime = CurTime() + 7.0;
  209.    
  210. end
  211.  
  212. function ENT:BehaveAct()
  213.  
  214. end
  215.  
  216. function ENT:OnStuck()
  217.     --self:SetVelocity(Vector(0, 0, 0));
  218.     --efdata = EffectData();
  219.     --efdata:SetOrigin(self:GetPos());
  220.     --util.Effect("explosion", efdata);
  221.     --util.BlastDamage(self, self, self:GetPos(), 150, 40);
  222.     --self:TakeDamage(1000, self, self);
  223.     --self:ClearStuck();
  224. end
  225.  
  226. function ENT:OnContact(ent)
  227.     if (ent:GetClass() == "player") then
  228.         --ent:TakeDamage(1, self, self);
  229.         --util.BlastDamage(self, self, self:GetPos(), 150, 40);
  230.         --ent:TakeDamage(25, self, self);
  231.         --ent:Ignite(5);
  232.         --give a jolt
  233.         --self:SetVelocity(Vector(0, 0, 200));
  234.         --efdata = EffectData();
  235.         --efdata:SetOrigin(self:GetPos());
  236.         --util.Effect("explosion", efdata);
  237.         --self:TakeDamage(1000, self, self);
  238.         self.heh = true;
  239.     elseif (ent:GetClass() == "npc_metropolice" || ent:GetClass() == "npc_ibbot") then
  240.         ent:Ignite();
  241.         ent:TakeDamage(1000, self, self);
  242.         self:TakeDamage(1000, self, self);
  243.     elseif (ent:GetClass() == "npc_barney") then
  244.         ent:Ignite(100);
  245.         self:SetVelocity(Vector(0, 0, 0));
  246.         self:TakeDamage(1000, self, self);
  247.     --also used as emergency situation if something not targeted pissed it off
  248.     --but only if they aren't a player. ugh.
  249.     elseif (ent:GetClass() == "npc_kleiner" || ent:GetClass() == "doom_npc_vile" || (ent == self.target && !ent:IsPlayer())) then
  250.         ent:SetVelocity(ent:GetVelocity() + Vector(0, 0, 1000));
  251.         self:SetVelocity(Vector(0, 0, 100));
  252.         self:TakeDamage(1000, self, self);
  253.     --cheap smashing!
  254.     elseif ((ent:GetClass() == "func_breakable_surf" || ent:GetClass() == "prop_physics" || ent:GetClass() == "func_breakable")) then
  255.         ent:TakeDamage(1000, self, self);
  256.     end
  257.    
  258. end
  259.  
  260. function ENT:Think()
  261.     if not SERVER then return end
  262.     --print("I'm using my brain!");
  263.  
  264.    
  265.    
  266.    
  267.     --if (self.loco:IsClimbingOrJumping() ) then
  268.         --print("fuck it I'm trying to climb or jump")
  269.     --end
  270.     physObj = self:GetPhysicsObject();
  271.     if (IsValid(physObj)) then
  272.         pos = self:GetPos();
  273.         ang = self:GetAngles();
  274.         physObj:UpdateShadow(pos, ang, FrameTime());
  275.         --physObj:UpdateShadow(pos, ang, 0);
  276.     end
  277.     return true
  278. end
  279.  
  280. function ENT:Use(activator, caller, type, value)
  281.     self.loco:Jump();
  282. end
  283.  
  284. function ENT:OnLeaveGround(entity)
  285.     if (!SERVER) then
  286.         return
  287.     end
  288.     --self:StartActivity(ACT_HL2MP_JUMP_PASSIVE);
  289. end
  290.  
  291. function ENT:OnInjured(dmginfo)
  292.     attacker = dmginfo:GetAttacker();
  293.     if (!IsValid(self.target) && IsValid(attacker)) then
  294.         --print("okay, now I'm pissed!");
  295.         --attacker:Ignite(5);
  296.         if (CurTime() < self.targetTime) then
  297.             --too soon for new target, but make it happen sooner
  298.             self.targetTime = self.targetTime - 0.5;
  299.         end
  300.         if (CurTime() > self.targetTime) then --try again! we might be able to change target
  301.             --can change now
  302.             self.target = attacker;
  303.         end
  304.     --elseif (IsValid(attacker) && attacker:GetClass() == "player" && self:GetAIPhase() == 0 && SERVER) then
  305.         --wake me up!
  306.         --self:SetAIPhase(1);
  307.         --self.target = attacker;
  308.     end
  309. end
  310.  
  311. function ENT:OnKilled( dmginfo )
  312.     --self.axe:Remove();
  313.     hook.Run( "OnNPCKilled", self, dmginfo:GetAttacker(), dmginfo:GetInflictor() )
  314.  
  315.     self:BecomeRagdoll( dmginfo )
  316.     --super():OnKilled(dmginfo)
  317. end
  318.  
  319. function ENT:BodyUpdate()
  320.     --print("Am I updated?")
  321.     --eh
  322.     if (self.useBodyMove) then
  323.         --MsgN("BodyMoveXY");
  324.         self:BodyMoveXY();
  325.     else
  326.         --MsgN("FrameAdvance");
  327.         self:FrameAdvance();
  328.     end
  329. end
  330.  
  331. function ENT:OnLandOnGround(ent)
  332.     if (!SERVER) then
  333.         return
  334.     end
  335.     --self:StartActivity(ACT_HL2MP_RUN_FIST);
  336.     if (self.loco:IsStuck()) then
  337.         --stupidly strafe some
  338.         --self:SetVelocity(Vector(0, math.Rand(-100, 100), 0));
  339.     end
  340.    
  341.     --print("hit ground at" .. self.fallvel);
  342.     --if (self.fallvel <= -800) then
  343.     --  self:TakeDamage(1000, self, self);
  344.     --end
  345.     self.fallvel = 0;
  346.     --print("heh");
  347.     self.heh2 = true;
  348. end
  349.  
  350. --We don't use the coroutine, so don't do anything
  351. function ENT:BehaveStart()
  352. end
  353.  
  354. --ugh, gmod
  355. --path computation function must be anonymous in order to use self...
  356. --split the messy function off into its own one
  357. function ENT:DoPathComputation(path, pos)
  358.     --print("time to compute path!");
  359.     path:Compute(self, pos, function(area, fromArea, ladder, elevator, length)
  360.     --print("Doing path computation");
  361.     if ( !IsValid( fromArea ) ) then
  362.         // first area in path, no cost
  363.         return 0
  364.  
  365.     else
  366.         if ( !self.loco:IsAreaTraversable( area ) ) then
  367.             // our locomotor says we can't move here
  368.             --print("Rejected location");
  369.             return -1
  370.         end
  371.  
  372.         // compute distance traveled along path so far
  373.         local dist = 0
  374.  
  375.         if ( IsValid( ladder ) ) then
  376.             --print("rejecting a ladder");
  377.             --dist = ladder:GetLength()
  378.             --absolutely no ladders, we can't mount them
  379.             return -1;
  380.         elseif ( length > 0 ) then
  381.             // optimization to avoid recomputing length
  382.             dist = length
  383.         else
  384.             dist = ( area:GetCenter() - fromArea:GetCenter() ):GetLength()
  385.         end
  386.  
  387.         local cost = dist + fromArea:GetCostSoFar()
  388.  
  389.         // check height change
  390.         local deltaZ = fromArea:ComputeAdjacentConnectionHeightChange(area)
  391.         --print("Evalulating height change of " .. deltaZ);
  392.         if (deltaZ >= 24) then
  393.             --need to check if the area is stairs
  394.             --if its stairs, we can walk up it
  395.             if (!area:HasAttributes(NAV_MESH_STAIRS) && !fromArea:HasAttributes(NAV_MESH_STAIRS)) then
  396.                 --print("Trying to climb too high!");
  397.                 return -1;
  398.             --else
  399.                 --print("Successfully navigated stairs");
  400.             end
  401.             --if ( deltaZ >= self.loco:GetMaxJumpHeight() ) then
  402.             --test
  403.             --maybe we won't try to ledge clime when we can't goddamned ledge climb!
  404.             --if ( deltaZ >= 24 ) then
  405.                 --// too high to reach
  406.                 --return -1
  407.             --end
  408.  
  409.             --// jumping is slower than flat ground
  410.             --local jumpPenalty = 5
  411.             --cost = cost + jumpPenalty * dist
  412.         --elseif ( deltaZ < -self.loco:GetDeathDropHeight() ) then
  413.             -- too far to drop
  414.             --return -1
  415.         end
  416.  
  417.         return cost
  418.     end
  419. end )
  420. end
  421.  
  422. function ENT:UpdateGoal()
  423.     if (CurTime() < self.pathTime) then
  424.         --print("its not time");
  425.         return;
  426.     end;
  427.  
  428.     local dest;
  429.     local targetvec;
  430.    
  431.     if (self.goal != nil) then
  432.         if (isentity(self.goal) && IsValid(self.goal)) then
  433.             --print("okay we have a target");
  434.             dest = self.goal:GetPos();
  435.         elseif (isvector(self.goal)) then
  436.             --print("okay we have a point");
  437.             dest = self.goal;
  438.         end
  439.     else
  440.         --print("our goal is not valid");
  441.         self.pathTime = CurTime() + 0.2;
  442.         return;
  443.     end
  444.    
  445.     local dist = self:DistanceToGoal();
  446.     --print("self is " .. self:GetPos().x .. " " .. self:GetPos().y .. " " .. self:GetPos().z);
  447.     --print("goal is " .. dest.x .. " " .. dest.y .. " " .. dest.z);
  448.    
  449.     if (dest != nil) then
  450.         if (dist < 20) then
  451.             --print("we're at the destination");
  452.             self.pathTime = CurTime() + 0.2;
  453.             return; --too short to do anything to
  454.         else
  455.             --print("time to find path!");
  456.             self:PathToPoint(dest);
  457.             self.path:MoveCursorToEnd();
  458.             self.pathTime = CurTime() + 0.2;
  459.         end
  460.     else
  461.         --print("dest is not valid?");
  462.     end
  463. end
  464.  
  465. function ENT:InvalidateGoal()
  466.     self.pathTime = 0.01;
  467. end
  468.  
  469. function ENT:GetGoalPos()
  470.     if (self.goal != nil) then
  471.         if (isentity(self.goal) && IsValid(self.goal)) then
  472.             return self.goal:GetPos();
  473.         elseif (isvector(self.goal)) then
  474.             return self.goal;
  475.         end
  476.     end
  477. end
  478.  
  479. function ENT:DistanceToGoal()
  480.     local targetvec;
  481.     if (self.goal != nil) then
  482.         if (isentity(self.goal) && IsValid(self.goal)) then
  483.             targetvec = self:GetPos() - self.goal:GetPos();
  484.         elseif (isvector(self.goal)) then
  485.             targetvec = self:GetPos() - self.goal;
  486.         end
  487.         if (targetvec) then
  488.             return targetvec:Length();
  489.         end
  490.     end
  491.     return 0;
  492. end
  493.  
  494. function ENT:IsAtGoal()
  495.     if (self.goal == nil) then
  496.         return true;
  497.     end
  498.     local dist = self:DistanceToGoal()
  499.     if (dist < 20) then
  500.         return true;
  501.     end
  502.     return false;
  503. end
  504.  
  505. function ENT:UpdatePathGoal()
  506.     if (self.path == nil || !IsValid(self.path)) then
  507.         return;
  508.     end
  509.    
  510.     if (self:GetRangeSquaredTo(self.pathGoal.pos) < 1296) then -- 36 units
  511.         local nodes = self.path:GetAllSegments();
  512.         local node;
  513.         local maxNodes = #nodes;
  514.        
  515.         if (self.curNode > maxNodes) then --we're out of nodes
  516.             --Invalidate the path, we need to find a new one
  517.             --print("We're beyond the last node");
  518.             self:InvalidateGoal();
  519.             return;
  520.         end
  521.        
  522.         node = nodes[self.curNode];
  523.         if (node == nil) then
  524.             --print(self.curNode);
  525.             --print("what the hell");
  526.             return;
  527.         end
  528.         self.curNode = self.curNode + 1;
  529.        
  530.         local i = self.curNode;
  531.         local testnode;
  532.         local tr;
  533.         --failed reactive pathfinding thing. Couldn't handle paths on multiple elevations
  534.         --while (i <= maxNodes) do
  535.         --  testnode = nodes[i];
  536.         --  if (testnode.distanceFromStart - self.path:GetCursorPosition() > 3000) then
  537.         --      --Too far away, don't try this node anymore
  538.         --      break;
  539.         --  end
  540.         --  tr = util.TraceLine({start = self:EyePos(), endpos = testnode.pos, mask = MASK_SOLID_BRUSHONLY});
  541.         --  --can't use this node if trace fell short
  542.         --  if (tr.Fraction < 0.999) then
  543.         --      break;
  544.         --  end
  545.         --  node = testnode;
  546.         --  self.curNode = i;
  547.         --  i = i + 1;
  548.         --end
  549.         self.pathGoal = node;
  550.        
  551.         --efdata = EffectData();
  552.         --efdata:SetOrigin(self.pathGoal.pos);
  553.         --util.Effect("explosion", efdata);
  554.         --print("Updated curnode, now " .. self.curNode);
  555.     end
  556. end
  557.  
  558. function ENT:LocomotionUpdate(fInterval)
  559.     local dist = self:DistanceToGoal();
  560.     local lgoal;
  561.     --Are we already at our goal?
  562.     if (self:IsAtGoal()) then
  563.         --print("at destination");
  564.         return;
  565.     end
  566.    
  567.     if (IsValid(self.path) && self.path:IsValid()) then --is our current path ready for use
  568.         if (dist < 192) then
  569.             --print("attempting to approach");
  570.             if (IsValid(self.faceTarget)) then
  571.                 self.loco:FaceTowards(self.faceTarget:GetPos());
  572.             else
  573.                 self.loco:FaceTowards(self:GetGoalPos());
  574.             end
  575.             self.loco:Approach(self:GetGoalPos(), 1.0);
  576.         else
  577.             --print("attempting to pathfind");
  578.             --self.path:Update(self);
  579.            
  580.             --self.path:GetPositionOnPath(self.path:GetCursorPosition());
  581.             --print(self.path:GetCursorPosition());
  582.             --self.path:MoveCursorToEnd();
  583.             --lgoal = self.path:GetCurrentGoal();
  584.             --print("my goal is " .. lgoal.length .. " units along a path " .. self.path:GetLength() .. " long." );
  585.             --print("(" .. self:GetPos().x .. "," .. self:GetPos().y .. "," .. self:GetPos().z .. ") (" .. lgoal.pos.x .. "," .. lgoal.pos.y .. "," .. lgoal.pos.z .. ")");
  586.             --self.loco:Approach(self.path:GetCursorData().pos, 1.0);
  587.             --self.loco:Approach(lgoal.pos, 1.0);
  588.             --self.loco:Approach(self.path:GetPositionOnPath(lgoal.length), 1.0);
  589.             if (IsValid(self.faceTarget)) then
  590.                 self.loco:FaceTowards(self.faceTarget:GetPos());
  591.             else
  592.                 self.loco:FaceTowards(self.pathGoal.pos);
  593.             end
  594.             self.loco:Approach(self.pathGoal.pos, 1.0);
  595.             --update?
  596.             self.path:MoveCursorToClosestPosition(self:GetPos(), SEEK_ENTIRE_PATH);
  597.             self.path:Draw();
  598.         end
  599.     --else
  600.         --print("why is everything deciding to not be valid tonight");
  601.     end
  602. end
  603.  
  604. function ENT:PathToPoint(pos)
  605.     --print("Repathing");
  606.     if (pos == nil) then
  607.         return;
  608.     end
  609.     self.path = Path("Follow")
  610.  
  611.     self.path:SetMinLookAheadDistance(300);
  612.     self.path:SetGoalTolerance(20);
  613.     self:DoPathComputation(self.path, pos);
  614.    
  615.     if (self.path != nil) then
  616.         --print("we got a path");
  617.         self.pathGoal = self.path:FirstSegment();
  618.     end
  619.     self.curNode = 1;
  620. end
  621.  
  622. --------------------------------------------------------------------------------
  623. --New AI experiment
  624. --New New AI experiment
  625. --------------------------------------------------------------------------------
  626. function ENT:BehaveUpdate(fInterval)
  627.     if SERVER then
  628.         if (self.heh) then
  629.             self:AddGesture(ACT_HL2MP_GESTURE_RANGE_ATTACK_FIST);
  630.             self.heh = false;
  631.         end
  632.         if (self.heh2) then
  633.             self:CurBehaviorActivity();
  634.             self.heh2 = true;
  635.         end
  636.         self:FindTarget();
  637.         self:UpdateTargetVis();
  638.         self:CurBehaviorThink(fInterval);
  639.         self:UpdateGoal();
  640.         self:UpdatePathGoal();
  641.         self:LocomotionUpdate(fInterval);
  642.         if (CurTime() >= self.nextbstart) then
  643.             self:CurBehaviorTimeout();
  644.         end
  645.     end
  646. end
  647.  
  648. --Called to start a behavior
  649. function ENT:CurBehaviorStart()
  650.     if (self:GetBehavior() == BEHAVIOR_SPAWN) then
  651.         print("BEHAVIOR_SPAWN");
  652.         self.nextbstart = CurTime() + self:SetSequence("zombie_slump_rise_01");
  653.  
  654.         self:ResetSequenceInfo();
  655.         self:SetCycle(0);
  656.         self:SetPlaybackRate(1.0);
  657.         self.useBodyMove = false;
  658.         self.goal = self:GetPos();
  659.     elseif (self:GetBehavior() == BEHAVIOR_STAND) then
  660.         print("BEHAVIOR_STAND");
  661.         self:StartActivity(ACT_HL2MP_IDLE);
  662.         --self:StartActivity(ACT_HL2MP_GESTURE_RANGE_ATTACK_FIST);
  663.         self.nextbstart = CurTime() + 0.3;
  664.         self.useBodyMove = false;
  665.         self:InvalidateGoal();
  666.         self.goal = self:GetPos();
  667.     elseif (self:GetBehavior() == BEHAVIOR_PATROL) then
  668.         print("BEHAVIOR_PATROL");
  669.         self:StartActivity(ACT_HL2MP_WALK);
  670.         self.nextbstart = CurTime() + 25.0;
  671.         self.useBodyMove = true;
  672.        
  673.         --Find a point
  674.         self.loco:SetDesiredSpeed(100);
  675.         self:InvalidateGoal();
  676.         local pos = self:FindRSpot("random", { type = 'hiding', radius = 1000 })
  677.         if (pos != nil) then
  678.             self.goal = pos;
  679.         else
  680.             self.goal = self:GetPos();
  681.         end
  682.     elseif (self:GetBehavior() == BEHAVIOR_CHASE) then
  683.         print("BEHAVIOR_CHASE");
  684.         self:StartActivity(ACT_HL2MP_RUN_FIST);
  685.         self.nextbstart = CurTime() + 0.4;
  686.         self.useBodyMove = true;
  687.        
  688.         --self:InvalidateGoal();
  689.         self.loco:SetDesiredSpeed(200);
  690.         self.faceTarget = nil; --face direction of travel
  691.         if (self.target) then
  692.             self.goal = self:GetTargetGoal();
  693.         else
  694.             self.goal = self:GetPos();
  695.         end
  696.     elseif (self:GetBehavior() == BEHAVIOR_FINDHEALTH) then
  697.         print("BEHAVIOR_FINDHEALTH");
  698.         self:StartActivity(ACT_HL2MP_RUN_FIST);
  699.         self.nextbstart = CurTime() + 20.0;
  700.         self.useBodyMove = true;
  701.        
  702.         self.loco:SetDesiredSpeed(200);
  703.         --changing goal in the new goal function seems messy, but we have no other option right now...
  704.         --this code is not as good as it seems
  705.         --self:InvalidateGoal();
  706.        
  707.         if (IsValid(self.target)) then
  708.             self.faceTarget = self.target;
  709.         end
  710.     elseif (self:GetBehavior() == BEHAVIOR_LOSTVIS) then
  711.         print("BEHAVIOR_LOSTVIS");
  712.         self:StartActivity(ACT_HL2MP_RUN_FIST);
  713.         self.nextbstart = CurTime() + 0.4;
  714.         self.useBodyMove = true;
  715.        
  716.         --self:InvalidateGoal();
  717.         self.loco:SetDesiredSpeed(200);
  718.         self.faceTarget = nil; --face direction of travel
  719.         --Try to go to the point where we last saw our guy
  720.         self.goal = self.lastSeenPos;
  721.     elseif (self:GetBehavior() == BEHAVIOR_FINDAMBUSH) then
  722.         print("BEHAVIOR_FINDAMBUSH");
  723.         self:StartActivity(ACT_HL2MP_WALK);
  724.         self.nextbstart = CurTime() + 25.0;
  725.         self.useBodyMove = true;
  726.         self.loco:SetDesiredSpeed(100);
  727.         self.ambushMode = true;
  728.         --Goal has been found in advance
  729.     elseif (self:GetBehavior() == BEHAVIOR_AMBUSH) then
  730.         print("BEHAVIOR_AMBUSH");
  731.         self:StartActivity(ACT_HL2MP_IDLE);
  732.         --self:StartActivity(ACT_HL2MP_GESTURE_RANGE_ATTACK_FIST);
  733.         self.nextbstart = CurTime() + 0.3;
  734.         self:InvalidateGoal();
  735.         self.goal = self:GetPos();
  736.     end
  737. end
  738.  
  739. function ENT:NewBehavior(newb)
  740.     self:SetBehavior(newb);
  741.     self:CurBehaviorStart();
  742.     self:CurBehaviorActivity();
  743. end
  744.  
  745. --Called to update a behavior
  746. function ENT:CurBehaviorThink(fInterval)
  747.     if(self:GetBehavior() == BEHAVIOR_SPAWN || self:GetBehavior() == BEHAVIOR_STAND) then
  748.         --This is a bit of a hack, but it prevents problems
  749.         self.goal = self:GetPos();
  750.     elseif(self:GetBehavior() == BEHAVIOR_PATROL) then
  751.         if (self:IsAtGoal()) then
  752.             print("at goal?");
  753.             self.nextbstart = 0.01; --End the current behavior
  754.         elseif (self.target != nil) then
  755.             print("We found a target wandering");
  756.             self.nextbstart = 0.01;
  757.         end
  758.     elseif(self:GetBehavior() == BEHAVIOR_CHASE) then
  759.         if (IsValid(self.target) == false) then --has our target died?
  760.             print("Target died");
  761.             self:InvalidateTarget(); --pick a new target sooner
  762.             self.nextbstart = 0.01; --abort instantly
  763.         end
  764.     --This really isn't elegant, honestly. Bot shouldn't know if their target died or not.
  765.     elseif(self:GetBehavior() == BEHAVIOR_LOSTVIS) then
  766.         if (IsValid(self.target) == false) then --has our target died?
  767.             print("Target died");
  768.             self:InvalidateTarget(); --pick a new target sooner
  769.             self.nextbstart = 0.01; --abort instantly
  770.         end
  771.     elseif(self:GetBehavior() == BEHAVIOR_FINDHEALTH) then
  772.         if (self:IsAtGoal()) then
  773.             print("I got a healthkit!");
  774.             self:SetHealth(self:Health() + 25);
  775.             self.goal:Remove();
  776.             self.nextbstart = 0.01; --End the current behavior
  777.         end
  778.     elseif(self:GetBehavior() == BEHAVIOR_FINDAMBUSH) then
  779.         if (self:IsAtGoal()) then
  780.             print("at goal?");
  781.             self.nextbstart = 0.01; --End the current behavior
  782.         elseif (self.target != nil) then
  783.             print("We found a target wandering");
  784.             self.nextbstart = 0.01;
  785.         end
  786.     elseif(self:GetBehavior() == BEHAVIOR_AMBUSH) then
  787.         --Stand in the hiding spot, waiting for something to come. Look around randomly
  788.         --local angles = self:GetAngles();
  789.         --angles.yaw = angles.yaw + math.Rand(-2, 2);
  790.         --self:SetAngles(angles);
  791.         --This is a bit of a hack, but it prevents problems
  792.         self.goal = self:GetPos();
  793.     end
  794. end
  795.  
  796. --Called to switch from one behavior into another
  797. function ENT:CurBehaviorTimeout()
  798.     if (self:GetBehavior() == BEHAVIOR_SPAWN) then
  799.         self:NewBehavior(BEHAVIOR_STAND);
  800.     elseif (self:GetBehavior() == BEHAVIOR_STAND) then
  801.         if (self.target != nil) then
  802.             self:InvalidateGoal();
  803.             self:NewBehavior(BEHAVIOR_CHASE);
  804.         else
  805.             --Sometimes find a new spot to patrol
  806.             if (math.Rand(0, 1) > 0.9) then
  807.                 self:NewBehavior(BEHAVIOR_PATROL);
  808.             else
  809.                 self:NewBehavior(BEHAVIOR_STAND);
  810.             end
  811.         end
  812.     elseif (self:GetBehavior() == BEHAVIOR_PATROL) then
  813.         self:NewBehavior(BEHAVIOR_STAND);
  814.     elseif (self:GetBehavior() == BEHAVIOR_CHASE) then
  815.         if (IsValid(self.target) == false) then
  816.             self:NewBehavior(BEHAVIOR_STAND);
  817.         elseif (!self.canSeeTarget) then
  818.             --We cannot see our target anymore, we need to switch our behavior
  819.             self:NewBehavior(BEHAVIOR_LOSTVIS);
  820.         elseif (self:Health() < 25) then
  821.             local _ents = ents.FindInSphere( self:GetPos(), 1200 )
  822.             local kit = nil
  823.             for k, v in pairs( _ents ) do
  824.                 if (v:GetClass() == "item_healthkit") then
  825.                     kit = v;
  826.                 end
  827.             end
  828.             if (kit) then
  829.                 --try to find a medikit
  830.                 self:InvalidateGoal();
  831.                 self.goal = kit;
  832.                 self:NewBehavior(BEHAVIOR_FINDHEALTH);
  833.             else
  834.                 --Go back to chasing, we're doomed
  835.                 self:NewBehavior(BEHAVIOR_CHASE);
  836.             end
  837.         else
  838.             self:NewBehavior(BEHAVIOR_CHASE);
  839.         end
  840.     elseif (self:GetBehavior() == BEHAVIOR_FINDHEALTH) then
  841.         self:InvalidateGoal();
  842.         self:NewBehavior(BEHAVIOR_CHASE);
  843.     elseif (self:GetBehavior() == BEHAVIOR_LOSTVIS) then
  844.         if (self.canSeeTarget) then
  845.             self:NewBehavior(BEHAVIOR_CHASE);
  846.         elseif (self:IsAtGoal()) then --We haven't found our target yet, do something
  847.             --Either enter patrol or ambush mode
  848.             self:InvalidateTarget();
  849.             if (math.Rand(0, 1) > 0.5) then
  850.                 self:NewBehavior(BEHAVIOR_STAND);
  851.             else
  852.                 local spot = self:FindSpot( "random", { type = 'hiding', radius = 5000 } );
  853.                 if (spot) then
  854.                     print("Hiding!");
  855.                     self.goal = spot;
  856.                     self:NewBehavior(BEHAVIOR_FINDAMBUSH);
  857.                 else
  858.                     print("No spot, patrolling");
  859.                     self:NewBehavior(BEHAVIOR_STAND);
  860.                 end
  861.             end
  862.         else --Continue going
  863.             self:NewBehavior(BEHAVIOR_LOSTVIS);
  864.         end
  865.     elseif (self:GetBehavior() == BEHAVIOR_FINDAMBUSH) then
  866.         if (self.target) then
  867.             self:NewBehavior(BEHAVIOR_CHASE);
  868.         else
  869.             self:NewBehavior(BEHAVIOR_AMBUSH);
  870.         end
  871.     elseif (self:GetBehavior() == BEHAVIOR_AMBUSH) then
  872.         if (self.target != nil) then
  873.             self:InvalidateGoal();
  874.             self:NewBehavior(BEHAVIOR_CHASE);
  875.         end
  876.     end
  877. end
  878.  
  879. --Called to figure out what hte primary animation we should be doing
  880. function ENT:CurBehaviorActivity()
  881.     if (self:GetBehavior() == BEHAVIOR_PATROL) then
  882.         return ACT_HL2MP_WALK;
  883.     elseif (self:GetBehavior() == BEHAVIOR_CHASE || self:GetBehavior() == BEHAVIOR_FINDHEALTH) then
  884.         return ACT_HL2MP_RUN_FIST;
  885.     end
  886.     return ACT_HL2MP_IDLE;
  887. end
  888.  
  889. --TEMPORARY HACK
  890. --
  891. -- Name: NextBot:FindSpots
  892. -- Desc: Returns a table of hiding spots.
  893. -- Arg1: table|specs|This table should contain the search info.\n\n * 'type' - the type (either 'hiding')\n * 'pos' - the position to search.\n * 'radius' - the radius to search.\n * 'stepup' - the highest step to step up.\n * 'stepdown' - the highest we can step down without being hurt.
  894. -- Ret1: table|An unsorted table of tables containing\n * 'vector' - the position of the hiding spot\n * 'distance' - the distance to that position
  895. --
  896. function ENT:FindRSpots( tbl )
  897.  
  898.     local tbl = tbl or {}
  899.  
  900.     tbl.pos         = tbl.pos           or self:WorldSpaceCenter()
  901.     tbl.radius      = tbl.radius        or 1000
  902.     tbl.stepdown    = tbl.stepdown      or 20
  903.     tbl.stepup      = tbl.stepup        or 20
  904.     tbl.type        = tbl.type          or 'hiding'
  905.  
  906.     -- Use a path to find the length
  907.     local path = Path( "Follow" )
  908.  
  909.     -- Find a bunch of areas within this distance
  910.     local areas = navmesh.Find( tbl.pos, tbl.radius, tbl.stepdown, tbl.stepup )
  911.  
  912.     local found = {}
  913.  
  914.     -- In each area
  915.     for _, area in pairs( areas ) do
  916.  
  917.         -- get the spots
  918.         local spot
  919.  
  920.         spot = area:GetRandomPoint()
  921.  
  922.         path:Invalidate()
  923.  
  924.         path:Compute( self, spot, 1 ) -- TODO: This is bullshit - it's using 'self.pos' not tbl.pos
  925.  
  926.         table.insert( found, { vector = spot, distance = path:GetLength() } )
  927.     end
  928.  
  929.     return found
  930.  
  931. end
  932.  
  933. --
  934. -- Name: NextBot:FindSpot
  935. -- Desc: Like FindSpots but only returns a vector
  936. -- Arg1: string|type|Either "random", "near", "far"
  937. -- Arg2: table|options|A table containing a bunch of tweakable options. See the function definition for more details
  938. -- Ret1: vector|If it finds a spot it will return a vector. If not it will return nil.
  939. --
  940. function ENT:FindRSpot( type, options )
  941.  
  942.     local spots = self:FindRSpots( options )
  943.     if ( !spots || #spots == 0 ) then return end
  944.  
  945.     if ( type == "near" ) then
  946.  
  947.         table.SortByMember( spots, "distance", true )
  948.         return spots[1].vector
  949.  
  950.     end
  951.  
  952.     if ( type == "far" ) then
  953.  
  954.         table.SortByMember( spots, "distance", false )
  955.         return spots[1].vector
  956.  
  957.     end
  958.  
  959.     -- random
  960.     return spots[ math.random( 1, #spots ) ].vector
  961.  
  962. end
  963.  
  964. --
  965. -- List the NPC as spawnable
  966. --
  967. list.Set( "NPC", "npc_ibbot_new", {
  968.     Name = "Enhanced IB Bot",
  969.     Class = "npc_ibbot_new",
  970.     Category = "Nextbot"   
  971. } )
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement