require "KLT_LAV" require "TimedActions/KLT_ReloadLAV" require "Vehicles/Papa_Chad_Tank_Cannon" local F = KLTLAV local characterVariables = { "M2_idle", "M2_360Anim", "M2_045Anim", "M2_090Anim", "M2_135Anim", "M2_180Anim", "M2_225Anim", "M2_270Anim", "M2_315Anim", } function F.installClient() if F.clientInstalled then return end if not weaponConfig or not weaponConfig.M41_76mm or not chooseWeaponPC or not tankAimSystemPC then print("[KI5LAVTurret] MTK turret API unavailable; controls not installed.") return end local profile = {} for key, value in pairs(weaponConfig.M41_76mm) do profile[key] = value end profile.requiredPart = F.weaponPart profile.requiredSeat = "SeatGunner" -- MTK's label for index 1, not a renamed seat. profile.requiredItem = F.ammoType profile.requiredItemHE = F.heAmmoType profile.coax = false profile.sound = "HRSys_LAV300_90mm_Fire" profile.soundEnd = "HRSys_LAV300_90mm_End" profile.rotationTime = 10 profile.shotsPerMinute = 12 profile.startHeight = 0.7 profile.penetrationMM = 150 profile.soundTurret = "Turret_Electre" profile.soundTurretCooldown = 0.25 weaponConfig[F.weaponPart] = profile F.profile = profile -- Keep AP damage unchanged. HE uses precisely the tank profile's explosion -- radius, flash radius and damage, with MTK's existing explosion code. local heProfile = {} for key, value in pairs(profile) do heProfile[key] = value end heProfile.penetrationMM = weaponConfig.M41_76mm.penetrationMM F.heProfile = heProfile local originalChoose = chooseWeaponPC chooseWeaponPC = function(vehicle) if F.isLAV(vehicle) then if not F.inputBlocked and F.weaponReady(vehicle) and not F.pendingReload[getPlayer()] then local part = vehicle:getPartById(F.weaponPart) local container = part and part:getItemContainer() if container and container:containsType(F.heAmmoType) then return heProfile end return profile end return nil end return originalChoose(vehicle) end local originalAim = tankAimSystemPC Events.OnPlayerUpdate.Remove(originalAim) tankAimSystemPC = function(player) local vehicle = player and player:getVehicle() if not F.isLAV(vehicle) then return originalAim(player) end local gunner = F.isGunner(vehicle, player) and player == getPlayer() and not player:isDead() local overInventory = UIManager and UIManager.isMouseOverInventory and UIManager.isMouseOverInventory() -- Still call MTK so its existing projectiles continue to advance. A nil -- weapon prevents input/state changes from driver or non-local updates. F.inputBlocked = not gunner or overInventory or getGameSpeed() == 0 if F.inputBlocked then originalAim(player) F.inputBlocked = false return end local oldDirection = player:getDirectionAngle() local oldSneaking = player:isSneaking() local oldVariables = {} for _, name in ipairs(characterVariables) do oldVariables[name] = player:getVariableString(name) end local aiming = isMouseButtonDown(1) and player:getCharacterActions():isEmpty() if aiming then -- ToWorld also uses the installed Viewpoint mouse bridge when active. -- Scaled mouse coordinates are required by the base-game conversion. local x, y = ISCoordConversion.ToWorld(getMouseXScaled(), getMouseYScaled(), player:getZ() + profile.startHeight) if x and y then local dx, dy = x - player:getX(), y - player:getY() if dx * dx + dy * dy > 0.0001 then player:setDirectionAngle(math.deg(math.atan2(dy, dx))) end end end local weapon = vehicle:getPartById(F.weaponPart) local container = weapon and weapon:getItemContainer() local round = aiming and isMouseButtonDown(0) and container and (container:FindAndReturn(F.heAmmoType) or container:FindAndReturn(F.ammoType)) originalAim(player) if round and isClient() and not container:contains(round) then sendRemoveItemFromContainer(container, round) end -- Keep DAMN's existing seated pose instead of MTK's exposed M2 gunner pose. player:setDirectionAngle(oldDirection) player:setSneaking(oldSneaking) for _, name in ipairs(characterVariables) do if oldVariables[name] and oldVariables[name] ~= "" then player:setVariable(name, oldVariables[name]) else player:clearVariable(name) end end if aiming and turretAngles[vehicle:getId()] and not isClient() then local hull = calculateVehicleRotation(vehicle:getAngleX(), vehicle:getAngleY(), vehicle:getAngleZ()) local relative = (hull - turretAngles[vehicle:getId()] + 360) % 360 F.savePose(vehicle, F.poseForAngle(relative)) end end Events.OnPlayerUpdate.Add(tankAimSystemPC) F.clientInstalled = true print("[KI5LAVTurret] Gunner controls registered with Military Tool Kit.") end Events.OnGameBoot.Add(F.installClient) Events.OnGameStart.Add(F.installClient)