require "Vehicles/Papa_Chad_Tank_Cannon" require "Vehicles/Papa_Chad_Tank_Aim" MTKViewpointTurrets = MTKViewpointTurrets or {} local M = MTKViewpointTurrets local seats = { [0] = "SeatFrontLeft", [1] = "SeatGunner", [2] = "SeatFrontRight", [3] = "SeatRearRight" } local scope = nil local function enabled() return MTKViewpointCamera and MTKViewpointCamera.enabled() end local function allowed(player, vehicle, weapon) return player == getPlayer() and not player:isDead() and MTKViewpointCamera.captured() and getGameSpeed() > 0 and not (UIManager and UIManager.isMouseOverInventory and UIManager.isMouseOverInventory()) and seats[vehicle:getSeat(player)] == weapon.requiredSeat and player:getCharacterActions():isEmpty() end function M.install() -- These local adapters register their own wrappers at boot/start. Install -- them first, then wrap the completed chain, regardless of event order. if KFTFerret and KFTFerret.installClient then KFTFerret.installClient() end if KLTLAV and KLTLAV.installClient then KLTLAV.installClient() end if not tankAimSystemPC or not chooseWeaponPC or not ISCoordConversion then return end if ISCoordConversion.ToWorld ~= M.toWorld then local previousToWorld = ISCoordConversion.ToWorld M.toWorld = function(x, y, z) -- Only override conversions inside this turret update. The Ferret -- and LAV wrappers otherwise overwrite our camera heading with a -- floor pick (or the screen-centre isometric fallback). if scope and scope.x then return scope.x, scope.y end return previousToWorld(x, y, z) end ISCoordConversion.ToWorld = M.toWorld end if chooseWeaponPC ~= M.choose then local previousChoose = chooseWeaponPC M.choose = function(vehicle) -- MTK still advances existing projectiles when weapon input is -- blocked; no simulation callback is removed or duplicated. if scope and scope.blocked then return nil end return previousChoose(vehicle) end chooseWeaponPC = M.choose end if tankAimSystemPC ~= M.aim then local previousAim = tankAimSystemPC Events.OnPlayerUpdate.Remove(previousAim) M.aim = function(player) local vehicle = player and player:getVehicle() if not enabled() or not vehicle then return previousAim(player) end local weapon = chooseWeaponPC(vehicle) if not weapon then return previousAim(player) end local oldScope = scope scope = { blocked = not allowed(player, vehicle, weapon) } local oldDirection = nil if not scope.blocked and isMouseButtonDown(1) then local heading = MTKViewpointCamera.heading() if type(heading) == "number" and heading == heading and math.abs(heading) < math.huge then oldDirection = player:getDirectionAngle() local rad = math.rad(heading) scope.x = player:getX() + math.cos(rad) * 100 scope.y = player:getY() + math.sin(rad) * 100 player:setDirectionAngle(heading) else scope.blocked = true end end -- Restore temporary input even if a dependency raises an error. local ok, err = pcall(previousAim, player) scope = oldScope if oldDirection ~= nil then player:setDirectionAngle(oldDirection) end if not ok then error(err) end end tankAimSystemPC = M.aim Events.OnPlayerUpdate.Add(M.aim) print("[MTKViewpointTurrets] MTK camera aiming registered; Ferret/LAV wrappers retained.") end if TankCursor and TankCursor.prerender ~= M.cursor then local previousCursor = TankCursor.prerender M.cursor = function(self) if not enabled() then return previousCursor(self) end -- MTK's two iso-projected textures cannot represent the 3D view. -- A centred cross marks camera bearing; green means the turret -- has caught up in yaw, not that ammunition or a hit is guaranteed. local player = getPlayer() local vehicle = player and player:getVehicle() local weapon = vehicle and chooseWeaponPC(vehicle) if not weapon or not allowed(player, vehicle, weapon) or not isMouseButtonDown(1) then return end local heading = MTKViewpointCamera.heading() if not heading then return end local turret = turretAngles and turretAngles[vehicle:getId()] local aligned = turret and math.abs(((turret - heading + 540) % 360) - 180) <= 2 local r, g, b = 1, 0.75, 0.25 if aligned then r, g, b = 0.3, 1, 0.4 end local x = getCore():getScreenWidth() / 2 - self.x local y = getCore():getScreenHeight() / 2 - self.y self:drawRect(x - 9, y, 5, 1, 0.9, r, g, b) self:drawRect(x + 4, y, 5, 1, 0.9, r, g, b) self:drawRect(x, y - 9, 1, 5, 0.9, r, g, b) self:drawRect(x, y + 4, 1, 5, 0.9, r, g, b) end TankCursor.prerender = M.cursor end end Events.OnGameBoot.Add(M.install) Events.OnGameStart.Add(M.install) Events.OnGameStart.Add(function() if not MTKViewpointCamera then print("[MTKViewpointTurrets] Camera bridge unavailable. Enable this mod and approve its local JAR in ZombieBuddy, then fully restart the game.") end end)