Advertisement
Berfuglol

Idk

Apr 10th, 2025 (edited)
341
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 15.79 KB | Gaming | 0 0
  1. -- Import necessary libraries
  2. print("Create Mod Big Cannons Ballistics Calculator Ultimate! Booting")
  3. math = require("math") -- DTB
  4.  
  5. -- Define the side of the computer where the bundled cable is connected
  6. local bundledSide = "bottom" -- Adjust this as needed
  7.  
  8. -- Define color variables in a table for dynamic access
  9. local chargeColors = {
  10.     Charge1 = colors.lightBlue,
  11.     Charge2 = colors.magenta,
  12.     Charge3 = colors.orange,
  13.     Charge4 = colors.white,
  14.     Shell = colors.yellow,
  15. }
  16. local componentColors = {
  17.     GunBreachGearShift = colors.lime,
  18.     GunLoadingPole = colors.brown,
  19.     GunPitchClutch = colors.cyan,
  20.     GunYawClutch = colors.purple,
  21.     GunYawGearShift = colors.blue,
  22.     GunBuild = colors.gray,
  23.     GunAlarm = colors.black,
  24.     GunFire = colors.green,
  25. }
  26.  
  27. -- Initialize variables for the chat system and the UUIDs
  28. local chatBox = peripheral.find("chatBox")
  29. if not chatBox then
  30.     error("ChatBox peripheral not found.")
  31. end
  32.  
  33. local authorizedUUIDs = {
  34.     "uuid1",
  35.     "76364a85-1e9c-48df-975c-11eb045d5a51",
  36.     -- Add more authorized UUIDs here
  37. }
  38.  
  39. -- Function to check if a UUID is authorized
  40. local function isAuthorized(uuid)
  41.     for _, authorizedUUID in ipairs(authorizedUUIDs) do
  42.         if uuid == authorizedUUID then
  43.             return true
  44.         end
  45.     end
  46.     return false
  47. end
  48.  
  49. -- Function to power on a specific color (activate a component)
  50. local function PowerOn(componentColor)
  51.     if not componentColor then
  52.         print("Error: Invalid color provided to PowerOn.")
  53.         return
  54.     end
  55.     local currentOutput = redstone.getBundledOutput(bundledSide) or 0
  56.     redstone.setBundledOutput(bundledSide, bit.bor(currentOutput, componentColor))
  57.     print("Powered on color: " .. tostring(componentColor))
  58. end
  59.  
  60. -- Function to power off a specific color (deactivate a component)
  61. local function PowerOff(componentColor)
  62.     if not componentColor then
  63.         print("Error: Invalid color provided to PowerOff.")
  64.         return
  65.     end
  66.     local currentOutput = redstone.getBundledOutput(bundledSide) or 0
  67.     redstone.setBundledOutput(bundledSide, bit.band(currentOutput, bit.bnot(componentColor)))
  68.     print("Powered off color: " .. tostring(componentColor))
  69. end
  70.  
  71. -- Function to reset all outputs
  72. local function ResetOutputs()
  73.     redstone.setBundledOutput(bundledSide, 0)
  74.     print("All outputs reset.")
  75. end
  76.  
  77. -- Variables to store cannon data and pending fire mission
  78. local Cannon = {}
  79. local pendingFireSolution = nil
  80. local RotationConstant = 2.6695 / 10
  81.  
  82. -- Function to send a denial message with red brackets
  83. local function sendDeniedMessage(username)
  84.     chatBox.sendMessageToPlayer("You are not authorized to perform this action.", username, "Denied", "[]", "&c")
  85. end
  86.  
  87. -- Function to send success message with green brackets
  88. local function sendAcceptedMessage(username, message)
  89.     chatBox.sendMessageToPlayer(message, username, "Accepted", "[]", "&a")
  90. end
  91.  
  92. -- Function to send informational message with blue brackets
  93. local function sendInfoMessage(username, message)
  94.     chatBox.sendMessageToPlayer(message, username, "Info", "[]", "&b")
  95. end
  96.  
  97. -- Function to save cannon data to a file
  98. local function SaveCannonData()
  99.     local file = fs.open("cannon_data.txt", "w")
  100.     if file == nil then
  101.         print("Error opening file for writing.")
  102.         return
  103.     end
  104.     file.writeLine(Cannon.x)
  105.     file.writeLine(Cannon.y)
  106.     file.writeLine(Cannon.z)
  107.     file.writeLine(Cannon.yaw)
  108.     file.writeLine(Cannon.maxCharges)
  109.     file.close()
  110.     print("Cannon data saved.")
  111. end
  112.  
  113. -- Function to load cannon data from a file
  114. local function LoadCannonData()
  115.     local file = fs.open("cannon_data.txt", "r")
  116.     if file == nil then
  117.         print("No cannon data found.")
  118.         return false -- Indicate that data was not loaded
  119.     end
  120.     Cannon.x = tonumber(file.readLine())
  121.     Cannon.y = tonumber(file.readLine())
  122.     Cannon.z = tonumber(file.readLine())
  123.     Cannon.yaw = tonumber(file.readLine())
  124.     Cannon.maxCharges = tonumber(file.readLine())
  125.     file.close()
  126.     print("Cannon data loaded.")
  127.     return true -- Indicate that data was loaded successfully
  128. end
  129.  
  130. -- Function to prompt the user for cannon info via console
  131. local function PromptForCannonInfo()
  132.     print("No cannon data found. Please enter cannon information.")
  133.     print("Input Barrel X: ")
  134.     Cannon.x = tonumber(io.read())
  135.     print("Input Barrel Y: ")
  136.     Cannon.y = tonumber(io.read())
  137.     print("Input Barrel Z: ")
  138.     Cannon.z = tonumber(io.read())
  139.     print("Facing Yaw? (-180 to 180): ")
  140.     Cannon.yaw = tonumber(io.read())
  141.     print("Max Charges?: ")
  142.     Cannon.maxCharges = tonumber(io.read())
  143.     SaveCannonData()
  144.     print("Cannon information saved.")
  145. end
  146.  
  147. -- Function to set cannon information via chat command
  148. local function SetCannonInfo(username, params)
  149.     local x, y, z, yaw, maxCharges = params:match("^(%-?%d+) (%-?%d+) (%-?%d+) (%-?%d+) (%d+)$")
  150.     if x and y and z and yaw and maxCharges then
  151.         Cannon.x = tonumber(x)
  152.         Cannon.y = tonumber(y)
  153.         Cannon.z = tonumber(z)
  154.         Cannon.yaw = tonumber(yaw)
  155.         Cannon.maxCharges = tonumber(maxCharges)
  156.         SaveCannonData()
  157.         sendAcceptedMessage(username, "Cannon information updated.")
  158.     else
  159.         sendInfoMessage(username, "Invalid format. Use: <SetCannon> x y z yaw maxCharges")
  160.     end
  161. end
  162.  
  163. -- Define the maximum acceptable distance error
  164. local MaxDistanceError = 70 -- Adjust this value as needed
  165.  
  166. -- Function to calculate the pitch angle and charge count
  167. local function CalculatePitch(maxCharges, Distance, TargetY)
  168.     local overallBestCharge = nil
  169.     local overallBestAngle = nil
  170.     local overallBestDistanceError = math.huge
  171.  
  172.     for ChargeCount = maxCharges, 2, -1 do  -- Minimum charge count is now 2
  173.         local bestAngle = nil
  174.         local bestDistanceError = math.huge
  175.  
  176.         for angle = 10, 60, 0.1 do
  177.             local height = Cannon.y + 0.01
  178.             local muzzle_velocity = 40 * ChargeCount
  179.             local rad_angle = math.rad(angle)
  180.             local horizontal_velocity = muzzle_velocity * math.cos(rad_angle)
  181.             local vertical_velocity = muzzle_velocity * math.sin(rad_angle)
  182.             local time = 0
  183.             local range = 0
  184.  
  185.             while height > TargetY or vertical_velocity > 0 do
  186.                 time = time + 0.05
  187.                 vertical_velocity = vertical_velocity - 23 * 0.05
  188.                 range = range + horizontal_velocity * 0.05
  189.                 horizontal_velocity = horizontal_velocity * 0.99
  190.                 height = height + vertical_velocity * 0.05
  191.             end
  192.  
  193.             local distanceError = math.abs(range - Distance)
  194.  
  195.             if distanceError < bestDistanceError then
  196.                 bestDistanceError = distanceError
  197.                 bestAngle = angle
  198.             end
  199.         end
  200.  
  201.         -- Check if this is the best overall solution
  202.         if bestDistanceError < overallBestDistanceError then
  203.             overallBestDistanceError = bestDistanceError
  204.             overallBestAngle = bestAngle
  205.             overallBestCharge = ChargeCount
  206.         end
  207.  
  208.         -- If the distance error is acceptable, return immediately
  209.         if bestDistanceError <= MaxDistanceError then
  210.             return ChargeCount, bestAngle, bestDistanceError
  211.         end
  212.     end
  213.  
  214.     -- After trying all charges, return nil if no acceptable solution found
  215.     return nil, nil, nil
  216. end
  217.  
  218. local function normalizeAngle(angle)
  219.     angle = angle % 360
  220.     if angle > 180 then
  221.         angle = angle - 360
  222.     end
  223.     return angle
  224. end
  225.  
  226. -- Function to handle the fire solution calculation
  227. -- Function to handle the fire solution calculation
  228. local function FireSolution(Target)
  229.     -- Ensure Cannon data is loaded
  230.     if not Cannon.x or not Cannon.y or not Cannon.z then
  231.         return false, "Cannon data not loaded. Please set cannon info using <SetCannon> command."
  232.     end
  233.  
  234.     -- Calculate Distance
  235.     local Distance = math.sqrt((Target.x - Cannon.x)^2 + (Target.z - Cannon.z)^2)
  236.  
  237.     -- Call CalculatePitch()
  238.     local ChargeCount, ClosestAngle, ClosestDistance = CalculatePitch(Cannon.maxCharges, Distance, Target.y)
  239.  
  240.     if ChargeCount then
  241.         local rawYaw = math.deg(math.atan2(Target.z - Cannon.z, Target.x - Cannon.x)) - Cannon.yaw - 90
  242.         local Yaw = normalizeAngle(rawYaw)
  243.         local RotationTimeAngle = ClosestAngle * RotationConstant
  244.         local YawTime = math.abs(Yaw * RotationConstant)
  245.  
  246.         local fireSolutionMessage = string.format(
  247.             "Fire Solution:\nAccuracy range: ±%.2f blocks\nCharge Count: %d\nYaw: %.2f degrees\nAngle: %.2f degrees\nType 'confirm' to proceed with firing.",
  248.             ClosestDistance, ChargeCount, Yaw, ClosestAngle
  249.         )
  250.  
  251.         -- Return success, message, and necessary data
  252.         return true, fireSolutionMessage, {
  253.             ChargeCount = ChargeCount,
  254.             ClosestAngle = ClosestAngle,
  255.             ClosestDistance = ClosestDistance,
  256.             Yaw = Yaw,
  257.             RotationTimeAngle = math.abs(ClosestAngle * RotationConstant),
  258.             YawTime = math.abs(Yaw * RotationConstant),
  259.             Target = Target,
  260.             username = pendingFireSolution and pendingFireSolution.username or nil,
  261.         }
  262.     else
  263.         return false, "No Fire Solution possible within acceptable error margin for coordinates X=" .. Target.x .. ", Y=" .. Target.y .. ", Z=" .. Target.z
  264.     end
  265. end
  266.  
  267.  
  268. -- Function to load the required number of charges
  269. local function func_load_shells_mission(shells)
  270.     if shells < 2 or shells > 4 then  -- Minimum shells is now 2
  271.         print("Error: Number of shells must be between 2 and 4.")
  272.         return
  273.     end
  274.  
  275.     -- Activate the required charges
  276.     for i = 1, shells do
  277.         local chargeName = "Charge" .. i
  278.         local chargeColor = chargeColors[chargeName] -- Access from the table
  279.         if chargeColor then
  280.             PowerOn(chargeColor)
  281.         else
  282.             print("Error: " .. chargeName .. " not defined.")
  283.         end
  284.     end
  285.     PowerOn(chargeColors["Shell"])
  286.  
  287.     -- Wait for 2 seconds
  288.     sleep(2)
  289.  
  290.     -- Deactivate all charges
  291.     for i = 1, shells do
  292.         local chargeName = "Charge" .. i
  293.         local chargeColor = chargeColors[chargeName]
  294.         if chargeColor then
  295.             PowerOff(chargeColor)
  296.         else
  297.             print("Error: " .. chargeName .. " not defined.")
  298.         end
  299.     end
  300.     PowerOff(chargeColors["Shell"])
  301.     sleep(13)
  302. end
  303.  
  304. -- Function to execute the fire mission
  305. local function ExecuteFireMission(fireMissionData)
  306.     -- Extract data
  307.     local ChargeCount = fireMissionData.ChargeCount
  308.     local ClosestAngle = fireMissionData.ClosestAngle
  309.     local Yaw = fireMissionData.Yaw
  310.     local RotationTimeAngle = fireMissionData.RotationTimeAngle
  311.     local YawTime = fireMissionData.YawTime
  312.     local Target = fireMissionData.Target
  313.     local username = fireMissionData.username
  314.  
  315.     -- Reset outputs
  316.     ResetOutputs()
  317.     PowerOff(componentColors.GunBuild)
  318.  
  319.     -- Load the required number of charges
  320.     print("Loading " .. ChargeCount .. " charges...")
  321.     sendAcceptedMessage(username, "Starting Fire Mission with " .. ChargeCount .. " charges.")
  322.     func_load_shells_mission(ChargeCount)
  323.     sendAcceptedMessage(username, ChargeCount .. " charges loaded.")
  324.  
  325.     -- Prepare for firing
  326.     PowerOn(componentColors.GunBuild)
  327.     sleep(0.5)
  328.  
  329.     -- Handle Yaw Direction
  330.     if Yaw < 0 then
  331.         PowerOn(componentColors.GunYawGearShift) -- Set direction for negative Yaw
  332.     else
  333.         PowerOff(componentColors.GunYawGearShift) -- Set direction for positive Yaw
  334.     end
  335.  
  336.     -- Start moving both Pitch and Yaw
  337.     print("Aiming Cannon Pitch and Yaw simultaneously...")
  338.     local pitchActive = true
  339.     local yawActive = true
  340.     local elapsedTime = 0
  341.     local timeStep = 0.1 -- Time increment for the loop
  342.  
  343.     -- Turn on both motors if movement is needed
  344.     if RotationTimeAngle > 0 then
  345.         PowerOn(componentColors.GunPitchClutch)
  346.     else
  347.         pitchActive = false -- No movement needed
  348.     end
  349.  
  350.     if YawTime > 0 then
  351.         PowerOn(componentColors.GunYawClutch)
  352.     else
  353.         yawActive = false -- No movement needed
  354.     end
  355.  
  356.     -- Timer loop
  357.     while pitchActive or yawActive do
  358.         sleep(timeStep)
  359.         elapsedTime = elapsedTime + timeStep
  360.  
  361.         -- Check Pitch
  362.         if pitchActive and elapsedTime >= RotationTimeAngle then
  363.             PowerOff(componentColors.GunPitchClutch)
  364.             pitchActive = false
  365.             print("Pitch adjustment complete.")
  366.         end
  367.  
  368.         -- Check Yaw
  369.         if yawActive and elapsedTime >= YawTime then
  370.             PowerOff(componentColors.GunYawClutch)
  371.             yawActive = false
  372.             print("Yaw adjustment complete.")
  373.         end
  374.     end
  375.  
  376.     -- Fire the cannon
  377.     print("Firing Cannon...")
  378.     PowerOn(componentColors.GunAlarm)
  379.     sleep(1)
  380.     PowerOn(componentColors.GunFire)
  381.     sleep(1)
  382.     PowerOff(componentColors.GunFire)
  383.     PowerOff(componentColors.GunAlarm)
  384.     PowerOff(componentColors.GunBuild)
  385.     print("Fire mission complete.")
  386.     sendAcceptedMessage(username, "Fire Mission Complete.")
  387. end
  388.  
  389.  
  390. -- Attempt to load cannon data
  391. local dataLoaded = LoadCannonData()
  392.  
  393. -- If data not loaded, prompt the user for cannon info
  394. if not dataLoaded then
  395.     PromptForCannonInfo()
  396. end
  397.  
  398. -- Main event loop for chat handling
  399. while true do
  400.     local event, username, message, uuid, isHidden = os.pullEvent("chat")
  401.     print("Chat event from " .. username .. ": " .. message)
  402.  
  403.     -- Check if the message is a command
  404.     if message == "<GetMyUUID>" then
  405.         -- Respond with the user's UUID
  406.         sendInfoMessage(username, "Your UUID is: " .. uuid)
  407.     elseif message:match("^<[%a]+>") then
  408.         -- This is a command, check authorization
  409.         if isAuthorized(uuid) then
  410.             local x, y, z = message:match("^<FireSolution> (%-?%d+) (%-?%d+) (%-?%d+)")
  411.             if x and y and z then
  412.                 -- Handle FireSolution command
  413.                 local Target = { x = tonumber(x), y = tonumber(y), z = tonumber(z) }
  414.                 local success, fireSolutionMessage, fireMissionData = FireSolution(Target)
  415.                 if success then
  416.                     -- Send the fire solution to the user via chat
  417.                     sendInfoMessage(username, fireSolutionMessage)
  418.                     -- Set pending fire solution
  419.                     pendingFireSolution = {
  420.                         username = username,
  421.                         data = fireMissionData,
  422.                     }
  423.                 else
  424.                     -- Send failure message
  425.                     sendInfoMessage(username, fireSolutionMessage)
  426.                     pendingFireSolution = nil
  427.                 end
  428.             else
  429.                 sendInfoMessage(username, "Unknown command or invalid format.")
  430.             end
  431.         else
  432.             -- Handle unauthorized access
  433.             sendDeniedMessage(username)
  434.         end
  435.     elseif pendingFireSolution and username == pendingFireSolution.username then
  436.         if message:lower() == "confirm" then
  437.             -- Proceed with firing
  438.             sendAcceptedMessage(username, "Firing mission proceeding.")
  439.             pendingFireSolution.data.username = username -- Pass the username to the execution function
  440.             ExecuteFireMission(pendingFireSolution.data)
  441.             pendingFireSolution = nil
  442.         elseif message:lower() == "cancel" then
  443.             sendInfoMessage(username, "Fire mission canceled.")
  444.             pendingFireSolution = nil
  445.         else
  446.             sendInfoMessage(username, "Please type 'confirm' to proceed or 'cancel' to abort.")
  447.         end
  448.     else
  449.         -- Normal chat message
  450.         print("Normal chat message: " .. message)
  451.     end
  452. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement