--[[
Name: Def Pack
Copyright (C) Levis, 2025
Author: Levis
All Rights Reserved
Date: 31.07.2025
Version: 1.0.0.3
]]

--[[
-- Important:
-- Not to be added to any mods / maps or modified from its current release form.
-- No modifications may be made to this script without written permission from Levis.

-- Wichtig:
-- Darf nicht zu Mods / Karten hinzugefügt oder in seiner aktuellen Veröffentlichungsform geändert werden.
-- Änderungen an diesem Skript dürfen nur mit schriftlicher Genehmigung von Levis vorgenommen werden.

-- Fontos:
-- Nem adható hozzá semmilyen modhoz / térképhez, és nem módosítható az aktuális kiadási formájában.
-- A szkript módosítása csak Levis írásos engedélyével történhet.

-- Important :
-- Ne doit pas être ajouté à des mods / cartes ou modifié sous sa forme de publication actuelle.
-- Aucune modification ne peut être apportée à ce script sans l'autorisation écrite de Levis.

-- Importante:
-- No debe añadirse a ningún mod / mapa ni modificarse desde su versión actual.
-- No se pueden hacer modificaciones a este script sin el permiso por escrito de Levis.

-- Önemli:
-- Hiçbir moda / haritaya eklenemez veya mevcut yayınlanan halinden değiştirilemez.
-- Bu betikte Levis'in yazılı izni olmadan değişiklik yapılamaz.

-- Ważne:
-- Nie może być dodawany do żadnych modów / map ani modyfikowany w swojej obecnej formie.
-- Żadne zmiany nie mogą być dokonywane w tym skrypcie bez pisemnej zgody Levisa.

-- Importante:
-- Non deve essere aggiunto a nessuna mod / mappa né modificato rispetto alla versione attuale.
-- Nessuna modifica può essere apportata a questo script senza il permesso scritto di Levis.

-- Importante:
-- Não deve ser adicionado a nenhum mod / mapa nem modificado em sua versão atual.
-- Nenhuma modificação pode ser feita neste script sem permissão por escrito de Levis.

-- Vigtigt:
-- Må ikke tilføjes til nogen mods / kort eller ændres fra den nuværende udgivelsesform.
-- Ingen ændringer må foretages i dette script uden skriftlig tilladelse fra Levis.

-- Viktig:
-- Skal ikke legges til i noen mods / kart eller endres fra sin nåværende utgivelsesform.
-- Ingen endringer kan gjøres i dette skriptet uten skriftlig tillatelse fra Levis.

-- Viktigt:
-- Får inte läggas till i några mods / kartor eller ändras från sin nuvarande version.
-- Inga ändringar får göras i detta skript utan skriftligt tillstånd från Levis.

-- 重要:
-- このスクリプトは、いかなるModやマップにも追加したり、現在のリリース形態から変更したりすることはできません。
-- Levis の書面による許可なしに、このスクリプトを変更することはできません。

-- Důležité:
-- Nesmí být přidáno do žádných modů / map ani upraveno z aktuální verze.
-- Žádné úpravy tohoto skriptu nejsou povoleny bez písemného souhlasu Levis.
]]

local function infoPrint(text, ...) if LOGGING_ENABLED then print(text, ...) end end infoPrint("DEFUsage: Script loaded") DEFUsage = {} DEFUsage.ModName = "FS25_Lev_DefPack" DEFUsage.ModDirectory = g_modManager.nameToMod.FS25_Lev_DefPack.modDir DEFUsage.Version = "1.0.0.3" DEFUsage.defMultipliers = {0.25, 0.5, 1, 1.5, 2, 3, 4, 5} DEFUsage.MultiplierIndex = 3 DEFUsage.DieselMultiplier = 1 DEFUsage.defBarColor = {0.788, 1.0, 0.329, 1} DEFUsage.ENABLED = true function DEFUsage:onPostLoad(savegame) if not DEFUsage.ENABLED then return false end local spec = self.spec_defUsage or {} local specMotorized = self.spec_motorized if specMotorized == nil then return end local consumerDEF = specMotorized.consumersByFillType[FillType.DEF] if consumerDEF ~= nil then spec.isDefActive = true infoPrint("DEFUsage: DEF consumer detected for vehicle " .. tostring(self:getFullName())) infoPrint("DEFUsage: DEF initial usage rate = " .. tostring(consumerDEF.usage)) else infoPrint("DEFUsage: No DEF consumer found for vehicle " .. tostring(self:getFullName())) end self.spec_defUsage = spec self:initDefUsageHud() end function DEFUsage.prerequisitesPresent(specializations) if not DEFUsage.ENABLED then return false end return SpecializationUtil.hasSpecialization(Motorized, specializations) end function DEFUsage.registerFunctions(vehicleType) if not DEFUsage.ENABLED then return false end SpecializationUtil.registerFunction(vehicleType, "applyDefConsumption", DEFUsage.applyDefConsumption) SpecializationUtil.registerFunction(vehicleType, "applyDieselConsumption", DEFUsage.applyDieselConsumption) SpecializationUtil.registerFunction( vehicleType, "getVehicleDefLevelAndCapacity", DEFUsage.getVehicleDefLevelAndCapacity ) SpecializationUtil.registerFunction(vehicleType, "initDefUsageHud", DEFUsage.initDefUsageHud) SpecializationUtil.registerFunction(vehicleType, "updateDefHud", DEFUsage.updateDefHud) end function DEFUsage.registerEventListeners(vehicleType) if not DEFUsage.ENABLED then return false end SpecializationUtil.registerEventListener(vehicleType, "onPostLoad", DEFUsage) SpecializationUtil.registerEventListener(vehicleType, "onUpdate", DEFUsage) SpecializationUtil.registerEventListener(vehicleType, "onDraw", DEFUsage) SpecializationUtil.registerEventListener(vehicleType, "onDelete", DEFUsage) end function DEFUsage:onUpdate(dt) if not DEFUsage.ENABLED then return false end local specMotorized = self.spec_motorized if specMotorized and specMotorized.motor then if self.spec_defUsage and self.spec_defUsage.isDefActive then self:applyDefConsumption(dt) end self:applyDieselConsumption(dt) end end function DEFUsage:applyDieselConsumption(dt) local specMotorized = self.spec_motorized if specMotorized == nil or specMotorized.motor == nil then return end local dieselConsumer = specMotorized.consumersByFillType[FillType.DIESEL] if dieselConsumer == nil then return end if not self:getIsMotorStarted() then return end local dieselFillUnitIndex = self:getConsumerFillUnitIndex(FillType.DIESEL) if dieselFillUnitIndex == nil then return end local currentDiesel = self:getFillUnitFillLevel(dieselFillUnitIndex) local capacityDiesel = self:getFillUnitCapacity(dieselFillUnitIndex) if capacityDiesel <= 0 then return end local motor = specMotorized.motor local rpmFactor = (motor.lastMotorRpm - motor.minRpm) / (motor.maxRpm - motor.minRpm) local throttleFactor = motor.lastAcceleratorPedal local loadFactor = motor.rawLoadPercentage local baseConsumption = dieselConsumer.usage * dt local adjustedConsumption = baseConsumption * rpmFactor * throttleFactor * loadFactor * DEFUsage.DieselMultiplier adjustedConsumption = math.max(0, adjustedConsumption) if currentDiesel > 0 then self:addFillUnitFillLevel( self:getOwnerFarmId(), dieselFillUnitIndex, -adjustedConsumption, FillType.DIESEL, ToolType.UNDEFINED, nil ) if self.spec_fillUnit then self:raiseDirtyFlags(self.spec_fillUnit.dirtyFlag) end end end function DEFUsage:applyDefConsumption(dt) if not DEFUsage.ENABLED then return false end local specMotorized = self.spec_motorized if specMotorized == nil or specMotorized.motor == nil then return end local consumer = specMotorized.consumersByFillType[FillType.DEF] if consumer == nil then return end if not self:getIsMotorStarted() then return end local defFillUnitIndex = self:getConsumerFillUnitIndex(FillType.DEF) if defFillUnitIndex == nil then return end local currentLevel = self:getFillUnitFillLevel(defFillUnitIndex) local capacity = self:getFillUnitCapacity(defFillUnitIndex) if capacity <= 0 then return end local motor = specMotorized.motor local rpmFactor = (motor.lastMotorRpm - motor.minRpm) / (motor.maxRpm - motor.minRpm) local throttleFactor = motor.lastAcceleratorPedal local loadFactor = motor.rawLoadPercentage local baseConsumption = consumer.usage * dt local multiplier = DEFUsage.defMultipliers[DEFUsage.MultiplierIndex or 4] local adjustedConsumption = baseConsumption * rpmFactor * throttleFactor * loadFactor * multiplier adjustedConsumption = math.max(0, adjustedConsumption) if currentLevel > 0 then self:addFillUnitFillLevel( self:getOwnerFarmId(), defFillUnitIndex, -adjustedConsumption, FillType.DEF, ToolType.UNDEFINED, nil ) if self.spec_fillUnit then self:raiseDirtyFlags(self.spec_fillUnit.dirtyFlag) end end end function DEFUsage:getVehicleDefLevelAndCapacity() local defFillUnitIndex = self:getConsumerFillUnitIndex(FillType.DEF) local level = self:getFillUnitFillLevel(defFillUnitIndex) local capacity = self:getFillUnitCapacity(defFillUnitIndex) return level, capacity end function DEFUsage:onFillUnitFillLevelChanged( superFunc, fillUnitIndex, fillLevelDelta, fillType, toolType, fillPositionData, appliedDelta) return superFunc(self, fillUnitIndex, fillLevelDelta, fillType, toolType, fillPositionData, appliedDelta) end function DEFUsage:onDelete() local spec = self.spec_defUsage if spec then spec.isDefActive = false end end local originalStoreScaledValues = SpeedMeterDisplay.storeScaledValues function SpeedMeterDisplay:storeScaledValues() originalStoreScaledValues(self) if DEFUsage and DEFUsage.config then self.sectionOffsetX = (self.sectionOffsetX or 0) + DEFUsage.config.sectionOffsetXOverride self.sectionOffsetY = (self.sectionOffsetY or 0) + DEFUsage.config.sectionOffsetYOverride self.fuelOffsetX = (self.fuelOffsetX or 0) + DEFUsage.config.fuelOffsetXOverride self.fuelOffsetY = (self.fuelOffsetY or 0) + DEFUsage.config.fuelOffsetYOverride self.fuelBarOffsetX = (self.fuelBarOffsetX or 0) + DEFUsage.config.fuelBarOffsetXOverride self.fuelBarOffsetY = (self.fuelBarOffsetY or 0) + DEFUsage.config.fuelBarOffsetYOverride self.repairOffsetX = (self.repairOffsetX or 0) + DEFUsage.config.repairOffsetXOverride self.repairOffsetY = (self.repairOffsetY or 0) + DEFUsage.config.repairOffsetYOverride self.repairBarOffsetX = (self.repairBarOffsetX or 0) + DEFUsage.config.repairBarOffsetXOverride self.repairBarOffsetY = (self.repairBarOffsetY or 0) + DEFUsage.config.repairBarOffsetYOverride self.gearOffsetX = (self.gearOffsetX or 0) + DEFUsage.config.gearOffsetXOverride self.gearOffsetY = (self.gearOffsetY or 0) + DEFUsage.config.gearOffsetYOverride self.gearIconOffsetX = (self.gearIconOffsetX or 0) + DEFUsage.config.gearIconOffsetXOverride self.gearIconOffsetY = (self.gearIconOffsetY or 0) + DEFUsage.config.gearIconOffsetYOverride end end local originalSpeedMeterDraw = SpeedMeterDisplay.draw function SpeedMeterDisplay:draw() originalSpeedMeterDraw(self) if self.spec_defUsage and self.spec_defUsage.isDefActive and self.updateDefHud then self:updateDefHud() end end DEFUsage.config = { sectionOffsetXOverride = 0.0, sectionOffsetYOverride = 0.0, fuelOffsetXOverride = -0.002, fuelOffsetYOverride = 0.0, fuelBarOffsetXOverride = 0.0, fuelBarOffsetYOverride = 0.0, repairOffsetXOverride = 0.002, repairOffsetYOverride = 0.0, repairBarOffsetXOverride = 0.0, repairBarOffsetYOverride = 0.0, gearOffsetXOverride = 0.0, gearOffsetYOverride = 0.0, gearIconOffsetXOverride = 0.0, gearIconOffsetYOverride = 0.0, defBarXOverride = 0.0, defBarYOverride = 0.0, defIconOffsetXOverride = 0.0, defIconOffsetYOverride = 0.0 } DEFUsage.extraDefOffsetX = -0.003 DEFUsage.extraDefOffsetY = 0.0432 DEFUsage.defIconLiftX = -0.007 DEFUsage.defIconLiftY = 0.136 function DEFUsage:initDefUsageHud() if not DEFUsage.ENABLED then return end if not self.defHudInitialized then local hud = g_currentMission.hud if not hud or not hud.speedMeter then return end local speedMeter = hud.speedMeter local leftWidth, leftHeight = speedMeter:scalePixelValuesToScreenVector(6, 6) leftHeight = leftHeight * 1.1 local totalWidth, _ = speedMeter:scalePixelValuesToScreenVector(130, 0) local barMaxScaleWidth = totalWidth - 2 * leftWidth self.defBar = ThreePartOverlay.new() self.defBar:setLeftPart("gui.progressbar_left", leftWidth, leftHeight) self.defBar:setMiddlePart("gui.progressbar_middle", barMaxScaleWidth, leftHeight) self.defBar:setRightPart("gui.progressbar_right", leftWidth, leftHeight) self.defBar:setRotation(math.rad(90)) local iconWidth, iconHeight = speedMeter:scalePixelValuesToScreenVector(22, 24) local defIconFilename = Utils.getFilename("textures/hud_fill_def.dds", DEFUsage.ModDirectory) self.defIcon = Overlay.new(defIconFilename, 0, 0, iconWidth, iconHeight) self.defHudInitialized = true end end function DEFUsage:updateDefHud() if not DEFUsage.ENABLED then return end local hud = g_currentMission.hud if not hud or not hud.speedMeter then return end local speedMeter = hud.speedMeter local uiScale = 1 if g_gameSettings and g_gameSettings.getValue then uiScale = g_gameSettings:getValue("uiScale") or 1 end local posX, posY = speedMeter:getPosition() local fuelBarOffsetX = (speedMeter.fuelBarOffsetX or 0) + (DEFUsage.config.fuelBarOffsetXOverride or 0) local fuelBarOffsetY = (speedMeter.fuelBarOffsetY or 0) + (DEFUsage.config.fuelBarOffsetYOverride or 0) local fuelBarX = posX + fuelBarOffsetX local fuelBarY = posY + fuelBarOffsetY local baseTotalWidth = 130 local baseEdgeWidth = 6 local baseEdgeHeight = 6 local scaledEdgeWidth, scaledEdgeHeight = speedMeter:scalePixelValuesToScreenVector(baseEdgeWidth, baseEdgeHeight) local scaledTotalWidth, _ = speedMeter:scalePixelValuesToScreenVector(baseTotalWidth, 0) local barMaxWidth = scaledTotalWidth - (2 * scaledEdgeWidth) local totalBarHeight = barMaxWidth + (2 * scaledEdgeHeight) local defBarXOffset = DEFUsage.extraDefOffsetX * uiScale local defBarYOffset = DEFUsage.extraDefOffsetY * uiScale local defBarX = fuelBarX + defBarXOffset local defBarY = fuelBarY + defBarYOffset self.defBar:setLeftPart("gui.progressbar_left", scaledEdgeWidth, scaledEdgeHeight) self.defBar:setMiddlePart("gui.progressbar_middle", barMaxWidth, scaledEdgeHeight) self.defBar:setRightPart("gui.progressbar_right", scaledEdgeWidth, scaledEdgeHeight) self.defBar:setRotation(math.rad(90)) self.defBar:setPosition(defBarX, defBarY) self.defBar:setColor(0, 0, 0, 1) self.defBar:render() local level, capacity = self:getVehicleDefLevelAndCapacity() local defPercentage = (capacity > 0) and (level / capacity) or 1 if defPercentage > 0.1 then self.defBar:setColor(unpack(DEFUsage.defBarColor)) else self.defBar:setColor(unpack(DEFUsage.defBarColor), math.abs(math.cos(g_time / 300))) end local filledWidth = math.clamp(barMaxWidth * defPercentage, 0, barMaxWidth) self.defBar:setMiddlePart(nil, filledWidth, nil) self.defBar:render() local defIconXOffset = DEFUsage.defIconLiftX * uiScale local defIconYOffset = DEFUsage.defIconLiftY * uiScale local baseIconWidth = 22 local baseIconHeight = 24 local iconWidth, iconHeight = speedMeter:scalePixelValuesToScreenVector(baseIconWidth, baseIconHeight) local iconX = defBarX + defIconXOffset local iconY = defBarY + defIconYOffset self.defIcon:setPosition(iconX, iconY) self.defIcon:setDimension(iconWidth, iconHeight) self.defIcon:render() end function DEFUsage:onDraw(isActiveForInput, isActiveForInputIgnoreSelection) if not DEFUsage.ENABLED then return end if self.spec_enterable.isEntered and self.spec_defUsage and self.spec_defUsage.isDefActive then self:updateDefHud() end end function DEFUsage:onFillUnitFillLevelChanged( superFunc, fillUnitIndex, fillLevelDelta, fillType, toolType, fillPositionData, appliedDelta) end Motorized.onFillUnitFillLevelChanged = Utils.overwrittenFunction(Motorized.onFillUnitFillLevelChanged, DEFUsage.onFillUnitFillLevelChanged)
