Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- **** BEGIN insert this function before "local function manage_drive_assistant(index)"
- -- adjusts the orientation of the unit being controlled to follow paved tiles
- local function manage_drive_assistant_for_unit(unit, player)
- local car = unit.vehicle
- if global.unit_data == nil then
- global.unit_data = {}
- end
- if global.unit_data[unit.unit_id] == nil then
- global.unit_data[unit.unit_id] = {}
- end
- local car_data = global.unit_data[unit.unit_id]
- if car ~= nil and math.abs(unit.speed) > global.min_speed then
- local dir = car.orientation
- local newdir = 0
- local dirr = dir + lookangle
- local dirl = dir - lookangle
- -- scores for straight, right and left (@sillyfly)
- local ss,sr,sl = 0,0,0
- local vs = {math.sin(2*math.pi*dir), -math.cos(2*math.pi*dir)}
- local vr = {math.sin(2*math.pi*dirr), -math.cos(2*math.pi*dirr)}
- local vl = {math.sin(2*math.pi*dirl), -math.cos(2*math.pi*dirl)}
- local px = car.position['x'] or car.position[1]
- local py = car.position['y'] or car.position[2]
- -- notification("X " .. px .. " Y " .. py)
- local sign = (unit.speed >= 0 and 1) or -1
- local sts = {px, py}
- local str = {px + sign*vs[2]*eccent, py - sign*vs[1]*eccent}
- local stl = {px -sign*vs[2]*eccent, py + sign*vs[1]*eccent}
- -- linearly increases start and length of the scanned area if the car is very fast
- local lookahead_start_hs = 0
- local lookahead_length_hs = 0
- if car.speed > global.highspeed then
- local speed_factor = car.speed / global.highspeed
- lookahead_start_hs = math.floor (hs_start_extension * speed_factor + 0.5)
- lookahead_length_hs = math.floor (hs_length_extension * speed_factor + 0.5)
- end
- -- sign detection
- if game.surfaces[car.surface.index].count_entities_filtered{area = {{px-1, py-1},{px+1, py+1}}, type="constant-combinator"} > 0 then
- local sign_scanner = game.surfaces[car.surface.index].find_entities_filtered{area = {{px-1, py-1},{px+1, py+1}}, type="constant-combinator"}
- for i = 1, #sign_scanner do
- -- speed limit sign
- if sign_scanner[i].name == "pda-road-sign-speed-limit" then
- local sign = sign_scanner[i].get_or_create_control_behavior().get_signal(1)
- local sign_value = 0
- if sign.signal ~= nil then sign_value = sign.count end
- -- read signal value only if a signal is set
- if sign_value ~= 0 then
- car_data.imposed_speed_limit = kmph_to_mpt(sign_value)
- if car.speed > car_data.imposed_speed_limit then
- -- activate brake to deccelerate the vehicle
- car_data.cruise_control_brake_active = true
- end
- end
- return
- -- unlimit sign
- elseif sign_scanner[i].name == "pda-road-sign-speed-unlimit" then
- car_data.imposed_speed_limit_car = nil
- return
- end
- end
- end
- --local last_scan = global.last_scan[player.index]
- --local new_scan = {{},{}}
- -- calculate scores within the scanning area in front of the vehicle (@sillyfly)
- -- commented out areas: Intended to cache scanned tiles to avoid multiple scans. Downside: This is apparently 5%-10% slower than accessing the raw tile data on each tick.
- for i=lookahead_start + lookahead_start_hs,lookahead_start + lookahead_length + lookahead_length_hs do
- local d = i*sign
- local rstx = str[1] + vs[1]*d
- local rsty = str[2] + vs[2]*d
- local lstx = stl[1] + vs[1]*d
- local lsty = stl[2] + vs[2]*d
- local rtx = px + vr[1]*d
- local rty = py + vr[2]*d
- local ltx = px + vl[1]*d
- local lty = py + vl[2]*d
- local rst = --[[(last_scan ~= nil and last_scan[rstx] ~= nil and last_scan[rstx][rsty]) or]] scores[car.surface.get_tile(rstx, rsty).name]
- local lst = --[[(last_scan ~= nil and last_scan[lstx] ~= nil and last_scan[lstx][lsty]) or]] scores[car.surface.get_tile(lstx, lsty).name]
- local rt = --[[(last_scan ~= nil and last_scan[rtx] ~= nil and last_scan[rtx][rty]) or]] scores[car.surface.get_tile(rtx, rty).name]
- local lt = --[[(last_scan ~= nil and last_scan[ltx] ~= nil and last_scan[ltx][lty]) or]] scores[car.surface.get_tile(ltx, lty).name]
- ss = ss + (((rst or 0) + (lst or 0))/2.0)
- sr = sr + (rt or 0)
- sl = sl + (lt or 0)
- --[[
- new_scan[rstx] = (new_scan ~= nil and new_scan[rstx]) or {}
- new_scan[rstx][rsty] = rst
- new_scan[lstx] = (new_scan ~= nil and new_scan[lstx]) or {}
- new_scan[lstx][lsty] = lst
- new_scan[rtx] = (new_scan ~= nil and new_scan[rtx]) or {}
- new_scan[rtx][rty] = rt
- new_scan[ltx] = (new_scan ~= nil and new_scan[ltx]) or {}
- new_scan[ltx][lty] = lt
- ]]
- end
- --global.last_scan[player.index] = new_scan
- if debug and player then
- player.print("x:" .. px .. "->" .. px+vs[1]*(lookahead_start + lookahead_length) .. ", y:" .. py .. "->" .. py+vs[2]*(lookahead_start + lookahead_length))
- player.print("S: " .. ss .. " R: " .. sr .. " L: " .. sl)
- end
- -- check if the score indicates that the vehicle leaved paved area
- local ls = car_data.last_score or 0
- local ts = ss+sr+sl
- if ts < ls and ts == 0 and not car_data.emergency_brake_active then
- -- warn the player and activate emergency brake
- if player and player.mod_settings["PDA-setting-sound-alert"].value then
- player.surface.create_entity({name = "pda-warning-1", position = player.position})
- elseif player and player.mod_settings["PDA-setting-verbose"].value then
- player.print({"DA-road-departure-warning"})
- end
- if player then
- player.riding_state = {acceleration = defines.riding.acceleration.braking, direction = player.riding_state.direction}
- end
- car_data.emergency_brake_active = true
- end
- car_data.last_score_car = ts
- -- set new direction depending on the scores (@sillyfly)
- if sr > ss and sr > sl then
- newdir = dir + (changeangle*sr*2)/(sr+ss)
- elseif sl > ss and sl > sr then
- newdir = dir - (changeangle*sl*2)/(sl+ss)
- else
- newdir = dir
- end
- -- Snap car to nearest 1/64 to avoid oscillation (@GotLag)
- car.orientation = math.floor(newdir * 64 + 0.5) / 64
- -- no score reset in curves -> allow the player to guide his vehicle off road manually
- elseif player and player.riding_state.direction ~= defines.riding.direction.straight then
- car_data.last_score = 0
- end
- end
- -- **** END of function to insert
- -- **** BEGIN insert this section at the end of the "function pda.on_tick(event)" function right before "global.playertick = ptick"
- -- if aai mod is active, manage drive assistant for all units
- -- TODO only manage drive assistant if a certain signal is active on the car to avoid performance issues and add flexibility
- if remote.interfaces["aai-programmable-vehicles"]["get_units"] then
- local units = remote.call("aai-programmable-vehicles", "get_units", entity)
- for key1, unit in pairs(units) do
- if unit and unit.vehicle ~= nil and unit.vehicle.valid and not unit.vehicle.passenger then
- manage_drive_assistant_for_unit(unit)
- end
- end
- end
- -- **** END of section to insert
Advertisement
Add Comment
Please, Sign In to add comment