Rusev

Untitled

Jun 7th, 2024
131
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.04 KB | None | 0 0
  1. penDrone : CCombatDronePuppetEntity
  2. -- penFoe : CPuppetEntity
  3.  
  4. local Math = import("Content/Shared/Scripts/Math.lua")
  5. local bDebug = false
  6.  
  7. if bDebug then
  8. local srZero = CreateScriptedRenderer(worldGlobals.worldInfo, Math.qvIdentity)
  9. end
  10.  
  11. local afShootChances = {0.25, 0.5, 0.75, 1}
  12. local aiNumberOfShots = {2, 2, 3, 5}
  13. local aiNumberOfShots = {3, 3, 3, 3}
  14.  
  15. local tblBehavior = { DestinationWaitMin = 0.25, DestinationWaitMax = 0.5, PreShootWaitMin = 0.3, PreShootWaitMax = 0.6, PostDismountDelay = 1.0}
  16.  
  17. local tblSoldierParams = {}
  18. tblSoldierParams.fShootingDelayMin = 3
  19. tblSoldierParams.fShootingDelayMax = 3
  20. tblSoldierParams.fShootingCount = 6
  21.  
  22. -- character behavior hints
  23. local ID_KAMIKAZE = "Carry kamikaze"
  24. local ID_FLY_IN_FRONT = "Fly in front of ride"
  25.  
  26. -- function called from SED so that script can provide list of behavior hints for user to choose using popup menu
  27. function globals.GetStringList()
  28. return ID_FLY_IN_FRONT, ID_KAMIKAZE
  29. end
  30.  
  31. -- stop if executing from GUI
  32. if worldGlobals==nil then return end
  33.  
  34. local worldInfo = worldGlobals.worldInfo --worldInfo : CWorldInfoEntity
  35.  
  36. local BEH_NORMAL = 0
  37. local BEH_FLY_IN_FRONT = 1
  38.  
  39. local kamikazeSpawnerName = "Kamikaze_Drone"
  40. --local spwKamikaze = worldInfo:GetEntityByName(kamikazeSpawnerName) -- spwKamikaze : CSpawnerEntity
  41. local spwKamikaze = worldInfo:GetAllEntitiesOfClassAndName("CSpawnerEntity", kamikazeSpawnerName)
  42.  
  43. --[[print(#spwKamikaze)
  44. for i=1,#spwKamikaze,1 do
  45. local vPlace = spwKamikaze[i]:GetPos()
  46. print("("..vPlace.x..","..vPlace.y..","..vPlace.z..")")
  47. end]]--
  48.  
  49. if (#spwKamikaze == 0) then
  50. conErrorF("Combat drone found unable to spawn kamikaze! Please resolve this by creating kamikaze spawner named \"" .. kamikazeSpawnerName .. "\" on your level.\n")
  51. spwKamikaze = nil
  52. else
  53. spwKamikaze = spwKamikaze[1]
  54. spwKamikaze:SetTotalCount(100000)
  55. end
  56.  
  57. --[[if spwKamikaze ~= nil and spwKamikaze:GetClassName() == "CSpawnerEntity" then
  58. local totalCount = spwKamikaze:GetTotalCount()
  59. if totalCount < 10000 then
  60. conWarningF("Drone's kamikaze spawner total count is set to " .. totalCount .. ". It is recommended to set it to something above 10000 in order prevent undesired errors.\n")
  61. end
  62. end]]--
  63.  
  64. local function CanBehave(penDrone)
  65. if penDrone == nil or IsDeleted(penDrone) then
  66. return false
  67. end
  68. while globals.worldInfo:IsCutSceneActive() do
  69. Wait(Delay(0.5))
  70. if IsDeleted(penDrone) then
  71. return false
  72. end
  73. end
  74. if not penDrone:IsAlive() then
  75. return false
  76. end
  77. return true
  78. end
  79.  
  80. local function CanRiderBehave(penRider, penDrone)
  81. if penDrone == nil or IsDeleted(penDrone) then
  82. return false
  83. end
  84. if penRider == nil or IsDeleted(penRider) then
  85. return false
  86. end
  87. while globals.worldInfo:IsCutSceneActive() do
  88. Wait(Delay(0.5))
  89. if IsDeleted(penDrone) or IsDeleted(penRider) then
  90. return false
  91. end
  92. end
  93. if not penDrone:IsAlive() or not penRider:IsAlive() then
  94. return false
  95. end
  96. return penDrone:IsRiddenBy(penRider)
  97. end
  98.  
  99. local function ShouldShoot(penDrone, fShootAngle)
  100. local penFoe = penDrone:GetFoe()
  101. if penFoe==nil then
  102. return false
  103. end
  104. local vFoeToMe = mthSafeNormalizeV3f(penDrone:GetPlacement():GetVect()-penFoe:GetPlacement():GetVect())
  105. vFoeToMe.y = 0
  106. vFoeToMe = mthSafeNormalizeV3f(vFoeToMe)
  107. local vFoeLookDirXZ = penFoe:GetLookDir(true)
  108. local fDot = mthDotV3f(vFoeLookDirXZ, vFoeToMe)
  109. local fAngle = mthRadToDeg(mthACosF(fDot))
  110. -- if we see foe
  111. if fAngle<fShootAngle then
  112. -- we can shoot
  113. return true
  114. end
  115.  
  116. -- if we have already skipped several attacks
  117. penDrone.ctSkippedAttacks = penDrone.ctSkippedAttacks+1
  118. if penDrone.ctSkippedAttacks>4 then
  119. -- attack
  120. penDrone.ctSkippedAttacks = 0
  121. return true
  122. end
  123. return false
  124. end
  125.  
  126. function worldGlobals.CombatDroneBehavior(penDrone)
  127. penDrone.BehaviorHint = penDrone:GetBehaviorHint()
  128.  
  129. -- handler for kamikaze spawning functionality
  130. RunAsync(function()
  131. RunHandled(function() while not IsDeleted(penDrone) do Wait(Times(20, CustomEvent("OnStep"))) end end,
  132. OnEvery(CustomEvent("DroneSpawnKamikaze")), function(DroneSpawnKamikaze)
  133. if penDrone.BehaviorHint ~= ID_KAMIKAZE then return end
  134.  
  135. local Denemy = DroneSpawnKamikaze:GetEventThrower()
  136. if Denemy ~= penDrone then return end
  137.  
  138. if spwKamikaze == nil then
  139. conErrorF("Combat drone found unable to spawn kamikaze! Please resolve this by creating kamikaze spawner named \"" .. kamikazeSpawnerName .. "\" on your level.")
  140. return
  141. elseif spwKamikaze:GetClassName() ~= "CSpawnerEntity" then
  142. conErrorF("Found an entity named \"" .. kamikazeSpawnerName .. "\" which is not CSpawnerEntity. Perhaps you named a puppet, but not a spawner? (expand Spawner in puppet properties, there is a 'Name' field too)\n")
  143. return
  144. elseif spwKamikaze:GetRemainToSpawnCount() <= 0 then
  145. conErrorF("Combat drone's kamikaze spawner has run out of total spawn count! Combat drones cannot spawn kamikaze anymore.\nPlease, increase total count of combat drone's kamikaze spawner.\n")
  146. return
  147. end
  148.  
  149. local Kamikazepuppet = spwKamikaze:SpawnOne() -- Kamikazepuppet : CLeggedCharacterEntity
  150. Denemy:MountPuppetToDrone(Kamikazepuppet, "Kamikaze")
  151.  
  152. while not IsDeleted(Denemy) do
  153.  
  154. local foe = Denemy:GetFoe()
  155. if foe ~= nil then
  156. if worldInfo:GetDistance(foe, Denemy) < 35 then
  157. --Denemy:PlayAnim("ThrowKamikaze")
  158. Denemy:DismountRider()
  159. if not IsDeleted(Kamikazepuppet) then
  160. Kamikazepuppet:SetPlacement(Denemy:GetAttachmentAbsolutePlacement("Kamikaze"))
  161. end
  162. break
  163. end
  164. end
  165.  
  166. Wait(CustomEvent("OnStep"))
  167. end
  168.  
  169. if not IsDeleted(Denemy) and Denemy:IsAlive() and not IsDeleted(Kamikazepuppet) and Kamikazepuppet:IsAlive() then
  170. local q4plc2 = Denemy:GetAttachmentAbsolutePlacement("Kamikaze")
  171. local foe = Denemy:GetFoe()
  172. if not IsDeleted(foe) then
  173. local foepls = foe:GetPlacement()
  174. local v3fdir = mthNormalize(mthVector3f(foepls.vx - q4plc2.vx, foepls.vy - q4plc2.vy, foepls.vz - q4plc2.vz))
  175. v3fdir.x = v3fdir.x * 25
  176. v3fdir.z = v3fdir.z * 25
  177. Kamikazepuppet:SetLinearVelocity(v3fdir)
  178. Kamikazepuppet:ForceFoe(foe)
  179. end
  180. end
  181. end
  182. )
  183. end) -- 1st async end
  184.  
  185. Wait(Delay(0.1))
  186. if penDrone:IsMovedUsingSpecialMover() then
  187. Wait(CustomEvent(penDrone, "StoppedUsingSpecialMover"))
  188. end
  189.  
  190. local strBehaviorHint = penDrone:GetBehaviorHint()
  191. if strBehaviorHint == ID_FLY_IN_FRONT then
  192. penDrone.iBehavior = BEH_FLY_IN_FRONT
  193. end
  194.  
  195. -- disable mover
  196. penDrone:DisableAutoMove()
  197. -- counter of flights without shooting
  198. local iShootCounter = 1
  199. penDrone.ctSkippedAttacks = 0
  200. local strDifficulty = worldGlobals.worldInfo:GetGameDifficulty()
  201. local fDifficultyBias = 0
  202.  
  203. strDifficulty="Normal"
  204.  
  205. if strDifficulty=="Tourist" then
  206. fDifficultyBias = -1
  207. elseif strDifficulty=="Easy" then
  208. fDifficultyBias = -0.5
  209. elseif strDifficulty=="Normal" then
  210. fDifficultyBias = 0
  211. elseif strDifficulty=="Hard" then
  212. fDifficultyBias = 0.5
  213. elseif strDifficulty=="Serious" then
  214. fDifficultyBias = 1
  215. elseif strDifficulty=="Mental" then
  216. fDifficultyBias = 1.5
  217. end
  218.  
  219. -- control rider's AI
  220. RunAsync(function()
  221. -- while the drone is alive
  222. while CanBehave(penDrone) do
  223. -- fetch the rider
  224. local penRider = penDrone:GetRiderPuppet()
  225. while penRider == nil and CanBehave(penDrone) do
  226. penRider = penDrone:GetRiderPuppet()
  227. Wait(Delay(1))
  228. end
  229.  
  230. -- if a rider is found, get it's attack
  231. if penRider ~= nil then
  232. local idAttack = penDrone:GetRiderAttack()
  233. -- while rider can behave and is riding the drone
  234. while CanRiderBehave(penRider, penDrone) do
  235. -- freeze behaviour if requested
  236. if penDrone:ShouldFreezeAutoActing() then
  237. while CanRiderBehave(penRider, penDrone) and penDrone:ShouldFreezeAutoActing() do
  238. Wait(Delay(0.5))
  239. end
  240. end
  241.  
  242. -- break if can not behave any more
  243. if not CanRiderBehave(penRider, penDrone) then
  244. break
  245. end
  246.  
  247. -- wait between shootings
  248. local fDelay = mthLerpF(tblSoldierParams.fShootingDelayMin, tblSoldierParams.fShootingDelayMax, mthRndF())
  249. Wait(Delay(fDelay))
  250.  
  251. -- break if can not behave any more
  252. if not CanRiderBehave(penRider, penDrone) then
  253. break
  254. end
  255.  
  256. -- shoot at foe
  257. if penRider:GetFoe() and penRider:CanSeeEntity(penRider:GetFoe()) then
  258. local fShots = tblSoldierParams.fShootingCount
  259. Wait(penRider:AttackShoot(idAttack, fShots, false))
  260. end
  261. end
  262. end
  263. end
  264. end)
  265.  
  266. while CanBehave(penDrone) do
  267.  
  268. -- while automatic acting should be frozen or if there is a flight request
  269. while penDrone:ShouldFreezeAutoActing() or penDrone:IsFlightRequested() do
  270. if not CanBehave(penDrone) then
  271. break
  272. end
  273.  
  274. -- if there is a flight requested
  275. if penDrone:IsFlightRequested() then
  276. local qvRequestedPlacement = penDrone:GetRequestedPlacement()
  277. Wait(penDrone:FlyToGivenDestination(qvRequestedPlacement, true, true, true))
  278. if not CanBehave(penDrone) then
  279. break
  280. end
  281.  
  282. -- if dismount is requested
  283. if penDrone:IsDismountRequested() then
  284. penDrone:DismountRider()
  285. local fDismountDelay = tblBehavior.PostDismountDelay
  286. Wait(Delay(fDismountDelay))
  287. end
  288. end
  289.  
  290. -- if freezing, skip some time
  291. if penDrone:ShouldFreezeAutoActing() then
  292. Wait(Delay(0.5))
  293. end
  294. end
  295.  
  296. -- select delay due to difficulty factor
  297. local fDelay = 0.25
  298. fDelay = mthClampDnF(fDelay-fDifficultyBias,0.1)
  299.  
  300. Wait(Delay(fDelay))
  301. if not CanBehave(penDrone) then
  302. break
  303. end
  304.  
  305. local fDestinationWait = mthLerpF( tblBehavior["DestinationWaitMin"], tblBehavior["DestinationWaitMax"], mthRndF())
  306. local fPreShootWait = mthLerpF( tblBehavior["PreShootWaitMin"], tblBehavior["PreShootWaitMax"], mthRndF())
  307. local fShootChance = afShootChances[iShootCounter]
  308. local fShootAngle = 30
  309. local ctDrones = worldGlobals.worldInfo:GetEnemyCount("Drone_Combat", penFoe)
  310. if ctDrones<3 then
  311. fDestinationWait = fDestinationWait/4
  312. fPreShootWait = fPreShootWait/4
  313. fShootChance = fShootChance+0.5
  314. fShootAngle = fShootAngle+30
  315. elseif ctDrones<6 then
  316. fDestinationWait = fDestinationWait/2
  317. fPreShootWait = fPreShootWait/2
  318. fShootChance = fShootChance+0.25
  319. fShootAngle = fShootAngle+10
  320. end
  321.  
  322. local bShooting = false
  323. local penFoe = penDrone:GetFoe()
  324. if penFoe then
  325. bShooting = mthRndF() <= fShootChance
  326. end
  327.  
  328. local bAutoFly = true
  329. if penDrone.iBehavior == BEH_FLY_IN_FRONT then
  330. local penFoe = penDrone:GetFoe()
  331. if penFoe~=nil and penFoe:GetRide()~=nil then
  332. local penRide = penFoe:GetRide()
  333. local vXZVelocity = penRide:GetLinearVelocity()
  334. local qvRide = penRide:GetPlacement()
  335. local fH = mthLerpF(mthDegToRad(-70), mthDegToRad(70), mthRndF())
  336. local fP = mthLerpF(mthDegToRad(3), mthDegToRad(20), mthRndF())
  337. local fDistance = mthLerpF(20, 60, mthRndF())
  338. local qDirRel = mthEulerToQuaternion(mthVector3f(fH,fP,0))
  339. local qDirAbs = mthMulQ4f(qvRide:GetQuat(), qDirRel)
  340. local vDirAbs = mthQuaternionToDirection(qDirAbs)
  341. local vPos = qvRide:GetVect()+vDirAbs*fDistance+vXZVelocity*5
  342. local qvRequestedPlacement = penDrone:GetPlacement()
  343. qvRequestedPlacement:SetVect(vPos)
  344. bAutoFly = false
  345. if bDebug then
  346. srZero:AddPoint(vPos, 1)
  347. end
  348. Wait(penDrone:FlyToGivenDestination(qvRequestedPlacement, false, true, true))
  349. end
  350. end
  351.  
  352. if bAutoFly then
  353. Wait(penDrone:FlyToNewDestination(bShooting))
  354. end
  355. if not CanBehave(penDrone) then
  356. break
  357. end
  358.  
  359. if penDrone:GetFoe() and bShooting then
  360. if fDestinationWait>0 then
  361. Wait(Delay(fPreShootWait))
  362. end
  363. if CanBehave(penDrone) and ShouldShoot(penDrone, fShootAngle) then
  364. if penDrone:CanSeeEntity(penDrone:GetFoe()) then
  365. penDrone.ctSkippedAttacks = 0
  366. Wait(penDrone:AttackShoot("Shoot_Laser", aiNumberOfShots[iShootCounter], false))
  367. end
  368. end
  369. iShootCounter = 0
  370. else
  371. if fDestinationWait>0 then
  372. Wait(Delay(fDestinationWait))
  373. end
  374. end
  375.  
  376. if iShootCounter < 4 then
  377. iShootCounter = iShootCounter + 1
  378. end
  379. end
  380. end
  381.  
Advertisement
Add Comment
Please, Sign In to add comment