Guest User

FtD Missile Guidance

a guest
Aug 15th, 2025
75
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 23.37 KB | None | 0 0
  1. -- Enhanced missile guidance script
  2. -- - Memory management for destroyed missiles
  3. -- - Energy-efficient updates with variable tick rates
  4. -- - Climb-to-altitude behavior before engaging targets
  5. -- - Performance optimizations for large missile salvos
  6. -- - Exact proportional allocation (largest-remainder)
  7. -- - Per-missile-type guidance based on initial speed (small/medium/large)
  8. -- - Predictive lead applied before dive adjustment
  9. -- - Adaptive smoothing per missile type, with reduced lag when close
  10. -- - Proximity detonation when missile starts moving away from target within 5 meters
  11. -- - Fan-out behavior at cruising altitude to improve effectiveness against countermeasures
  12.  
  13. -- Persistent tables with cleanup tracking
  14. smoothed_aim_points = smoothed_aim_points or {}
  15. last_target_velocities = last_target_velocities or {}
  16. missile_target_index = missile_target_index or {}
  17. missile_initial_speeds = missile_initial_speeds or {}
  18. missile_last_update = missile_last_update or {}
  19. missile_altitude_phase = missile_altitude_phase or {} -- Tracks if missile is in climb phase
  20. missile_guidance_active = missile_guidance_active or {} -- Tracks if missile is actively guiding
  21. missile_last_distance = missile_last_distance or {} -- Tracks last known distance to target
  22. missile_proximity_armed = missile_proximity_armed or {} -- Tracks if proximity detonation is armed
  23. missile_fan_offset = missile_fan_offset or {} -- Tracks fan-out offset for each missile
  24.  
  25. -- Missile energy tracking
  26. local missile_max_speeds = {}  -- Tracks max speed achieved by each missile
  27. local missile_energy = {}      -- Normalized energy level (0-1) for each missile
  28. local energy_update_interval = 1.0 -- Check energy every second
  29. local last_energy_update = 0
  30.  
  31. -- Profiles per missile type
  32. smoothing_profiles = {
  33.     small  = {alpha_min = 0.3,  alpha_max = 0.6,  dive_distance = 1000,  cruise_altitude = 150, update_interval = 0.1},
  34.     medium = {alpha_min = 0.15, alpha_max = 0.5,  dive_distance = 2000, cruise_altitude = 300, update_interval = 0.2},
  35.     large  = {alpha_min = 0.1,  alpha_max = 0.35, dive_distance = 2000, cruise_altitude = 300, update_interval = 0.3}
  36. }
  37.  
  38. local alpha_vel_scale = 0.05
  39. local EPS = 1e-6
  40.  
  41. ------------------------------------------------------------
  42. -- Helper: Predictive lead aimpoint with performance optimization
  43. function GetLeadAimpoint(targetPos, targetVel, missilePos, missileSpeed, maxLead)
  44.     maxLead = maxLead or 500
  45.     local toTarget = targetPos - missilePos
  46.     local distance = toTarget.magnitude
  47.    
  48.     -- Skip calculation for very slow missiles or very close targets
  49.     if missileSpeed <= 0.1 or distance < 5 then
  50.         return targetPos
  51.     end
  52.    
  53.     -- Cache magnitude calculations
  54.     local timeToImpact = distance / missileSpeed
  55.     local leadOffset = targetVel * timeToImpact
  56.     local leadMag = leadOffset.magnitude
  57.    
  58.     -- Limit lead distance
  59.     if leadMag > maxLead then
  60.         leadOffset = leadOffset * (maxLead / leadMag)
  61.     end
  62.    
  63.     return targetPos + leadOffset
  64. end
  65.  
  66. ------------------------------------------------------------
  67. -- Helper: Exponential smoothing with nil checks
  68. function ExponentialSmooth(prev, current, alpha)
  69.     if not current then return prev end
  70.     if not prev then return current end
  71.     return Vector3(
  72.         alpha * current.x + (1 - alpha) * prev.x,
  73.         alpha * current.y + (1 - alpha) * prev.y,
  74.         alpha * current.z + (1 - alpha) * prev.z
  75.     )
  76. end
  77.  
  78. ------------------------------------------------------------
  79. -- Helper: Clean up missile data for destroyed missiles
  80. function CleanupMissileData(I)
  81.     if not I then return end  -- Safety check
  82.     local current_time = I:GetTime()
  83.     local missile_ids = {}
  84.    
  85.     -- Build set of active missile IDs
  86.     for t = 0, I:GetLuaTransceiverCount() - 1 do
  87.         for m = 0, I:GetLuaControlledMissileCount(t) - 1 do
  88.             local mi = I:GetLuaControlledMissileInfo(t, m)
  89.             if mi and mi.Valid then
  90.                 missile_ids[mi.Id] = true
  91.             end
  92.         end
  93.     end
  94.    
  95.     -- Clean up data for missiles that no longer exist
  96.     for id, _ in pairs(missile_initial_speeds) do
  97.         if not missile_ids[id] then
  98.             missile_initial_speeds[id] = nil
  99.             missile_target_index[id] = nil
  100.             missile_last_update[id] = nil
  101.             smoothed_aim_points[id] = nil
  102.             missile_altitude_phase[id] = nil
  103.             missile_guidance_active[id] = nil
  104.         end
  105.     end
  106. end
  107.  
  108. ------------------------------------------------------------
  109. -- Helper: Update missile energy state based on speed
  110. function UpdateMissileEnergy(missile_id, current_speed, current_time, I)
  111.     -- Initialize if needed
  112.     if missile_max_speeds[missile_id] == nil then
  113.         missile_max_speeds[missile_id] = current_speed
  114.         missile_energy[missile_id] = 0.0
  115.     end
  116.    
  117.     -- Only update energy at fixed intervals
  118.     if current_time - (missile_energy[missile_id.."_last_update"] or 0) < energy_update_interval then
  119.         return missile_energy[missile_id]
  120.     end
  121.    
  122.     -- Update max speed if current speed is higher
  123.     if current_speed > missile_max_speeds[missile_id] then
  124.         missile_max_speeds[missile_id] = current_speed
  125.     end
  126.    
  127.     -- Calculate energy level (0-1) based on current speed vs max speed
  128.     if missile_max_speeds[missile_id] > 0 then
  129.         missile_energy[missile_id] = current_speed / missile_max_speeds[missile_id]
  130.     else
  131.         missile_energy[missile_id] = 0
  132.     end
  133.    
  134.     missile_energy[missile_id.."_last_update"] = current_time
  135.     return missile_energy[missile_id]
  136. end
  137.  
  138. ------------------------------------------------------------
  139. -- Helper: Get update interval based on missile energy and type
  140. function GetUpdateInterval(missile_id, profile, current_time, I)
  141.     local base_interval = profile.update_interval or 0.1
  142.     local energy = missile_energy[missile_id] or 1.0
  143.    
  144.     -- Scale update rate based on energy (more frequent when energy is high)
  145.     local scaled_interval = base_interval * (1.5 - (energy * 0.5))
  146.    
  147.     -- Ensure minimum update interval
  148.     return math.max(0.05, scaled_interval)
  149. end
  150.  
  151. ------------------------------------------------------------
  152. -- Helper: Track target acceleration (unused for now)
  153. function GetTargetAcceleration(target_idx, current_vel)
  154.     local last_vel = last_target_velocities[target_idx]
  155.     last_target_velocities[target_idx] = current_vel
  156.     if not last_vel then
  157.         return Vector3(0, 0, 0)
  158.     end
  159.     return (current_vel - last_vel) / 1 -- assuming 1s update
  160. end
  161.  
  162. ------------------------------------------------------------
  163. -- Helper: Adaptive alpha based on target velocity change
  164. function GetAdaptiveAlpha(target_idx, current_vel, profile)
  165.     local last_vel = last_target_velocities[target_idx]
  166.     last_target_velocities[target_idx] = current_vel
  167.     if not last_vel then return profile.alpha_min end
  168.     local vel_change = Vector3.Magnitude(current_vel - last_vel)
  169.     local alpha = profile.alpha_min + math.min(profile.alpha_max - profile.alpha_min, vel_change * alpha_vel_scale)
  170.     return alpha
  171. end
  172.  
  173. ------------------------------------------------------------
  174. -- Helper: Classify missile type by initial speed
  175. function ClassifyMissile(initial_speed)
  176.     if initial_speed >= 35 then
  177.         return "small"
  178.     elseif initial_speed >= 15 then
  179.         return "medium"
  180.     else
  181.         return "large"
  182.     end
  183. end
  184.  
  185. ------------------------------------------------------------
  186. -- Helper: Score target for allocation
  187. function GetTargetScore(ref_pos, tinfo)
  188.     return Vector3.Distance(ref_pos, tinfo.AimPointPosition)
  189. end
  190.  
  191. ------------------------------------------------------------
  192. -- Helper: Exact proportional allocation
  193. function AllocateMissilesExact(targets, missile_count, ref_pos)
  194.     local weights = {}
  195.     local total_weight = 0
  196.  
  197.     for _, tgt in ipairs(targets) do
  198.         local score = GetTargetScore(ref_pos, tgt.info)
  199.         local weight = 1 / (score + EPS)
  200.         weights[tgt.index] = {weight = weight, tgt = tgt}
  201.         total_weight = total_weight + weight
  202.     end
  203.  
  204.     if total_weight <= 0 then
  205.         local allocation = {}
  206.         local base = math.floor(missile_count / #targets)
  207.         local rem = missile_count - base * #targets
  208.         for _, tgt in ipairs(targets) do
  209.             allocation[tgt.index] = base
  210.         end
  211.         for i = 1, rem do
  212.             allocation[targets[((i - 1) % #targets) + 1].index] =
  213.             allocation[targets[((i - 1) % #targets) + 1].index] + 1
  214.         end
  215.         return allocation
  216.     end
  217.  
  218.     local quotas = {}
  219.     local allocation = {}
  220.     local remainders = {}
  221.     local allocated_sum = 0
  222.     for _, tgt in ipairs(targets) do
  223.         local w = weights[tgt.index].weight
  224.         local quota = (w / total_weight) * missile_count
  225.         quotas[tgt.index] = quota
  226.         local flo = math.floor(quota)
  227.         allocation[tgt.index] = flo
  228.         allocated_sum = allocated_sum + flo
  229.         remainders[tgt.index] = quota - flo
  230.     end
  231.  
  232.     local remaining = missile_count - allocated_sum
  233.     if remaining > 0 then
  234.         local rem_list = {}
  235.         for idx, rem in pairs(remainders) do
  236.             table.insert(rem_list, {index = idx, rem = rem})
  237.         end
  238.         table.sort(rem_list, function(a, b)
  239.             if a.rem == b.rem then return a.index < b.index end
  240.             return a.rem > b.rem
  241.         end)
  242.         local i = 1
  243.         while remaining > 0 do
  244.             local pick = rem_list[((i - 1) % #rem_list) + 1]
  245.             allocation[pick.index] = allocation[pick.index] + 1
  246.             remaining = remaining - 1
  247.             i = i + 1
  248.         end
  249.     end
  250.  
  251.     return allocation
  252. end
  253.  
  254. ------------------------------------------------------------
  255. -- MAIN UPDATE
  256. function Update(I)
  257.     if not I then return end  -- Safety check
  258.     -- Get current time for update timing
  259.     local current_time = I:GetTime()
  260.    
  261.     -- Clean up data for destroyed missiles
  262.     CleanupMissileData(I)
  263.    
  264.     -- Gather valid targets with caching
  265.     local target_count = I:GetNumberOfTargets(0)
  266.     if target_count == 0 then
  267.         -- No targets, clean up and return
  268.         CleanupMissileData()
  269.         return
  270.     end
  271.    
  272.     local targets = {}
  273.     for ti = 0, target_count - 1 do
  274.         local tinfo = I:GetTargetInfo(0, ti)
  275.         if tinfo and tinfo.Valid then
  276.             table.insert(targets, {index = ti, info = tinfo})
  277.         end
  278.     end
  279.     if #targets == 0 then return end
  280.  
  281.     -- Gather missiles and compute average position
  282.     local missiles = {}
  283.     local total_missiles = 0
  284.     local sum_pos = Vector3(0,0,0)
  285.     for t = 0, I:GetLuaTransceiverCount() - 1 do
  286.         for m = 0, I:GetLuaControlledMissileCount(t) - 1 do
  287.             local mi = I:GetLuaControlledMissileInfo(t, m)
  288.             if mi and mi.Valid then
  289.                 total_missiles = total_missiles + 1
  290.                 local pos = mi.Position
  291.                 sum_pos = sum_pos + pos
  292.                 local vel = mi.Velocity
  293.                 local speed = Vector3.Magnitude(vel)
  294.                 -- Update missile energy state
  295.                 local energy = UpdateMissileEnergy(mi.Id, speed, current_time, I)
  296.                 table.insert(missiles, {t = t, m = m, id = mi.Id, pos = pos, velocity = vel, speed = speed, energy = energy})
  297.             end
  298.         end
  299.     end
  300.     if total_missiles == 0 then return end
  301.     local avg_pos = sum_pos / total_missiles
  302.  
  303.     -- Proportional allocation
  304.     local allocation = AllocateMissilesExact(targets, total_missiles, avg_pos)
  305.     local assigned_counts = {}
  306.     for _, tgt in ipairs(targets) do
  307.         assigned_counts[tgt.index] = 0
  308.         if allocation[tgt.index] == nil then allocation[tgt.index] = 0 end
  309.     end
  310.  
  311.     -- Sort missiles by speed
  312.     table.sort(missiles, function(a,b) return a.speed > b.speed end)
  313.  
  314.     -- Assign missiles
  315.     local target_index_order = {}
  316.     for _, tgt in ipairs(targets) do table.insert(target_index_order, tgt.index) end
  317.     for _, missile in ipairs(missiles) do
  318.         local missile_id = missile.id
  319.         if not missile_initial_speeds[missile_id] then
  320.             missile_initial_speeds[missile_id] = missile.speed
  321.         end
  322.         local current_tgt = missile_target_index[missile_id]
  323.         if current_tgt and allocation[current_tgt] and assigned_counts[current_tgt] < allocation[current_tgt] then
  324.             assigned_counts[current_tgt] = assigned_counts[current_tgt] + 1
  325.         else
  326.             local found = nil
  327.             for _, idx in ipairs(target_index_order) do
  328.                 if assigned_counts[idx] < allocation[idx] then
  329.                     found = idx
  330.                     break
  331.                 end
  332.             end
  333.             if not found then found = target_index_order[1] end
  334.             missile_target_index[missile_id] = found
  335.             assigned_counts[found] = assigned_counts[found] + 1
  336.         end
  337.     end
  338.  
  339.     -- Guidance loop with update rate control and climb behavior
  340.     for _, missile in ipairs(missiles) do
  341.         local t = missile.t
  342.         local m = missile.m
  343.         local missile_id = missile.id
  344.         local missile_pos = missile.pos
  345.         local missile_speed = missile.speed
  346.        
  347.         -- Skip if this missile was updated recently (update rate control)
  348.         local m_initial_speed = missile_initial_speeds[missile_id] or missile_speed
  349.         local missile_type = ClassifyMissile(m_initial_speed)
  350.         local profile = smoothing_profiles[missile_type]
  351.        
  352.         -- Initialize missile state if needed
  353.         if missile_guidance_active[missile_id] == nil then
  354.             missile_guidance_active[missile_id] = false
  355.             missile_altitude_phase[missile_id] = true -- Start in climb phase
  356.         end
  357.        
  358.         -- Check if it's time to update this missile based on energy and type
  359.         local last_update = missile_last_update[missile_id] or 0
  360.         local update_interval = GetUpdateInterval(missile_id, profile, current_time, I)
  361.         if current_time - last_update < update_interval then
  362.             goto continue
  363.         end
  364.         missile_last_update[missile_id] = current_time
  365.        
  366.         -- Skip update if missile is nearly out of energy
  367.         if missile.energy < 0.1 then
  368.             goto continue
  369.         end
  370.        
  371.         -- Get target info first
  372.         local target_idx = missile_target_index[missile_id]
  373.         local target_info = target_idx and I:GetTargetInfo(0, target_idx)
  374.         if not target_info or not target_info.Valid then
  375.             -- No valid target, fly straight
  376.             local straight_ahead = missile_pos + (missile.velocity.normalized * 1000)
  377.             I:SetLuaControlledMissileAimPoint(t, m,
  378.                 straight_ahead.x,
  379.                 straight_ahead.y,
  380.                 straight_ahead.z
  381.             )
  382.             goto continue
  383.         end
  384.        
  385.         local target_pos = target_info.AimPointPosition
  386.         local target_vel = target_info.Velocity
  387.         local target_distance = (missile_pos - target_pos).magnitude
  388.         if target_distance < 10 then  -- Within 5 meters
  389.             if not missile_proximity_armed[missile_id] then
  390.                 missile_proximity_armed[missile_id] = true
  391.                 missile_last_distance[missile_id] = target_distance
  392.             elseif missile_last_distance[missile_id] < target_distance then
  393.                 -- We're getting further away, detonate!
  394.                 I:DetonateLuaControlledMissile(t, m)
  395.                 goto continue
  396.             else
  397.                 missile_last_distance[missile_id] = target_distance
  398.             end
  399.         else
  400.             missile_proximity_armed[missile_id] = nil
  401.             missile_last_distance[missile_id] = nil
  402.         end
  403.        
  404.         -- Get target info
  405.         local target_idx = missile_target_index[missile_id]
  406.         local target_info = target_idx and I:GetTargetInfo(0, target_idx)
  407.        
  408.         -- Check if target is within 1500m for direct approach
  409.         if target_distance <= 1500 then
  410.             -- Fly directly to target with a small lead
  411.             local lead_point = GetLeadAimpoint(target_pos, target_vel or Vector3(0,0,0), missile_pos, missile_speed or 0, 500)
  412.             local direct_aim = lead_point or target_pos
  413.            
  414.             -- Add small vertical offset for hitbox
  415.             direct_aim = direct_aim + Vector3(0, -2, 0)
  416.            
  417.             I:SetLuaControlledMissileAimPoint(t, m, direct_aim.x, direct_aim.y, direct_aim.z)
  418.             goto continue
  419.         end
  420.        
  421.         -- Handle climb phase with fan-out (only for targets > 1500m away)
  422.         if missile_altitude_phase[missile_id] then
  423.             local cruise_alt = profile.cruise_altitude
  424.            
  425.             -- Generate a consistent fan-out offset based on missile ID
  426.             if not missile_fan_offset[missile_id] then
  427.                 -- Create a unique offset based on missile ID
  428.                 local id_str = tostring(missile_id)
  429.                 local id_hash = 0
  430.                 for i = 1, #id_str do
  431.                     id_hash = id_hash + string.byte(id_str, i) * i
  432.                 end
  433.                 math.randomseed(id_hash)
  434.                 -- Calculate angle relative to target direction (within 60 degrees left or right)
  435.                 local target_direction = (target_pos - missile_pos).normalized
  436.                 local base_angle = math.atan2(target_direction.z, target_direction.x)
  437.                 local angle_variation = (math.random() - 0.5) * (2 * math.pi / 3)  -- ±60 degrees
  438.                 local angle = base_angle + angle_variation
  439.                
  440.                 local distance = 50 + (id_hash % 100)  -- 50-150m offset
  441.                 missile_fan_offset[missile_id] = {
  442.                     x = math.cos(angle) * distance,
  443.                     z = math.sin(angle) * distance
  444.                 }
  445.             end
  446.            
  447.             -- Calculate climb point with offset
  448.             local offset = missile_fan_offset[missile_id] or {x=0, z=0}
  449.             local climb_point = Vector3(
  450.                 missile_pos.x + offset.x,
  451.                 cruise_alt,
  452.                 missile_pos.z + offset.z
  453.             )
  454.            
  455.             -- Check if we've reached cruise altitude
  456.             if missile_pos.y >= cruise_alt * 0.85 then  -- 85% of cruise alt
  457.                 missile_altitude_phase[missile_id] = false
  458.                 missile_guidance_active[missile_id] = true
  459.                 -- Initialize smoothed point at current position when starting guidance
  460.                 smoothed_aim_points[missile_id] = Vector3(climb_point.x, cruise_alt, climb_point.z)
  461.             end
  462.            
  463.             -- Set aim point with offset
  464.             I:SetLuaControlledMissileAimPoint(t, m,
  465.                 climb_point.x,
  466.                 cruise_alt,
  467.                 climb_point.z
  468.             )
  469.             goto continue
  470.         end
  471.        
  472.         -- Standard guidance for active phase
  473.         if not target_info or not target_info.Valid then
  474.             if missile_guidance_active[missile_id] then
  475.                 -- Try to find a new target if current one is lost
  476.                 missile_target_index[missile_id] = nil
  477.                 missile_guidance_active[missile_id] = false
  478.             end
  479.             goto continue
  480.         end
  481.        
  482.         local target_pos = target_info.AimPointPosition
  483.         local target_vel = target_info.Velocity
  484.         local target_distance = Vector3.Distance(target_pos, missile_pos)
  485.        
  486.         -- Only activate guidance if we're not in climb phase
  487.         if not missile_guidance_active[missile_id] and not missile_altitude_phase[missile_id] then
  488.             missile_guidance_active[missile_id] = true
  489.         end
  490.        
  491.         -- Calculate lead point with altitude management and safety checks
  492.         local lead_point = GetLeadAimpoint(target_pos, target_vel or Vector3(0,0,0), missile_pos, missile_speed or 0, 800)
  493.         local aim_point = lead_point and Vector3(lead_point.x, lead_point.y, lead_point.z) or Vector3(target_pos.x, target_pos.y, target_pos.z)
  494.        
  495.         -- Manage altitude based on distance to target
  496.         local min_dive_altitude = 20  -- Minimum altitude before starting dive
  497.         local start_dive_distance = profile.dive_distance * 1.5  -- Start diving earlier
  498.         local turn_start_distance = profile.dive_distance * 3.5  -- Start turning before diving
  499.        
  500.         -- Debug output
  501.         I:Log("Target distance: " .. target_distance .. ", turn_start_distance: " .. turn_start_distance)
  502.        
  503.         -- Calculate altitude based on distance
  504.         if target_distance > turn_start_distance then
  505.             -- Maintain cruise altitude while far from target
  506.             local base_point = Vector3(target_pos.x, profile.cruise_altitude, target_pos.z)
  507.            
  508.             -- Use the pre-calculated fan-out offset during cruise
  509.             local offset = missile_fan_offset[missile_id] or {x=0, z=0}
  510.             aim_point = Vector3(
  511.                 base_point.x + offset.x * 0.5,  -- Reduce offset during cruise
  512.                 base_point.y,
  513.                 base_point.z + offset.z * 0.5   -- Reduce offset during cruise
  514.             )
  515.            
  516.         elseif target_distance > start_dive_distance then
  517.             -- Start turning towards target while maintaining altitude
  518.             local turn_ratio = (target_distance - start_dive_distance) / (turn_start_distance - start_dive_distance)
  519.             local target_point = Vector3(target_pos.x, profile.cruise_altitude, target_pos.z)
  520.            
  521.             -- Blend between offset point and direct approach
  522.             aim_point = Vector3.Lerp(
  523.                 target_point,
  524.                 Vector3(target_pos.x, profile.cruise_altitude, target_pos.z),
  525.                 turn_ratio
  526.             )
  527.            
  528.         elseif target_distance > profile.dive_distance then
  529.             -- Start descending gradually while turning
  530.             local dive_ratio = (target_distance - profile.dive_distance) / (start_dive_distance - profile.dive_distance)
  531.             local target_alt = min_dive_altitude + (profile.cruise_altitude - min_dive_altitude) * dive_ratio
  532.             aim_point = Vector3(target_pos.x, math.max(target_alt, min_dive_altitude), target_pos.z)
  533.            
  534.         else
  535.             -- In final approach, aim directly at target with small offset
  536.             aim_point = target_pos + Vector3(0, -2, 0)  -- 2m offset to hit center
  537.         end
  538.        
  539.         -- Add small random offset to prevent perfect circular patterns
  540.         if target_distance < 50 then
  541.             aim_point = aim_point + Vector3(
  542.                 (math.random() - 0.5) * 2,
  543.                 (math.random() - 0.5) * 2,
  544.                 (math.random() - 0.5) * 2
  545.             )
  546.         end
  547.        
  548.         -- Adaptive smoothing with distance-based alpha
  549.         local alpha = GetAdaptiveAlpha(target_idx, target_vel, profile)
  550.         if target_distance < 300 then
  551.             alpha = profile.alpha_max -- More responsive at close range
  552.         end
  553.        
  554.         -- Apply smoothing
  555.         smoothed_aim_points[missile_id] =
  556.             ExponentialSmooth(smoothed_aim_points[missile_id], aim_point, alpha)
  557.        
  558.         -- Set final aim point
  559.         I:SetLuaControlledMissileAimPoint(t, m,
  560.             smoothed_aim_points[missile_id].x,
  561.             smoothed_aim_points[missile_id].y,
  562.             smoothed_aim_points[missile_id].z
  563.         )
  564.        
  565.         ::continue::
  566.     end
  567. end
  568.  
Advertisement
Add Comment
Please, Sign In to add comment