Archives
Trending
Support
Login
clear text
XML
Django
JavaScript
MATLAB
C
C++
C#
Python
SQL
Shell
Bash
Markdown
YAML
JSON
HTML
CSS
PHP
Java
Ruby
Go
Rust
Swift
Kotlin
Arduino
TypeScript
Perl
Autohotkey
Lua
SQF
R
Scala
Haskell
Groovy
Dart
Clojure
VB.NET
Objective-C
PowerShell
Bash
CoffeeScript
Verilog
-- This Source Code Form is subject to the terms of the bCDDL, v. 1.1. -- If a copy of the bCDDL was not distributed with this -- file, You can obtain one at http://beamng.com/bCDDL-1.1.txt local min = math.min local max = math.max local ceil = math.ceil local random = math.random local C = {} function C:init() self.personalityModifiers = {} self.actions = { fleePostCrash = function (args) if self.veh.isAi then self.veh:setAiMode('flee') local obj = getObjectByID(self.veh.id) obj:queueLuaCommand('ai.driveInLane("off")') obj:queueLuaCommand('ai.setAggressionMode("off")') self:setAggression(args.aggression or max(0.5, random())) end self.state = 'flee' self.flags.askInsurance = nil end, followPostCrash = function (args) if self.veh.isAi then self.veh:setAiMode(args.isChase and 'chase' or 'follow') local obj = getObjectByID(self.veh.id) obj:queueLuaCommand('ai.driveInLane("off")') obj:queueLuaCommand('ai.setAggressionMode("off")') self:setAggression(args.aggression or max(0.5, random())) end self.state = 'follow' self.flags.askInsurance = nil end, askInsurance = function (args) if self.veh.isAi then self.veh:setAiMode('stop') end self.flags.askInsurance = nil end, disabled = function (args) if self.veh.isAi then self.veh:setAiMode('stop') end self.state = 'disabled' end } for k, v in pairs(self.baseActions) do self.actions[k] = v end self.baseActions = nil end function C:onRefresh() self.targetId = nil self.actionTimer = 0 local personality = self.driver.personality self.driver.eventType = nil self.driver.damageAction = 'none' self.driver.damageThreshold = 1000 self.driver.collisionThreshold = math.huge if self.veh.isAi then -- only calculates values if vehicle is AI self.driver.damageAction = 'stop' if personality.bravery >= 0.55 then self.driver.damageAction = 'followPostCrash' elseif personality.bravery <= 0.45 then self.driver.damageAction = 'fleePostCrash' end local squareRandom = square(random()) self.driver.damageThreshold = max(self.veh.damageLimits[1], squareRandom * 1000) -- minimum damage that triggers damage action self.driver.collisionThreshold = ceil(squareRandom * 6) -- minimum number of collisions that triggers damage action end self.driver.selfHitCount = 0 self.driver.otherHitCount = 0 self.driver.enableAskInsurance = true end function C:onCrashDamage(data) -- triggers if self is currently not in a collision or witness to one if self.driver.eventType ~= 'selfCollision' and self.driver.eventType ~= 'otherCollision' then self.driver.eventType = 'selfCrash' end end function C:onOtherCrashDamage(otherId, data) -- triggers if self is currently not in a collision or witness to one if self.driver.eventType ~= 'selfCollision' and self.driver.eventType ~= 'otherCollision' then self.driver.eventType = 'otherCrash' self:setTarget(otherId) end end function C:onCollision(otherId, data) if self.veh.speed >= self.veh.tracking.speedLimit * 1.2 then -- speeding always means collision fault for self self.veh.collisions[otherId].fault = true end if self.driver.eventType ~= 'selfCollision' then -- overrides previous events self.driver.eventType = 'selfCollision' self:setTarget(otherId) end if self.veh.isAi and not self.flags.askInsurance and self.driver.personality.bravery >= 0.52 and random() >= 0.5 / clamp(data.count, 1, 3) then self.flags.honkHornDelay = 1 end self.driver.selfHitCount = data.count end function C:onOtherCollision(id1, id2, data) if self.driver.eventType ~= 'selfCollision' then local targetVeh, secondVeh = gameplay_traffic.getTrafficData()[id1], gameplay_traffic.getTrafficData()[id2] if not targetVeh or not secondVeh then return end local targetId = targetVeh.speed < secondVeh.speed and id1 or id2 -- target the slower vehicle in collision if targetId == id2 then targetVeh = gameplay_traffic.getTrafficData()[targetId] end -- checks if target is visible, within distance, and in front of self if self:checkTargetVisible(targetId) and self.veh:getInteractiveDistance(targetVeh.pos, true) <= 3600 and self.veh.dirVec:dot(targetVeh.pos - self.veh.pos) > 0 then if self.driver.eventType ~= 'otherCollision' then self.driver.eventType = 'otherCollision' self:setTarget(targetId) end if self.veh.isAi and self.driver.personality.bravery >= 0.56 and random() >= 0.5 then self.flags.honkHornDelay = 1 end self.driver.otherHitCount = data.count end end end function C:onTrafficTick(tickTime) if self.state == 'disabled' then return end if self.veh.isAi and self.state ~= 'disabled' and self.veh.state == 'active' and self.veh.damage > self.veh.damageLimits[3] then self:setAction('disabled') end local targetVeh = self.targetId and gameplay_traffic.getTrafficData()[self.targetId] self.targetVisible = self:checkTargetVisible() self.targetNear = (targetVeh and self.veh:getInteractiveDistance(targetVeh.pos, true) <= 3600) and true or false if targetVeh and self.veh.isAi then local driver = self.driver if self.targetVisible and self.targetNear then local actionType -- target vehicle collided with self if driver.eventType == 'selfCollision' and self.veh.damage >= driver.damageThreshold then if driver.selfHitCount >= driver.collisionThreshold then actionType = 'crashThreshold' driver.collisionThreshold = driver.collisionThreshold + 2 else actionType = 'crash' end -- target vehicle collided with other vehicle elseif driver.eventType == 'otherCollision' and targetVeh.damage >= driver.damageThreshold then if driver.otherHitCount >= driver.collisionThreshold + 1 then -- higher threshold than self collision actionType = 'crashThreshold' driver.collisionThreshold = driver.collisionThreshold + 2 else actionType = 'crash' end -- target vehicle crashed by itself elseif driver.eventType == 'otherCrash' then if self.state == 'none' and driver.personality.bravery + driver.personality.patience >= 0.8 and self.veh.driveVec:dot(targetVeh.pos - self.veh.pos) > 0 then actionType = 'crash' end end if actionType == 'crashThreshold' then -- follow, flee, etc. local minTime = 5 if driver.damageAction == 'followPostCrash' and self.state ~= 'follow' then local chaseTarget = false if targetVeh.tracking.collisions >= 2 and driver.personality.bravery >= 0.6 then -- mode change if target driver is reckless chaseTarget = true minTime = 10 end self:setAction('followPostCrash', {reason = driver.eventType, targetId = self.targetId, isChase = chaseTarget}) self.actionTimer = max(minTime, (driver.personality.bravery - 0.5) * 60) -- duration for following target elseif driver.damageAction == 'fleePostCrash' and self.state ~= 'flee' then self:setAction('fleePostCrash', {reason = driver.eventType, targetId = self.targetId}) self.actionTimer = max(minTime, (0.5 - driver.personality.bravery) * 60) -- duration for fleeing from target else if self.state == 'none' then self:setAction('pullOver', {dist = self.veh:getBrakingDistance(self.veh.speed, driver.aggression * 1.5), reason = driver.eventType, useWarnSignal = true}) self.actionTimer = max(minTime, driver.personality.patience * 30) end end elseif actionType == 'crash' then -- just pull over and stop if self.state == 'none' then self:setAction('pullOver', {dist = self.veh:getBrakingDistance(self.veh.speed, driver.aggression * 1.5), reason = driver.eventType, useWarnSignal = true}) self.actionTimer = max(3, driver.personality.patience * 20) if driver.eventType == 'selfCollision' then self.flags.askInsurance = 1 end end end else -- target not visible or out of range if self.state ~= 'none' and self.veh.pos:squaredDistance(targetVeh.pos) >= 14400 then -- check if state needs to be reset self:resetAction() end end end if self.enableTrafficSignalsChange and self.veh.speed >= 6 and next(map.objects[self.veh.id].states) then -- lightbar triggers all traffic lights to change to the red state -- this exists here until we have a way to properly recognize emergency vehicles (lightbar exists) if map.objects[self.veh.id].states.lightbar then self:freezeTrafficSignals(true) else if self.flags.freezeSignals then self:freezeTrafficSignals(false) end end else if self.flags.freezeSignals then self:freezeTrafficSignals(false) end end end function C:onUpdate(dt, dtSim) if self.state == 'disabled' then return end local targetVeh = self.targetId and gameplay_traffic.getTrafficData()[self.targetId] if targetVeh then if self.actionTimer > 0 then self.actionTimer = self.actionTimer - dtSim if self.flags.askInsurance then if self.actionTimer <= 0 then if self.targetVisible and self.veh.speed <= 1 and targetVeh.speed <= 1 and self.veh.pos:squaredDistance(targetVeh.pos) <= 400 then self:setAction('askInsurance') -- exchange insurance information if gameplay_traffic.showMessages and self.targetId == be:getPlayerVehicleID(0) then if career_career and career_career.isActive() then -- career insurance logic might go here else ui_message('ui.traffic.interactions.insuranceExchanged', 5, 'traffic', 'traffic') end end self.targetId = nil else self.actionTimer = 5 -- bounce time end end elseif self.actionName == 'followPostCrash' or self.actionName == 'fleePostCrash' then if self.veh.pos:squaredDistance(targetVeh.pos) > 1600 or self.actionTimer <= 0 then if self.veh.collisions[self.targetId] then -- switch to askInsurance mode self:setAction('pullOver', {dist = self.veh:getBrakingDistance(self.veh.speed, self.driver.aggression * 1.5), reason = 'selfCollision', useWarnSignal = true}) self.flags.askInsurance = 1 self.actionTimer = 5 else self:resetAction() end end elseif self.actionName == 'pullOver' then if self.actionTimer <= 0 then self:resetAction() end end end end if self.flags.honkHornDelay and random() >= 0.9 then self.veh:honkHorn(max(0.25, square(random()) * 1.5)) self.flags.honkHornDelay = nil end end return function(...) return require('/lua/ge/extensions/gameplay/traffic/baseRole')(C, ...) end
Mark as private (unlisted)
for 30 minutes
for 6 hours
for 1 day
for 1 week
for 1 month
for 1 year
everlasting (like CCCP)