-------------------------------------------------------------------- -- lib/materiel.lua : resolution des peripheriques et adaptateurs. -- Tous les formats sont VERIFIES en jeu (inventaire du 17/07/2026). -- -- Directs : altitude_sensor (top), 2 Create_DisplayLink (faces dans -- conf.ECRANS), ender modem (gps), moteur diesel en bottom pilote -- par redstone analogique (15=arret, 14=mini, 0=maxi). -- Reseau : RSC (roles calibres), velocity_sensor x3 (axes/directions -- calibres), gimbal_sensor (axes calibres), optical_sensor, -- Create_Stressometer, redstone_relay (joystick calibre), -- linked_typewriter, monitor, 2 cuves create:fluid_tank. -------------------------------------------------------------------- local Materiel = {} local function trouver(type_, obligatoire, journal, note) local p = peripheral.find(type_) if not p and obligatoire then error("peripherique manquant: " .. type_, 0) end if not p and journal then journal.alerte(type_ .. " introuvable" .. (note and (": " .. note) or "")) end return p end function Materiel.initialiser(conf, etat, journal) local m = {} m.altitude = trouver("altitude_sensor", true) m.gimbal = trouver("gimbal_sensor", true) m.optical = trouver("optical_sensor", true) m.moniteur = trouver("monitor", true) m.relay = trouver("redstone_relay", false, journal, "joystick inactif") m.stresso = trouver("Create_Stressometer", false, journal, "detection moteur et surcharge inactives") m.typewriter = trouver("linked_typewriter", false, journal, "consigne au moniteur uniquement") -- les deux display links, identifies par leur face (conf.ECRANS) local function ecran(face, usage) local p = peripheral.wrap(face) if not p or peripheral.getType(face) ~= "Create_DisplayLink" then error(("Create_DisplayLink attendu en '%s' (%s), voir conf.ECRANS") :format(face, usage), 0) end return p end m.ecranConduite = ecran(conf.ECRANS.conduite, "conduite") m.ecranCarburant = ecran(conf.ECRANS.carburant, "carburant") -- rotation speed controllers m.rsc, m.rscParRole = {}, {} for _, nom in ipairs(peripheral.getNames()) do if peripheral.getType(nom) == "Create_RotationSpeedController" then m.rsc[nom] = peripheral.wrap(nom) local role = etat.roles[nom] if role then m.rscParRole[role] = m.rsc[nom] end end end -- velocity sensors m.velocite, m.veloParAxe = {}, {} for _, nom in ipairs(peripheral.getNames()) do if peripheral.getType(nom) == "velocity_sensor" then m.velocite[nom] = peripheral.wrap(nom) local aff = etat.velocite[nom] if aff then m.veloParAxe[aff.axe] = { p = m.velocite[nom], signe = aff.signe } end end end -- cuves de carburant (create:fluid_tank; exclut le moteur diesel, -- qui est fluid_storage mais pas fluid_tank) m.cuves = {} for _, nom in ipairs(peripheral.getNames()) do if peripheral.hasType(nom, "create:fluid_tank") then table.insert(m.cuves, peripheral.wrap(nom)) end end if #m.cuves == 0 then journal.alerte("aucune cuve create:fluid_tank: suivi carburant inactif") end ------------------------------------------------------------------ -- LECTURES ------------------------------------------------------------------ function m.lireAltitude() return m.altitude.getHeight() end -- angles bruts du gimbal (table de 2) function m.lireAnglesBruts() local a = m.gimbal.getAngles() return a[1] or 0, a[2] or 0 end -- assiette NORMALISEE via la calibration gimbal : -- tangage negatif = nez bas, roulis negatif = penche a gauche function m.lireAssiette() local g = etat.gimbal if not g then return m.lireAnglesBruts() end local a = m.gimbal.getAngles() return (a[g.indexTangage] or 0) * g.signeTangage, (a[g.indexRoulis] or 0) * g.signeRoulis end function m.lireDistanceSol() return m.optical.getDistance() end function m.auSol() return m.lireDistanceSol() <= conf.DIST_SOL end -- sol detecte ET posable (pas d'eau/lave: garde-fou ocean) function m.solPosable() if not m.optical.hasHit() then return false end local bloc = m.optical.getBlock() return not conf.BLOCS_INTERDITS[bloc] end function m.horizontal() local t, r = m.lireAssiette() return math.abs(t) <= conf.ANGLE_MAX and math.abs(r) <= conf.ANGLE_MAX end -- vitesse le long d'un axe calibre ("avant"|"lateral"|"vertical") -- signe: positif = avant / gauche / haut function m.lireVitesseAxe(axe) local c = m.veloParAxe[axe] if not c then return 0 end return (c.p.getVelocity() or 0) * c.signe end function m.vitesseHorizontale() local va = m.lireVitesseAxe("avant") local vl = m.lireVitesseAxe("lateral") return math.sqrt(va * va + vl * vl) end -- joystick calibre: avance (devant-derriere), virage (gauche-droite) -- dans -1..1; pas de zone morte (joystick de mod, zero franc) function m.lireJoystick() local j = etat.joystick if not (m.relay and j) then return 0, 0 end local function lire(direction) local face = j[direction] if not face then return 0 end return m.relay.getAnalogInput(face) / 15 end return lire("devant") - lire("derriere"), lire("gauche") - lire("droite") end function m.lireFacesRelay() if not m.relay then return {} end local lectures = {} for _, face in ipairs({ "top", "bottom", "left", "right", "front", "back" }) do lectures[face] = m.relay.getAnalogInput(face) end return lectures end -- typewriter: table des codes de touches actuellement pressees function m.lireTouches() if not m.typewriter then return {} end return m.typewriter.getPressedKeyCodes() or {} end -- stressometer (formats verifies): ratio 0..1, ou nil function m.lireStress() if not m.stresso then return nil end local cap = m.stresso.getStressCapacity() if not cap or cap <= 0 then return nil end return m.stresso.getStress() / cap end -- capacite > 0 <=> le moteur tourne (verifie: capacite 0 a l'arret) function m.moteurTourne() if not m.stresso then return true end -- indetectable: on suppose oui return (m.stresso.getStressCapacity() or 0) > 0 end -- carburant: quantite totale (mB) et capacite totale function m.lireCarburant() if #m.cuves == 0 then return nil end local quantite, capacite = 0, 0 for _, cuve in ipairs(m.cuves) do for _, t in ipairs(cuve.tanks() or {}) do quantite = quantite + (t.amount or 0) capacite = capacite + (t.capacity or conf.CARBURANT.CAPACITE_TANK) end end if capacite <= 0 then capacite = conf.CARBURANT.CAPACITE_TANK * #m.cuves end return quantite, capacite end -- position GPS corrigee des offsets, ou nil function m.lirePosition() local x, y, z = gps.locate(2) if not x then return nil end return x + conf.OFFSET_X, y + conf.OFFSET_Y, z + conf.OFFSET_Z end ------------------------------------------------------------------ -- SORTIES ------------------------------------------------------------------ function m.reglerMoteur(niveau) -- 0 (arret) .. 15 (maxi) niveau = math.max(0, math.min(15, math.floor(niveau + 0.5))) redstone.setAnalogOutput("bottom", 15 - niveau) end function m.reglerRsc(role, vitesse) local p = m.rscParRole[role] if p then p.setTargetSpeed(math.floor(vitesse + 0.5)) end end function m.toutArreter() for _, p in pairs(m.rsc) do p.setTargetSpeed(0) end end ------------------------------------------------------------------ -- DIAGNOSTIC DES CALIBRATIONS ------------------------------------------------------------------ function m.helicesManquantes() local manquantes = {} for _, role in ipairs({ "lb", "rb", "lf", "rf" }) do if not m.rscParRole[role] then table.insert(manquantes, role) end end return manquantes end function m.propulseursManquants() local manquants = {} for _, role in ipairs({ "prop_l", "prop_r" }) do if not m.rscParRole[role] then table.insert(manquants, role) end end return manquants end function m.axesManquants() local manquants = {} for _, axe in ipairs({ "avant", "lateral", "vertical" }) do if not m.veloParAxe[axe] then table.insert(manquants, axe) end end return manquants end return m end return Materiel