├── icon_VIPOM.dds ├── FS22_VIPOrderManager_update.zip ├── Screenshots ├── Complete Order.png ├── Abort current Order.png ├── Overview VIP Orders.png └── Controls and current Order.png ├── InfoHUD.lua ├── MyTools.lua ├── gui ├── AvailableTypesDlgFrame.lua ├── AvailableTypesDlgFrame.xml ├── OrderFrame.xml ├── guiProfiles.xml └── OrderFrame.lua ├── VIPOrderManagerDefaults.lua ├── modDesc.xml └── VIPOrderManager.lua /icon_VIPOM.dds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fetty42/FS22_VIPOrderManager/HEAD/icon_VIPOM.dds -------------------------------------------------------------------------------- /FS22_VIPOrderManager_update.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fetty42/FS22_VIPOrderManager/HEAD/FS22_VIPOrderManager_update.zip -------------------------------------------------------------------------------- /Screenshots/Complete Order.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fetty42/FS22_VIPOrderManager/HEAD/Screenshots/Complete Order.png -------------------------------------------------------------------------------- /Screenshots/Abort current Order.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fetty42/FS22_VIPOrderManager/HEAD/Screenshots/Abort current Order.png -------------------------------------------------------------------------------- /Screenshots/Overview VIP Orders.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fetty42/FS22_VIPOrderManager/HEAD/Screenshots/Overview VIP Orders.png -------------------------------------------------------------------------------- /Screenshots/Controls and current Order.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Fetty42/FS22_VIPOrderManager/HEAD/Screenshots/Controls and current Order.png -------------------------------------------------------------------------------- /InfoHUD.lua: -------------------------------------------------------------------------------- 1 | -- Author: Fetty42 2 | -- Date: 20.10.2024 3 | -- Version: 1.4.0.0 4 | 5 | InfoHUD = {} 6 | 7 | local InfoHUD_mt = Class(InfoHUD, HUDElement) 8 | 9 | function InfoHUD.new() 10 | -- print("InfoHUD.new") 11 | local hudAtlasPath = g_baseHUDFilename 12 | -- print("g_baseHUDFilename=" .. tostring(g_baseHUDFilename)) 13 | local backgroundOverlay = InfoHUD.createBackground(hudAtlasPath) 14 | local self = InfoHUD:superClass().new(backgroundOverlay, nil, InfoHUD_mt) 15 | 16 | self:setVisible(false) 17 | 18 | return self 19 | end 20 | 21 | function InfoHUD.createBackground(hudAtlasPath) 22 | -- print("InfoHUD.createBackground") 23 | local width, height = getNormalizedScreenValues(table.unpack(InfoHUD.SIZE.BACKGROUND)) 24 | -- local backgroundOverlay = Overlay.new('dataS/menu/blank.png', 0.5, 0.5, width, height) 25 | local backgroundOverlay = Overlay.new(hudAtlasPath, 0.5, 0.5, width, height) 26 | 27 | backgroundOverlay:setAlignment(Overlay.ALIGN_VERTICAL_TOP, Overlay.ALIGN_HORIZONTAL_LEFT) 28 | backgroundOverlay:setUVs(GuiUtils.getUVs(HUDElement.UV.FILL)) 29 | backgroundOverlay:setColor(table.unpack(InfoHUD.COLOR.FRAME)) 30 | 31 | return backgroundOverlay 32 | end 33 | 34 | function InfoHUD:draw() 35 | -- print("InfoHUD.draw") 36 | InfoHUD:superClass().draw(self) 37 | end 38 | 39 | 40 | InfoHUD.SIZE = { 41 | BACKGROUND = { 42 | 300, 43 | 80 44 | } 45 | } 46 | 47 | InfoHUD.COLOR = { 48 | BAR_BACKGROUND = { 49 | 1, 50 | 1, 51 | 1, 52 | 0.2 53 | }, 54 | FRAME = { 55 | 0, 56 | 0, 57 | 0, 58 | 0.75 59 | } 60 | } -------------------------------------------------------------------------------- /MyTools.lua: -------------------------------------------------------------------------------- 1 | -- ************************************************************************************************ 2 | -- MyTools 3 | -- ************************************************************************************************ 4 | 5 | -- Author: Fetty42 6 | -- Version: 1.0.0.0 7 | 8 | local dbPrintfOn = false 9 | local dbInfoPrintfOn = false 10 | 11 | local function dbInfoPrintf(...) 12 | if dbInfoPrintfOn then 13 | print(string.format(...)) 14 | end 15 | end 16 | 17 | local function dbPrintf(...) 18 | if dbPrintfOn then 19 | print(string.format(...)) 20 | end 21 | end 22 | 23 | 24 | MyTools = {}; -- Class 25 | 26 | 27 | -- global variables 28 | MyTools.dir = g_currentModDirectory 29 | MyTools.modName = g_currentModName 30 | 31 | -- 32 | function MyTools:tableToString(t, separator) 33 | local str = "" 34 | for _, value in pairs(t) do 35 | if str == "" then 36 | str = tostring(value) 37 | else 38 | str = str .. separator .. tostring(value) 39 | end 40 | end 41 | return str 42 | end 43 | 44 | 45 | function MyTools:getCountElements(myTable) 46 | local i = 0 47 | for _, _ in pairs(myTable) do 48 | i = i + 1 49 | end 50 | return i 51 | end 52 | 53 | function MyTools:round(num, numDecimalPlaces) 54 | local mult = 10^(numDecimalPlaces or 0) 55 | return math.floor(num * mult + 0.5) / mult 56 | end 57 | 58 | -- Save copied tables in `copies`, indexed by original table. 59 | -- http://lua-users.org/wiki/CopyTable 60 | function MyTools:deepcopy(orig, copies) 61 | copies = copies or {} 62 | local orig_type = type(orig) 63 | local copy 64 | if orig_type == 'table' then 65 | if copies[orig] then 66 | copy = copies[orig] 67 | else 68 | copy = {} 69 | copies[orig] = copy 70 | for orig_key, orig_value in next, orig, nil do 71 | copy[MyTools:deepcopy(orig_key, copies)] = MyTools:deepcopy(orig_value, copies) 72 | end 73 | setmetatable(copy, MyTools:deepcopy(getmetatable(orig), copies)) 74 | end 75 | else -- number, string, boolean, etc 76 | copy = orig 77 | end 78 | return copy 79 | end 80 | -------------------------------------------------------------------------------- /gui/AvailableTypesDlgFrame.lua: -------------------------------------------------------------------------------- 1 | -- Author: Fetty42 2 | -- Date: 20.10.2024 3 | -- Version: 1.4.0.0 4 | 5 | 6 | local dbPrintfOn = false 7 | 8 | local function dbPrintf(...) 9 | if dbPrintfOn then 10 | print(string.format(...)) 11 | end 12 | end 13 | 14 | 15 | 16 | -- AvailableTypesDlgFrame = { 17 | -- CONTROLS = { 18 | -- DIALOG_TITLE = "dialogTitleElement", 19 | -- TABLE = "overviewTable", 20 | -- TABLE_TEMPLATE = "orderRowTemplate", 21 | -- } 22 | -- } 23 | 24 | AvailableTypesDlgFrame = { 25 | CONTROLS = { 26 | "dialogTitleElement", 27 | "typesTable", 28 | "orderRowTemplate", 29 | } 30 | } 31 | 32 | local AvailableTypesDlgFrame_mt = Class(AvailableTypesDlgFrame, MessageDialog) 33 | 34 | function AvailableTypesDlgFrame.new(target, custom_mt) 35 | dbPrintf("AvailableTypesDlgFrame:new()") 36 | local self = MessageDialog.new(target, custom_mt or AvailableTypesDlgFrame_mt) 37 | 38 | self:registerControls(AvailableTypesDlgFrame.CONTROLS) 39 | 40 | return self 41 | end 42 | 43 | function AvailableTypesDlgFrame:onGuiSetupFinished() 44 | dbPrintf("AvailableTypesDlgFrame:onGuiSetupFinished()") 45 | AvailableTypesDlgFrame:superClass().onGuiSetupFinished(self) 46 | self.typesTable:setDataSource(self) 47 | self.typesTable:setDelegate(self) 48 | end 49 | 50 | function AvailableTypesDlgFrame:onCreate() 51 | dbPrintf("AvailableTypesDlgFrame:onCreate()") 52 | AvailableTypesDlgFrame:superClass().onCreate(self) 53 | end 54 | 55 | 56 | function AvailableTypesDlgFrame:onOpen() 57 | dbPrintf("AvailableTypesDlgFrame:onOpen()") 58 | AvailableTypesDlgFrame:superClass().onOpen(self) 59 | end 60 | 61 | 62 | function AvailableTypesDlgFrame:InitData(data) 63 | dbPrintf("AvailableTypesDlgFrame:InitData()") 64 | 65 | -- Fill data structure 66 | self.tableData = data 67 | 68 | -- finilaze dialog 69 | self.typesTable:reloadData() 70 | 71 | self:setSoundSuppressed(true) 72 | FocusManager:setFocus(self.typesTable) 73 | self:setSoundSuppressed(false) 74 | 75 | end 76 | 77 | 78 | function AvailableTypesDlgFrame:getNumberOfSections(list) 79 | dbPrintf("AvailableTypesDlgFrame:getNumberOfSections()") 80 | return #self.tableData 81 | end 82 | 83 | 84 | function AvailableTypesDlgFrame:getNumberOfItemsInSection(list, section) 85 | dbPrintf("AvailableTypesDlgFrame:getNumberOfItemsInSection()") 86 | return #self.tableData[section].items 87 | end 88 | 89 | 90 | function AvailableTypesDlgFrame:getTitleForSectionHeader(list, section) 91 | dbPrintf("AvailableTypesDlgFrame:getTitleForSectionHeader()") 92 | return self.tableData[section].sectionTitle 93 | end 94 | 95 | 96 | function AvailableTypesDlgFrame:populateCellForItemInSection(list, section, index, cell) 97 | dbPrintf("AvailableTypesDlgFrame:populateCellForItemInSection()") 98 | local item = self.tableData[section].items[index] 99 | cell:getAttribute("ftIcon"):setImageFilename(item.hudOverlayFilename) 100 | cell:getAttribute("ftTitle"):setText(item.title) 101 | cell:getAttribute("minOrderLevel"):setText(item.minOrderLevel) 102 | cell:getAttribute("probability"):setText(string.format("%s %%", item.probability)) 103 | cell:getAttribute("quantityCorrectionFactor"):setText(string.format("%.1f", item.quantityCorrectionFactor)) 104 | cell:getAttribute("msg"):setText(item.msg) 105 | end 106 | 107 | 108 | function AvailableTypesDlgFrame:onClose() 109 | dbPrintf("AvailableTypesDlgFrame:onClose()") 110 | AvailableTypesDlgFrame:superClass().onClose(self) 111 | end 112 | 113 | 114 | function AvailableTypesDlgFrame:onClickClose(sender) 115 | dbPrintf("AvailableTypesDlgFrame:onClickClose()") 116 | self:close() 117 | end 118 | 119 | -------------------------------------------------------------------------------- /gui/AvailableTypesDlgFrame.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /gui/OrderFrame.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | /> 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /gui/guiProfiles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /gui/OrderFrame.lua: -------------------------------------------------------------------------------- 1 | -- Author: Fetty42 2 | -- Date: 20.10.2024 3 | -- Version: 1.4.0.0 4 | 5 | 6 | local dbPrintfOn = false 7 | 8 | local function dbPrintf(...) 9 | if dbPrintfOn then 10 | print(string.format(...)) 11 | end 12 | end 13 | 14 | 15 | 16 | OrderFrame = { 17 | CONTROLS = { 18 | DIALOG_TITLE = "dialogTitleElement", 19 | TABLE = "orderTable", 20 | TABLE_TEMPLATE = "orderRowTemplate", 21 | BUTTON_ABORT = "buttonAbort", 22 | BUTTON_TAG = "buttonTag", 23 | BUTTON_SHOWTYPES = "buttonShowTypes" 24 | } 25 | } 26 | 27 | OrderFrame.availableTypesDlg = nil 28 | source(VIPOrderManager.dir .. "MyTools.lua") 29 | source(VIPOrderManager.dir .. "gui/AvailableTypesDlgFrame.lua") 30 | 31 | 32 | local OrderFrame_mt = Class(OrderFrame, MessageDialog) 33 | 34 | function OrderFrame.new(target, custom_mt) 35 | local self = MessageDialog.new(target, custom_mt or OrderFrame_mt) 36 | 37 | self:registerControls(OrderFrame.CONTROLS) 38 | 39 | return self 40 | end 41 | 42 | function OrderFrame:onGuiSetupFinished() 43 | -- dbPrintf("OrderFrame:onGuiSetupFinished()") 44 | OrderFrame:superClass().onGuiSetupFinished(self) 45 | self.orderTable:setDataSource(self) 46 | self.orderTable:setDelegate(self) 47 | end 48 | 49 | function OrderFrame:onCreate() 50 | -- dbPrintf("OrderFrame:onCreate()") 51 | OrderFrame:superClass().onCreate(self) 52 | end 53 | 54 | 55 | function OrderFrame:onOpen() 56 | -- dbPrintf("OrderFrame:onOpen()") 57 | OrderFrame:superClass().onOpen(self) 58 | FocusManager:setFocus(self.orderTable) 59 | end 60 | 61 | 62 | function OrderFrame:setVIPOrders(VIPOrders) 63 | -- dbPrintf("OrderFrame:setVIPOrders()") 64 | 65 | -- fill table data (title, quantity, fillLevel, payout, targetStationTitle, isCompleted, mapHotspot) 66 | self.VIPOrdersData = {} 67 | 68 | -- hudOverlayFilename :: dataS/menu/hud/fillTypes/hud_fill_grass.png 69 | 70 | -- current VIPOrder 71 | for _, vipOrder in pairs(VIPOrders) do 72 | local VIPOrderData = {title = "No title", orders = {}} 73 | local payoutTotal = 0 74 | for _, vipOrderEntry in pairs(vipOrder.entries) do 75 | local orderEntry = {} 76 | orderEntry.ft = g_fillTypeManager:getFillTypeByName(vipOrderEntry.fillTypeName) 77 | if vipOrderEntry.isAnimal then 78 | orderEntry.fillLevel = string.format("%d %s", math.ceil(vipOrderEntry.fillLevel), g_i18n:getText("VIPOrderManager_Piece")) 79 | orderEntry.quantity = string.format("%d %s", vipOrderEntry.quantity, g_i18n:getText("VIPOrderManager_Piece")) 80 | else 81 | orderEntry.fillLevel = g_i18n:formatVolume(math.ceil(vipOrderEntry.fillLevel), 0) 82 | orderEntry.quantity = g_i18n:formatVolume(vipOrderEntry.quantity, 0) 83 | end 84 | orderEntry.isCompleted = math.ceil(vipOrderEntry.fillLevel) >= vipOrderEntry.quantity 85 | orderEntry.title = vipOrderEntry.title 86 | 87 | orderEntry.mapHotspot = nil 88 | if vipOrderEntry.targetStation ~= nil then 89 | orderEntry.targetStationTitle = vipOrderEntry.targetStation.owningPlaceable:getName() 90 | if vipOrderEntry.targetStation.owningPlaceable.spec_hotspots ~= nil and vipOrderEntry.targetStation.owningPlaceable.spec_hotspots.mapHotspots ~= nil then 91 | 92 | for _, mapHotspot in ipairs(vipOrderEntry.targetStation.owningPlaceable.spec_hotspots.mapHotspots) do 93 | if mapHotspot.worldX ~= nil and mapHotspot.worldZ ~= nil then 94 | orderEntry.mapHotspot = mapHotspot 95 | end 96 | end 97 | end 98 | else 99 | if vipOrderEntry.isAnimal then 100 | orderEntry.targetStationTitle = g_i18n:getText("VIPOrderManager_Automatic") 101 | else 102 | orderEntry.targetStationTitle = g_i18n:getText("VIPOrderManager_FreeChoise") 103 | end 104 | end 105 | 106 | orderEntry.payout = g_i18n:formatMoney(vipOrderEntry.payout, 0, true) -- g_i18n:formatMoney(value, bool Währung ausgeben, bool Währung vor dem Betrag?) 107 | table.insert(VIPOrderData.orders, orderEntry) 108 | payoutTotal = payoutTotal + vipOrderEntry.payout 109 | end 110 | if vipOrder == VIPOrders[1] then 111 | VIPOrderData.title = string.format(g_i18n:getText("ui_orderDlg_section_active"), vipOrder.level, g_i18n:formatMoney(payoutTotal, 0, true)) 112 | else 113 | VIPOrderData.title = string.format(g_i18n:getText("ui_orderDlg_section_notactive"), vipOrder.level, g_i18n:formatMoney(payoutTotal, 0, true)) 114 | end 115 | table.insert(self.VIPOrdersData, VIPOrderData) 116 | end 117 | 118 | self.orderTable:reloadData() 119 | end 120 | 121 | 122 | function OrderFrame:getNumberOfSections() 123 | return #self.VIPOrdersData 124 | end 125 | 126 | 127 | function OrderFrame:getNumberOfItemsInSection(list, section) 128 | return #self.VIPOrdersData[section].orders 129 | end 130 | 131 | 132 | function OrderFrame:getTitleForSectionHeader(list, section) 133 | -- dbPrintf("OrderFrame:getTitleForSectionHeader()") 134 | return self.VIPOrdersData[section].title 135 | end 136 | 137 | 138 | function OrderFrame:populateCellForItemInSection(list, section, index, cell) 139 | local orderEntry = self.VIPOrdersData[section].orders[index] 140 | cell:getAttribute("fillTypeIcon"):setImageFilename(orderEntry.ft.hudOverlayFilename) 141 | cell:getAttribute("ftTitle"):setText(orderEntry.title) 142 | cell:getAttribute("quantity"):setText(orderEntry.quantity) 143 | cell:getAttribute("fillLevel"):setText(orderEntry.fillLevel) 144 | cell:getAttribute("payout"):setText(orderEntry.payout) 145 | cell:getAttribute("targetStationTitle"):setText(orderEntry.targetStationTitle) 146 | 147 | local bold = section == 1 -- only the active order 148 | local color = {1, 1, 1, 1} 149 | local colorSelected = {1, 1, 1, 1} 150 | 151 | dbPrintf("section=%s | index=%s | title=%s | quantity=%s | filllevel=%s", section, index, orderEntry.title, orderEntry.quantity, orderEntry.fillLevel) 152 | if orderEntry.isCompleted then 153 | dbPrintf("order entry completed") 154 | -- color completed order entrys 155 | color = {0.2122, 0.5271, 0.0307, 1} 156 | colorSelected = {0.0781, 0.2233, 0.0478, 1} 157 | end 158 | 159 | cell:getAttribute("ftTitle").textBold = bold 160 | cell:getAttribute("quantity").textBold = bold 161 | cell:getAttribute("fillLevel").textBold = bold 162 | cell:getAttribute("payout").textBold = bold 163 | cell:getAttribute("targetStationTitle").textBold = bold 164 | 165 | cell:getAttribute("ftTitle"):setTextColor(table.unpack(color)) 166 | cell:getAttribute("ftTitle"):setTextSelectedColor(table.unpack(colorSelected)) 167 | cell:getAttribute("quantity").textColor = color 168 | cell:getAttribute("quantity"):setTextSelectedColor(table.unpack(colorSelected)) 169 | cell:getAttribute("fillLevel").textColor = color 170 | cell:getAttribute("fillLevel"):setTextSelectedColor(table.unpack(colorSelected)) 171 | cell:getAttribute("payout").textColor = color 172 | cell:getAttribute("payout"):setTextSelectedColor(table.unpack(colorSelected)) 173 | cell:getAttribute("targetStationTitle").textColor = color 174 | cell:getAttribute("targetStationTitle"):setTextSelectedColor(table.unpack(colorSelected)) 175 | 176 | -- dbPrintf("** Start DebugUtil.printTableRecursively() ************************************************************") 177 | -- DebugUtil.printTableRecursively(cell:getAttribute("targetStationTitle"), ".", 0, 2) 178 | -- dbPrintf("** End DebugUtil.printTableRecursively() **************************************************************\n") 179 | end 180 | 181 | 182 | function OrderFrame:onClose() 183 | -- dbPrintf("OrderFrame:onClose()") 184 | OrderFrame:superClass().onClose(self) 185 | end 186 | 187 | 188 | function OrderFrame:onClickBack(sender) 189 | -- dbPrintf("OrderFrame:onClickBack()") 190 | self:close() 191 | end 192 | 193 | 194 | function OrderFrame:onClickAbort() 195 | -- dbPrintf("OrderFrame:onClickAbort()") 196 | VIPOrderManager:AbortCurrentVIPOrder() 197 | end 198 | 199 | 200 | function OrderFrame:onListSelectionChanged(list, section, index) 201 | local orderEntry = self.VIPOrdersData[section].orders[index] 202 | 203 | self.mapHotspot = orderEntry.mapHotspot 204 | if self.mapHotspot ~= nil then 205 | self.buttonTag.disabled = false 206 | if self.mapHotspot == g_currentMission.currentMapTargetHotspot then 207 | self.buttonTag.text = string.upper(g_i18n:getText("ui_orderDlg_btnUntagSellPoint")) 208 | else 209 | self.buttonTag.text = string.upper(g_i18n:getText("ui_orderDlg_btnTagSellPoint")) 210 | end 211 | else 212 | self.buttonTag.disabled = true 213 | end 214 | end 215 | 216 | 217 | function OrderFrame:onTagLocation(m) 218 | if self.mapHotspot ~= nil then 219 | if self.mapHotspot == g_currentMission.currentMapTargetHotspot then 220 | self.buttonTag.text = string.upper(g_i18n:getText("ui_orderDlg_btnTagSellPoint")) 221 | g_currentMission:setMapTargetHotspot() 222 | else 223 | self.buttonTag.text = string.upper(g_i18n:getText("ui_orderDlg_btnUntagSellPoint")) 224 | g_currentMission:setMapTargetHotspot(self.mapHotspot) 225 | end 226 | end 227 | end 228 | 229 | 230 | function OrderFrame:onShowAvailableTypes(m) 231 | dbPrintf("OrderFrame:onShowAvailableTypes()") 232 | 233 | -- fill table 234 | local data = {} 235 | 236 | local groupNameSections = {} 237 | 238 | local sectionNotUseable = {} 239 | sectionNotUseable.sectionTitle = g_i18n:getText("ui_AvailableTypesDlg_sectionTitle_notUseable") 240 | sectionNotUseable.sectionOrder = 99 241 | sectionNotUseable.items = {} 242 | table.insert(data, sectionNotUseable) 243 | 244 | -- create table for groupName --> idx searching 245 | local groupNameSettingsByGroupNameToIdx = {} 246 | for idx, gns in pairs(VIPOrderManager.groupNameSettings) do 247 | groupNameSettingsByGroupNameToIdx[gns.groupName] = idx 248 | end 249 | 250 | local relevantFillTypes = {}; 251 | VIPOrderManager:GetRelevantFillTypes(relevantFillTypes) 252 | for index, ft in pairs(relevantFillTypes) do 253 | local ftConfig = ft.ftConfig 254 | 255 | local item = {} 256 | item.title = string.format("%s (%s)", ft.title, ft.name) 257 | item.hudOverlayFilename = g_fillTypeManager:getFillTypeByName(ft.name).hudOverlayFilename 258 | item.minOrderLevel = ftConfig.minOrderLevel 259 | item.probability = ftConfig.probability 260 | item.quantityCorrectionFactor = ft.ftConfig.quantityCorrectionFactor 261 | item.sortAttribut = Utils.getNoNil(ft.animalTypeName, "") 262 | 263 | -- item.acceptingStationsString = ft.acceptingStationsString 264 | 265 | if ft.isUsable ~= nil and not ft.isUsable then 266 | item.msg = ft.notUsableMsg 267 | table.insert(sectionNotUseable.items, item) 268 | else 269 | item.msg = MyTools:tableToString(ftConfig.msg, "; ") 270 | 271 | -- add food consumtion for animals 272 | -- if ft.isAnimal then 273 | -- local strFoodConsumption = VIPOrderManager:GetAnimalFoodConsumptionPerMonthStringByFillTypeIdx(g_fillTypeManager:getFillTypeIndexByName(ft.name)) 274 | -- item.msg = item.msg .. "; " .. strFoodConsumption 275 | -- end 276 | 277 | 278 | if groupNameSections[ftConfig.groupName] == nil then 279 | local newSection = {} 280 | newSection.sectionTitle = g_i18n:getText("ui_AvailableTypesDlg_sectionTitle_" .. ftConfig.groupName) 281 | newSection.sectionOrder = groupNameSettingsByGroupNameToIdx[ftConfig.groupName] 282 | if newSection.sectionTitle == nil or newSection.sectionTitle == "" or string.find(newSection.sectionTitle, "Missing '") then -- "Missing 'ui_AvailableTypesDlg_sectionTitle_fruit' in l10n_de.xml" 283 | newSection.sectionTitle = "** " .. ftConfig.groupName .. " **" 284 | end 285 | 286 | newSection.items = {} 287 | table.insert(data, newSection) 288 | groupNameSections[ftConfig.groupName] = newSection 289 | end 290 | 291 | table.insert(groupNameSections[ftConfig.groupName].items, item) 292 | end 293 | end 294 | 295 | -- order section items 296 | -- table.sort(sectionAnimal.items, function(a,b) return a.title < b.title end) 297 | table.sort(sectionNotUseable.items, CompItem) 298 | 299 | for index, section in pairs(groupNameSections) do 300 | table.sort(section.items, CompItem) 301 | end 302 | 303 | -- order sections 304 | table.sort(data, CompSection) 305 | 306 | -- create and show dialog 307 | OrderFrame.availableTypesDlg = nil 308 | local modDir = VIPOrderManager.dir 309 | g_gui:loadProfiles(modDir .. "gui/guiProfiles.xml") 310 | local availableTypesDlgFrame = AvailableTypesDlgFrame.new(g_i18n) 311 | g_gui:loadGui(modDir .. "gui/AvailableTypesDlgFrame.xml", "AvailableTypesDlgFrame", availableTypesDlgFrame) 312 | OrderFrame.availableTypesDlg = g_gui:showDialog("AvailableTypesDlgFrame") 313 | 314 | if OrderFrame.availableTypesDlg ~= nil then 315 | OrderFrame.availableTypesDlg.target:InitData(data) 316 | end 317 | dbPrintf("OrderFrame:onShowAvailableTypes() --> End function") 318 | end 319 | 320 | function CompItem(a,b) 321 | -- if a.minOrderLevel ~= b.minOrderLevel then 322 | -- return a.minOrderLevel < b.minOrderLevel 323 | if a.probability ~= b.probability then 324 | return a.probability > b.probability 325 | else 326 | return a.sortAttribut .. a.title < b.sortAttribut .. b.title 327 | end 328 | end 329 | 330 | function CompSection(a,b) 331 | return a.sectionOrder < b.sectionOrder 332 | end -------------------------------------------------------------------------------- /VIPOrderManagerDefaults.lua: -------------------------------------------------------------------------------- 1 | -- Author: Fetty42 2 | -- Date: 20.10.2024 3 | -- Version: 1.4.0.0 4 | 5 | VIPOrderManager.isAnimalOrdersWished= true 6 | 7 | -- orders definition for order level 1 and own field area of 1 ha 8 | VIPOrderManager.countOrderItemsRange = {min=3, max=5} 9 | VIPOrderManager.quantityFactor = {min=6, max=6} 10 | -- VIPOrderManager.quantityFactor = {min=5, max=7} 11 | VIPOrderManager.payoutFactor = {min=4, max=6} 12 | 13 | -- Depending on the OrderLeven, special correction factors for count, quantity and payout 14 | VIPOrderManager.orderLevelCorrectionFactors = {} 15 | VIPOrderManager.orderLevelCorrectionFactors[1] = {0.40, 0.60, 1.00} 16 | VIPOrderManager.orderLevelCorrectionFactors[2] = {0.65, 0.80, 1.00} 17 | VIPOrderManager.orderLevelCorrectionFactors[3] = {0.90, 1.00, 1.00} 18 | 19 | 20 | -- Constants for filltype selection 21 | VIPOrderManager.fillTypesNoPriceList = {} 22 | VIPOrderManager.acceptOwnPlaceableProductionPointsAsSellingStation = true -- accept own placeable production points if fill types is not also loadable at the same time 23 | 24 | 25 | -- constants 26 | VIPOrderManager.maxVIPOrdersCount = 4 -- Count of already calculated orders (preview) 27 | VIPOrderManager.abortFeeInPercent = 35 28 | VIPOrderManager.allowSumQuantitySameFT = false -- Summarize quantity of same filetypes 29 | VIPOrderManager.ownFieldArea = 1 -- min field area 30 | VIPOrderManager.rangeAnimalAgeDifInMonths = {min=6, max=12} 31 | VIPOrderManager.rangeAnimalDummyPrice = {min=500, max=800} 32 | 33 | VIPOrderManager.limitedGroupsPercent = {} -- Max share of limited groups 34 | -- VIPOrderManager.limitedGroupsPercent["animal"] = 50 35 | -- VIPOrderManager.limitedGroupsPercent["production"] = 30 36 | 37 | VIPOrderManager.numPrioTrysForGroup = 100 38 | 39 | VIPOrderManager.groupNameSettings = {} 40 | table.insert(VIPOrderManager.groupNameSettings, {groupName="basic crop", sectionOrder=1, probability=55}) 41 | table.insert(VIPOrderManager.groupNameSettings, {groupName="windrowed, silaged, chopped", sectionOrder=2, probability=25}) 42 | table.insert(VIPOrderManager.groupNameSettings, {groupName="animal", sectionOrder=3, probability=65}) 43 | table.insert(VIPOrderManager.groupNameSettings, {groupName="production easy", sectionOrder=4, probability=25}) 44 | table.insert(VIPOrderManager.groupNameSettings, {groupName="production", sectionOrder=5, probability=20}) 45 | 46 | 47 | -- overwrite group name which comes from the ftConfig defaults 48 | VIPOrderManager.defaultGroupNameOverwriting = {} 49 | VIPOrderManager.defaultGroupNameOverwriting["GOATMILK"] = "production easy" 50 | VIPOrderManager.defaultGroupNameOverwriting["FORAGE"] = "production easy" 51 | 52 | 53 | -- groupName="" 54 | -- isAllowed (true, false) - whether the fill type is offered 55 | -- minOrderLevel {(1-n)(, (1-n), (1-n))} - from which level the fill type is offered (1:default, 2:existing, 3:self owned) 56 | -- quantityCorrectionFactor (> 0) - Factor for the correction of the quantity calculation 57 | -- probability {(1-n)(, (1-n), (1-n))} - The probability with which this filltype is taken when selected. (1:default, 2:existing, 3:sef owned) 58 | VIPOrderManager.ftConfigs = 59 | { 60 | -- Not Allowed 61 | STONE = {isAllowed=false, minOrderLevel={1}, quantityCorrectionFactor=1.0, probability={0}}, -- Steine 62 | ROUNDBALE = {isAllowed=false, minOrderLevel={1}, quantityCorrectionFactor=1.0, probability={0}}, -- Rundballen 63 | ROUNDBALE_WOOD = {isAllowed=false, minOrderLevel={1}, quantityCorrectionFactor=1.0, probability={0}}, -- RundballenHolz 64 | SQUAREBALE = {isAllowed=false, minOrderLevel={1}, quantityCorrectionFactor=1.0, probability={0}}, -- Quaderballen 65 | WATER = {isAllowed=false, minOrderLevel={1}, quantityCorrectionFactor=1.0, probability={0}}, -- Wasser 66 | LIME = {isAllowed=false, minOrderLevel={1}, quantityCorrectionFactor=1.0, probability={0}}, -- Kalk 67 | SOYBEANSTRAW = {isAllowed=false, minOrderLevel={1}, quantityCorrectionFactor=1.0, probability={0}}, -- Sojabohnen Stroh 68 | EMPTYPALLET = {isAllowed=false, minOrderLevel={1}, quantityCorrectionFactor=1.0, probability={0}}, -- leere Paletten 69 | 70 | -- defaults 71 | DEFAULT_FRUITTYPE = {groupName="basic crop", isUnknown=true, isAllowed=true, minOrderLevel={3}, quantityCorrectionFactor=0.5, probability={30}}, -- for unknown fruittypes 72 | DEFAULT_FILLTYPE = {groupName="production", isUnknown=true, isAllowed=true, minOrderLevel={5,4,2}, quantityCorrectionFactor=1.0, probability={2, 5, 15}}, -- for unknown filltypes (booster possible) 73 | DEFAULT_ANIMALTYPE = {groupName="animal", isUnknown=true, isAllowed=true, minOrderLevel={4,3,2}, quantityCorrectionFactor=2.0, probability={40, 60, 70}}, -- for unknown animals (booster possible) 74 | 75 | -- standard animals (booster possible) 76 | ANIMALTYPE_CHICKEN = {groupName="animal", isAllowed=true, minOrderLevel={2,1,1}, quantityCorrectionFactor=3.0, probability={30, 40, 50}, quantityCorrectionFactorMaizePlus=1.5}, 77 | ANIMALTYPE_SHEEP = {groupName="animal", isAllowed=true, minOrderLevel={3,2,1}, quantityCorrectionFactor=3.5, probability={30, 35, 50}, quantityCorrectionFactorMaizePlus=1.5}, 78 | ANIMALTYPE_COW = {groupName="animal", isAllowed=true, minOrderLevel={4,3,2}, quantityCorrectionFactor=2.0, probability={20, 30, 50}, quantityCorrectionFactorMaizePlus=1.0}, 79 | ANIMALTYPE_PIG = {groupName="animal", isAllowed=true, minOrderLevel={4,3,2}, quantityCorrectionFactor=5.0, probability={20, 30, 50}, quantityCorrectionFactorMaizePlus=2.5}, 80 | ANIMALTYPE_HORSE = {groupName="animal", isAllowed=true, minOrderLevel={4,3,2}, quantityCorrectionFactor=0.7, probability={20, 30, 50}, quantityCorrectionFactorMaizePlus=0.7}, 81 | 82 | -- other animals (booster possible) 83 | ANIMALTYPE_BULL = {groupName="animal", isAllowed=true, minOrderLevel={4,3,2}, quantityCorrectionFactor=0.4, probability={5, 7, 20}}, -- Hof Bergmann 84 | ANIMALTYPE_CAT = {groupName="animal", isAllowed=true, minOrderLevel={4,3,2}, quantityCorrectionFactor=0.2, probability={5, 7, 10}}, -- Hof Bergmann 85 | ANIMALTYPE_RABBIT = {groupName="animal", isAllowed=true, minOrderLevel={4,3,2}, quantityCorrectionFactor=1.0, probability={10, 15, 30}}, -- Hof Bergmann 86 | ANIMALTYPE_PULLET = {groupName="animal", isAllowed=true, minOrderLevel={4,3,2}, quantityCorrectionFactor=2.0, probability={20, 30, 50}}, -- Hof Bergmann 87 | ANIMALTYPE_GOAT = {groupName="animal", isAllowed=true, minOrderLevel={3,2,1}, quantityCorrectionFactor=2.0, probability={30, 35, 50}, quantityCorrectionFactorMaizePlus=1.5}, -- TerraLifePlus 88 | 89 | -- Animal products (booster possible) 90 | HONEY = {groupName="production easy", isAllowed=true, minOrderLevel={2}, quantityCorrectionFactor=0.3, probability={25}}, -- Honig 91 | EGG = {groupName="production easy", isAllowed=true, minOrderLevel={2,1,1}, quantityCorrectionFactor=0.7, probability={15, 20, 25}}, -- Eier 92 | WOOL = {groupName="production easy", isAllowed=true, minOrderLevel={3,2,1}, quantityCorrectionFactor=0.7, probability={15, 17, 25}}, -- Wolle 93 | MILK = {groupName="production easy", isAllowed=true, minOrderLevel={4,3,2}, quantityCorrectionFactor=1.0, probability={10, 15, 25}}, -- Milch 94 | GOATMILK = {groupName="production easy", isAllowed=true, minOrderLevel={4,3,2}, quantityCorrectionFactor=1.0, probability={10, 15, 25}}, -- Ziegenmilch 95 | LIQUIDMANURE = {groupName="production easy", isAllowed=true, minOrderLevel={4,3,2}, quantityCorrectionFactor=0.1, probability={10, 15, 25}}, -- Gülle 96 | MANURE = {groupName="production easy", isAllowed=true, minOrderLevel={4,3,2}, quantityCorrectionFactor=0.1, probability={10, 15, 25}}, -- Mist 97 | 98 | -- Basic crops (incl. Premium Expansion) 99 | BARLEY = {groupName="basic crop", isAllowed=true, minOrderLevel={1}, quantityCorrectionFactor=1.0, probability={30}}, -- Gerste 100 | WHEAT = {groupName="basic crop", isAllowed=true, minOrderLevel={1}, quantityCorrectionFactor=1.0, probability={30}}, -- Weizen 101 | OAT = {groupName="basic crop", isAllowed=true, minOrderLevel={1}, quantityCorrectionFactor=1.0, probability={30}}, -- Hafer 102 | CANOLA = {groupName="basic crop", isAllowed=true, minOrderLevel={1}, quantityCorrectionFactor=1.0, probability={30}}, -- Raps 103 | SORGHUM = {groupName="basic crop", isAllowed=true, minOrderLevel={1}, quantityCorrectionFactor=1.0, probability={30}}, -- Sorghumhirse 104 | SOYBEAN = {groupName="basic crop", isAllowed=true, minOrderLevel={1}, quantityCorrectionFactor=1.0, probability={30}}, -- Sojabohnen 105 | SUNFLOWER = {groupName="basic crop", isAllowed=true, minOrderLevel={2}, quantityCorrectionFactor=1.0, probability={30}}, -- Sonnenblumen 106 | MAIZE = {groupName="basic crop", isAllowed=true, minOrderLevel={2}, quantityCorrectionFactor=1.0, probability={30}}, -- Mais 107 | SUGARBEET = {groupName="basic crop", isAllowed=true, minOrderLevel={3}, quantityCorrectionFactor=1.0, probability={30}}, -- Zuckerrüben 108 | POTATO = {groupName="basic crop", isAllowed=true, minOrderLevel={3}, quantityCorrectionFactor=1.0, probability={30}}, -- Kartoffeln 109 | OLIVE = {groupName="basic crop", isAllowed=true, minOrderLevel={4}, quantityCorrectionFactor=1.0, probability={30}}, -- Oliven 110 | GRAPE = {groupName="basic crop", isAllowed=true, minOrderLevel={4}, quantityCorrectionFactor=1.0, probability={30}}, -- Trauben 111 | COTTON = {groupName="basic crop", isAllowed=true, minOrderLevel={5}, quantityCorrectionFactor=1.0, probability={30}}, -- Baumwolle 112 | SUGARCANE = {groupName="basic crop", isAllowed=true, minOrderLevel={5}, quantityCorrectionFactor=1.0, probability={30}}, -- Zuckerrohr 113 | PARSNIP = {groupName="basic crop", isAllowed=true, minOrderLevel={3}, quantityCorrectionFactor=0.6, probability={30}, neededFruittype="PARSNIP"}, -- Premium Expansion 114 | BEETROOT = {groupName="basic crop", isAllowed=true, minOrderLevel={3}, quantityCorrectionFactor=0.6, probability={30}, neededFruittype="BEETROOT"}, -- Premium Expansion 115 | CARROT = {groupName="basic crop", isAllowed=true, minOrderLevel={3}, quantityCorrectionFactor=0.6, probability={30}, neededFruittype="CARROT"}, -- Premium Expansion 116 | 117 | -- Tree products 118 | WOOD = {groupName="production easy", isAllowed=true, minOrderLevel={2}, quantityCorrectionFactor=2.0, probability={30}}, -- Holz 119 | WOODCHIPS = {groupName="production easy", isAllowed=true, minOrderLevel={2}, quantityCorrectionFactor=0.8, probability={30}}, -- Hackschnitzel 120 | 121 | -- Greenhouse products (booster possible) 122 | STRAWBERRY = {groupName="production easy", isAllowed=true, minOrderLevel={3,2,1}, quantityCorrectionFactor=0.8, probability={15, 20, 30}}, -- Erdbeeren 123 | TOMATO = {groupName="production easy", isAllowed=true, minOrderLevel={3,2,1}, quantityCorrectionFactor=0.8, probability={15, 20, 30}}, -- Tomaten 124 | LETTUCE = {groupName="production easy", isAllowed=true, minOrderLevel={3,2,1}, quantityCorrectionFactor=0.8, probability={15, 20, 30}}, -- Salat 125 | 126 | -- Factory products 127 | SEEDS = {groupName="production easy", isAllowed=true, minOrderLevel={3}, quantityCorrectionFactor=1.0, probability={0, 20, 20}}, -- Samen 128 | DIESEL = {groupName="production easy", isAllowed=true, minOrderLevel={3}, quantityCorrectionFactor=1.0, probability={0, 20, 20}}, -- Diesel 129 | FORAGE = {groupName="production easy", isAllowed=true, minOrderLevel={2}, quantityCorrectionFactor=1.0, probability={20}}, 130 | SUGARBEET_CUT = {groupName="production easy", isAllowed=true, minOrderLevel={4}, quantityCorrectionFactor=0.4, probability={20}}, -- Zuckerrübenschnitzel 131 | POTATO_CUT = {groupName="production easy", isAllowed=true, minOrderLevel={4}, quantityCorrectionFactor=0.4, probability={20}}, 132 | 133 | -- Straw, grass and chaff 134 | STRAW = {groupName="windrowed, silaged, chopped", isAllowed=true, minOrderLevel={2}, quantityCorrectionFactor=0.4, probability={20}}, -- Stroh 135 | GRASS_WINDROW = {groupName="windrowed, silaged, chopped", isAllowed=true, minOrderLevel={2}, quantityCorrectionFactor=0.4, probability={20}}, -- Gras 136 | DRYGRASS_WINDROW = {groupName="windrowed, silaged, chopped", isAllowed=true, minOrderLevel={2}, quantityCorrectionFactor=0.4, probability={20}}, -- Heu 137 | SILAGE = {groupName="windrowed, silaged, chopped", isAllowed=true, minOrderLevel={2}, quantityCorrectionFactor=0.5, probability={30}, probabilityMaizePlus=20, quantityCorrectionFactorMaizePlus=0.3}, -- Silage 138 | CHAFF = {groupName="windrowed, silaged, chopped", isAllowed=true, minOrderLevel={2}, quantityCorrectionFactor=0.4, probability={30}, probabilityMaizePlus=20, quantityCorrectionFactorMaizePlus=0.3}, -- Häckselgut 139 | 140 | -- MaizePlus 141 | GRASS_FERMENTED = {groupName="windrowed, silaged, chopped", isAllowed=true, minOrderLevel={3}, quantityCorrectionFactor=0.4, probability={20}}, 142 | CHOPPEDMAIZE = {groupName="windrowed, silaged, chopped", isAllowed=true, minOrderLevel={3}, quantityCorrectionFactor=0.7, probability={30}}, 143 | CHOPPEDMAIZE_FERMENTED = {groupName="windrowed, silaged, chopped", isAllowed=true, minOrderLevel={3}, quantityCorrectionFactor=0.7, probability={30}}, 144 | CCM = {groupName="production easy", isAllowed=true, minOrderLevel={3}, quantityCorrectionFactor=0.4, probability={20}}, 145 | CCMRAW = {groupName="production easy", isAllowed=true, minOrderLevel={3}, quantityCorrectionFactor=0.4, probability={20}}, 146 | GRAINGRIST = {groupName="production easy", isAllowed=true, minOrderLevel={3}, quantityCorrectionFactor=0.4, probability={20}}, 147 | 148 | -- TerraLifePlus 149 | WINTERWHEAT = {groupName="basic crop", isAllowed=true, minOrderLevel={1}, quantityCorrectionFactor=1.0, probability={30}}, 150 | WINTERBARLEY = {groupName="basic crop", isAllowed=true, minOrderLevel={1}, quantityCorrectionFactor=1.0, probability={30}}, 151 | TRITICALE = {groupName="basic crop", isAllowed=true, minOrderLevel={1}, quantityCorrectionFactor=1.0, probability={30}}, 152 | SPELT = {groupName="basic crop", isAllowed=true, minOrderLevel={1}, quantityCorrectionFactor=1.0, probability={30}}, 153 | RYE = {groupName="basic crop", isAllowed=true, minOrderLevel={1}, quantityCorrectionFactor=1.0, probability={30}}, 154 | VETCHRYE = {groupName="basic crop", isAllowed=true, minOrderLevel={1}, quantityCorrectionFactor=1.0, probability={30}}, 155 | MUSTARD = {groupName="basic crop", isAllowed=true, minOrderLevel={1}, quantityCorrectionFactor=1.0, probability={30}}, 156 | LINSEED = {groupName="basic crop", isAllowed=true, minOrderLevel={1}, quantityCorrectionFactor=1.0, probability={30}}, 157 | SILAGEMAIZE = {groupName="basic crop", isAllowed=true, minOrderLevel={2}, quantityCorrectionFactor=1.0, probability={30}}, 158 | SILAGESORGHUM = {groupName="basic crop", isAllowed=true, minOrderLevel={2}, quantityCorrectionFactor=1.0, probability={30}}, 159 | STARCHPOTATO = {groupName="basic crop", isAllowed=true, minOrderLevel={3}, quantityCorrectionFactor=1.0, probability={30}}, 160 | FODDERBEET = {groupName="basic crop", isAllowed=true, minOrderLevel={3}, quantityCorrectionFactor=1.0, probability={30}}, 161 | FODDERCARROT = {groupName="basic crop", isAllowed=true, minOrderLevel={3}, quantityCorrectionFactor=0.6, probability={30}}, 162 | ONION = {groupName="basic crop", isAllowed=true, minOrderLevel={3}, quantityCorrectionFactor=0.6, probability={30}}, 163 | 164 | 165 | -- MaizePlus - only allowed if fruittype exists 166 | -- CARROT = {isAllowed=true, minOrderLevel=3, quantityCorrectionFactor=0.4, probability=70, neededFruittype="CARROT"}, 167 | CLOVER_WINDROW = {groupName="windrowed, silaged, chopped", isAllowed=true, minOrderLevel={2}, quantityCorrectionFactor=0.4, probability={20}, neededFruittype="CLOVER"}, 168 | DRYCLOVER_WINDROW = {groupName="windrowed, silaged, chopped", isAllowed=true, minOrderLevel={3}, quantityCorrectionFactor=0.4, probability={20}, neededFruittype="CLOVER"}, 169 | CLOVER_FERMENTED = {groupName="windrowed, silaged, chopped", isAllowed=true, minOrderLevel={3}, quantityCorrectionFactor=0.4, probability={20}, neededFruittype="CLOVER"}, 170 | ALFALFA_WINDROW = {groupName="windrowed, silaged, chopped", isAllowed=true, minOrderLevel={2}, quantityCorrectionFactor=0.4, probability={20}, neededFruittype="ALFALFA"}, 171 | DRYALFALFA_WINDROW = {groupName="windrowed, silaged, chopped", isAllowed=true, minOrderLevel={3}, quantityCorrectionFactor=0.4, probability={20}, neededFruittype="ALFALFA"}, 172 | ALFALFA_FERMENTED = {groupName="windrowed, silaged, chopped", isAllowed=true, minOrderLevel={3}, quantityCorrectionFactor=0.4, probability={20}, neededFruittype="ALFALFA"}, 173 | DRYHORSEGRASS_WINDROW = {groupName="windrowed, silaged, chopped", isAllowed=true, minOrderLevel={3}, quantityCorrectionFactor=0.4, probability={20}, neededFruittype="HORSEGRASS"}, 174 | HORSEGRASS_FERMENTED = {groupName="windrowed, silaged, chopped", isAllowed=true, minOrderLevel={3}, quantityCorrectionFactor=0.4, probability={20}, neededFruittype="HORSEGRASS"}, 175 | 176 | -- other new Filltypes 177 | LUCERNE_WINDROW = {groupName="windrowed, silaged, chopped", isAllowed=true, minOrderLevel={2}, quantityCorrectionFactor=0.4, probability={20}, neededFruittype="LUCERNE"}, 178 | DRYLUCERNE_WINDROW = {groupName="windrowed, silaged, chopped", isAllowed=true, minOrderLevel={3}, quantityCorrectionFactor=0.4, probability={20}, neededFruittype="LUCERNE"}, 179 | 180 | -- MaizePlus - not allowed because is only buyable 181 | CROP_WINDROW = {isAllowed=false, minOrderLevel={3}, quantityCorrectionFactor=0.4, probability={0}}, 182 | WETGRASS_WINDROW = {isAllowed=false, minOrderLevel={3}, quantityCorrectionFactor=0.4, probability={0}}, 183 | SEMIDRYGRASS_WINDROW = {isAllowed=false, minOrderLevel={3}, quantityCorrectionFactor=0.4, probability={0}}, 184 | BREWERSGRAIN = {isAllowed=false, minOrderLevel={3}, quantityCorrectionFactor=0.4, probability={0}}, 185 | BREWERSGRAIN_FERMENTED = {isAllowed=false, minOrderLevel={3}, quantityCorrectionFactor=0.4, probability={0}}, 186 | BEETPULP = {isAllowed=false, minOrderLevel={3}, quantityCorrectionFactor=0.4, probability={0}}, 187 | BEETPULP_FERMENTED = {isAllowed=false, minOrderLevel={3}, quantityCorrectionFactor=0.4, probability={0}}, 188 | MOLASSES = {isAllowed=false, minOrderLevel={3}, quantityCorrectionFactor=0.4, probability={0}}, 189 | CLEAREDWATER = {isAllowed=false, minOrderLevel={3}, quantityCorrectionFactor=0.4, probability={0}}, 190 | HAYPELLETS = {isAllowed=false, minOrderLevel={3}, quantityCorrectionFactor=0.4, probability={0}}, 191 | CHICKENFOOD = {isAllowed=false, minOrderLevel={3}, quantityCorrectionFactor=0.4, probability={0}}, 192 | FEEDPELLETS = {isAllowed=false, minOrderLevel={3}, quantityCorrectionFactor=0.4, probability={0}}, 193 | HORSEFOOD = {isAllowed=false, minOrderLevel={3}, quantityCorrectionFactor=0.4, probability={0}}, 194 | MINERALS = {isAllowed=false, minOrderLevel={3}, quantityCorrectionFactor=0.4, probability={0}}, 195 | PIGFOOD2 = {isAllowed=false, minOrderLevel={3}, quantityCorrectionFactor=0.4, probability={0}}, 196 | POWERFOOD = {isAllowed=false, minOrderLevel={3}, quantityCorrectionFactor=0.4, probability={0}}, 197 | SHEEPFOOD = {isAllowed=false, minOrderLevel={3}, quantityCorrectionFactor=0.4, probability={0}} 198 | } -------------------------------------------------------------------------------- /modDesc.xml: -------------------------------------------------------------------------------- 1 | 2 | Fetty42 3 | 1.4.0.0 4 | 5 | <en>VIP Order Manager</en> 6 | <de>VIP Auftrags Manager</de> 7 | <fr>Gestionnaire De Commandes VIP</fr> 8 | <ru>Менеджер VIP-заказов</ru> 9 | 10 | 11 | true" durch "false" ersetzen. Ist dann aber nur für diesen Spielstand deaktiviert. 47 | 48 | Update 1.3.1 49 | - Korrektur der nicht sichtbaren Spaltenüberschriften 50 | - kleinere Anpassungen an der Konfiguration 51 | 52 | Update 1.3.0 53 | - Ein Zielstandort kann jetzt markiert werden (Hotspot) 54 | - Tieraufträge werden jetzt unterstützt (Verkauf erfolgt um 8 Uhr morgens automatisch, wenn das angeforderte Alter erreicht ist; Gesundheit der Tiere muss bei mindestens 75% liegen) 55 | - Französische Übersetzung vervollständigt (Danke an BOB51160) 56 | 57 | Update 1.2.0 58 | - Unterstützung für MaizePlus 59 | - Wahrscheinlichkeiten für die Verwendung von jeweiligen Fülltypen 60 | - Übersetzung ins Russische (Dank an Gonimy-Vetrom) 61 | 62 | Update 1.1.1 63 | - Probleme mit eigenen Verkaufsstationen und Produktionen behoben 64 | 65 | Update 1.1.0 66 | - Berücksichtigung von bereits eigenen Tierhaltungen und Produktionen 67 | - erste kleine Multiplayer-Anpassungen (noch nicht multiplayerkompatibel)]]> 68 | 69 | true" with "false". Is then but only deactivated for this savegame 105 | 106 | Translated with www.DeepL.com/Translator (free version) 107 | Update 1.3.1 108 | - Correction of the invisible column headers 109 | - Minor adjustments to the configuration 110 | 111 | Update 1.3.0 112 | - A target location can now be marked (hotspot) 113 | - Animal orders are now supported (sale takes place automatically at 8 a.m. when the requested age is reached; health of the animals must be at least 75%) 114 | - French translation completed (thanks to BOB51160) 115 | 116 | Update 1.2.0 117 | - Support for MaizePlus 118 | - Probabilities for the use of specific fill types 119 | - Translation into Russian (thanks to Gonimy-Vetrom) 120 | 121 | Update 1.1.1 122 | - Fixed problems with own selling stations and productions 123 | 124 | Update 1.1.0 125 | - Consideration of already own animal husbandries and productions 126 | - first smal multiplayer adjustments (not yet multiplayer compatible)]]> 127 | 128 | true" par "false" à la 5e ligne. Mais cela ne sera désactivé que pour cette sauvegarde 164 | 165 | Update 1.3.1 166 | - correction des en-têtes de colonnes non visibles 167 | - ajustements mineurs de la configuration 168 | 169 | Update 1.3.0 170 | - Il est désormais possible de marquer un site cible (hotspot) 171 | - Les commandes d'animaux sont désormais prises en charge (la vente a lieu automatiquement à 8 heures du matin lorsque l'âge demandé est atteint ; la santé des animaux doit être d'au moins 75%) 172 | - Traduction française complétée (merci à BOB51160) 173 | 174 | Update 1.2.0 175 | - Prise en charge de MaizePlus 176 | - Probabilités d'utilisation de chaque type de remplissage 177 | - Traduction en russe (merci à Gonimy-Vetrom) 178 | 179 | Update 1.1.1 180 | - Correction de problèmes avec les propres points de vente et productions 181 | 182 | Update 1.1.0 183 | - Prise en compte des élevages et des productions déjà propres à l'entreprise 184 | - premières petites adaptations multijoueurs (pas encore compatibles avec le multijoueur)]]> 185 | 186 | true" con "false" nella quinta riga. Tuttavia, questo viene disattivato solo per questo punteggio 222 | 223 | Aggiornamento 1.3.1 224 | - Correzione delle intestazioni invisibili delle colonne 225 | - Piccole modifiche alla configurazione 226 | 227 | Aggiornamento 1.3.0 228 | - È ora possibile contrassegnare un luogo di destinazione (hotspot) 229 | - Gli ordini di animali sono ora supportati (la vendita avviene automaticamente alle 8 del mattino al raggiungimento dell'età richiesta; lo stato di salute degli animali deve essere almeno del 75%) 230 | - Traduzione francese completata (grazie a BOB51160) 231 | 232 | Aggiornamento 1.2.0 233 | - Supporto per MaizePlus 234 | - Probabilità di utilizzo dei rispettivi tipi di riempimento 235 | - Traduzione in russo (grazie a Gonimy-Vetrom) 236 | 237 | Aggiornamento 1.1.1 238 | - Problemi con le proprie stazioni di vendita e produzioni risolti 239 | 240 | Aggiornamento 1.1.0 241 | - Vengono Considerati allevamenti e produzioni già di proprietà 242 | - prime piccole modifiche al multiplayer (non ancora compatibile con il multiplayer)]]> 243 | 244 | true" на "false". Однако после этого она будет деактивирована только для этого балла 279 | 280 | Обновление 1.3.1 281 | - Исправление невидимых заголовков столбцов 282 | - Незначительные изменения в конфигурации 283 | 284 | Обновление 1.3.0 285 | - Теперь можно отметить местоположение цели (Hotspot) 286 | - Теперь поддерживается заказ животных (продажа происходит автоматически в 8 часов утра при достижении требуемого возраста; здоровье животных должно быть не менее 75%) 287 | - Перевод на французский язык завершен (спасибо BOB51160) 288 | 289 | Обновление 1.2.0 290 | - Поддержка MaizePlus 291 | - Вероятность использования определённого заполнения types 292 | - Перевод на русский язык (спасибо Gonimy-Vetrom) 293 | 294 | Обновление 1.1.1 295 | - Исправлены проблемы с собственными точками продаж и производствами 296 | 297 | Обновление 1.1.0 298 | - Учитывается, есть ли в собственности загоны для животных и производства 299 | - Первые небольшие корректировки для многопользовательской игры (ещё не совместим с многопользовательской игрой)]]> 300 | 301 | 302 | icon_VIPOM.dds 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | Durchblättern VIP Aufträge 322 | Flip VIP Orders 323 | Inverser les commandes VIP 324 | Vedi Ordini VIP correnti 325 | Взглянуть VIP-заказы 326 | 327 | 328 | Anzeige des VIP Auftragsdialogs 329 | Shows VIP Orders Dialog 330 | Affiche la boîte de dialogue des commandes VIP 331 | Mostra la panoramica degli Ordini VIP 332 | Обзор VIP-заказов 333 | 334 | 335 | 336 | 337 | Abbruch aktuellen VIP Auftrag 338 | Aborting current VIP Orders 339 | Annulation des commandes VIP en cours 340 | Annulla gli Ordini VIP correnti 341 | Отказаться от текущих VIP-заказов 342 | 343 | 344 | Du musst eine Abbruchgebühr von %s bezahlen. Für die bereits abgeschlossenen Teilaufträge erhältst du %s. 345 | You have to pay a aborting fee of %s. For the already completed partial orders you will receive %s. 346 | Vous devez payer des frais d'abandon de %s. Pour les commandes partielles déjà terminées, vous recevrez %s. 347 | Devi pagare una commissione di %s per l'annullamento. Per gli ordini parziali già consegnati ricevi una somma di %s. 348 | За отказ вам необходимо возместить убытки в размере %s. За уже выполненную часть заказов вы получите %s. 349 | 350 | 351 | 352 | 353 | Aktueller VIP Auftrag 354 | Current VIP Order 355 | Commande VIP en cours 356 | Ordine VIP corrente 357 | Текущий VIP-заказ 358 | 359 | 360 | Nächster VIP Auftrag 361 | Next VIP Order 362 | Prochaine commande VIP 363 | Prossimo Ordine VIP 364 | Следующий VIP-заказ 365 | 366 | 367 | Auszahlung: %s 368 | Payout: %s 369 | Paiement: %s 370 | Pagamento: %s 371 | Выплата: %s 372 | 373 | 374 | Der aktuelle VIP-Auftrag wurde abgeschlossen. 375 | Current VIP order was completed. 376 | La commande VIP actuelle a été complétée. 377 | Ordine VIP corrente completato. 378 | Текущий VIP-заказ был завершён. 379 | 380 | 381 | Monate 382 | months 383 | Mois 384 | mesi 385 | мес. 386 | 387 | 388 | ** Freie Wahl ** 389 | ** Free choice ** 390 | ** Libre choix ** 391 | ** Scelta libera ** 392 | ** Свободный выбор ** 393 | 394 | 395 | ** Automatisch ** 396 | ** Automatic ** 397 | ** Automatique ** 398 | ** Automatico ** 399 | ** Автоматический ** 400 | 401 | 402 | Stk. 403 | pcs. 404 | pcs. 405 | pz. 406 | шт. 407 | 408 | 409 | %s "%s" geliefert für den aktuellen VIP-Auftrag 410 | %s "%s" delivered for the current VIP order 411 | %s "%s" livrées pour la commande VIP en cours 412 | %s "%s" consegnate per l'ordine VIP in corso 413 | %s "%s" доставленных для текущего VIP-заказа 414 | 415 | 416 | 417 | 418 | Übersicht der VIP-Aufträge 419 | Overview VIP Orders 420 | Aperçu des commandes VIP 421 | Panoramica Ordini VIP 422 | Обзор VIP-заказов 423 | 424 | 425 | Produkt 426 | Product 427 | Produit 428 | Prodotto 429 | Продукция 430 | 431 | 432 | Angefordert 433 | Requested 434 | Demandé 435 | Richiesto 436 | Запрошено 437 | 438 | 439 | Geliefert 440 | Delivered 441 | Livré 442 | Consegnato 443 | Доставлено 444 | 445 | 446 | Auszahlung 447 | Payout 448 | Paiement 449 | Pagamento 450 | Выплата 451 | 452 | 453 | Lieferstation 454 | Delivery station 455 | Poste de livraison 456 | Luogo di Consegna 457 | Станция доставки 458 | 459 | 460 | Schließen 461 | Close 462 | Fermer 463 | Chiuso 464 | Закрыть 465 | 466 | 467 | Abbruch des aktuellen VIP Auftrags 468 | Abort current VIP Order 469 | Annuler la commande VIP en cours 470 | Annulla l'Ordine VIP corrente 471 | Отказаться от текущего VIP-заказа 472 | 473 | 474 | Markierung setzen 475 | Tag place 476 | Mettre un marqueur 477 | Impostare il marcatore 478 | Установить маркер 479 | 480 | 481 | Markierung löschen 482 | Untag place 483 | Supprimer la marque 484 | Cancellare il marcatore 485 | Удалить маркер 486 | 487 | 488 | Verfügbare Lieferprodukte anzeigen 489 | Show available delivery products 490 | Afficher les produits de livraison disponibles 491 | Mostra i prodotti di consegna disponibili 492 | Показать доступные товары для доставки 493 | 494 | 495 | Level %s - Auszahlung: %s (Aktiv) 496 | Level %s - Payout: %s (Active) 497 | Level %s - Paiement: %s (Actif) 498 | Livello %s - Pagamento: %s (Attivo) 499 | Уровень %s - Выплата: %s (активный) 500 | 501 | 502 | Level %s - Auszahlung: %s 503 | Level %s - Payout: %s 504 | Level %s - Paiement: %s 505 | Livello %s - Pagamento: %s 506 | Уровень %s - Выплата: %s 507 | 508 | 509 | Verfügbare Lieferprodukte 510 | Available delivery products 511 | Produits de livraison disponibles 512 | Prodotti di consegna disponibili 513 | Доступные товары для доставки 514 | 515 | 516 | Lieferprodukt 517 | Delivery product 518 | Produit livré 519 | Consegna prodotto 520 | Продукт доставки 521 | 522 | 523 | min. Level 524 | min. level 525 | min. Level 526 | min. livello 527 | мин. уровень 528 | 529 | 530 | Wahrscheinlichkeit 531 | Probability 532 | Probabilité 533 | Probabilità 534 | Вероятность 535 | 536 | 537 | Kommentar 538 | Comment 539 | Commentaire 540 | Commento 541 | Комментарий 542 | 543 | 544 | Korr. Menge 545 | Corr. Quantity 546 | Corr. Quantité 547 | Corr. Quantità 548 | Корр. Количество 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | Fruchttypen 557 | Fruit Types 558 | Types de remplissage disponibles 559 | Tipi di riempimento disponibili 560 | Доступные типы наполнения 561 | 562 | 563 | Fülltypen 564 | Fill Types 565 | Types de remplissage disponibles 566 | Tipi di riempimento disponibili 567 | Доступные типы наполнения 568 | 569 | 570 | Tiere 571 | Animals 572 | Types de remplissage disponibles 573 | Tipi di riempimento disponibili 574 | Доступные типы наполнения 575 | 576 | 577 | Nicht verwendbar 578 | Not Useable 579 | Types de remplissage disponibles 580 | Tipi di riempimento disponibili 581 | Доступные типы наполнения 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | -------------------------------------------------------------------------------- /VIPOrderManager.lua: -------------------------------------------------------------------------------- 1 | -- Author: Fetty42 2 | -- Date: 20.10.2024 3 | -- Version: 1.4.0.0 4 | 5 | local dbPrintfOn = false 6 | local dbInfoPrintfOn = false 7 | 8 | local function dbInfoPrintf(...) 9 | if dbInfoPrintfOn then 10 | print(string.format(...)) 11 | end 12 | end 13 | 14 | local function dbPrintf(...) 15 | if dbPrintfOn then 16 | print(string.format(...)) 17 | end 18 | end 19 | 20 | local function dbPrintHeader(ftName) 21 | if dbPrintfOn then 22 | print(string.format("Call %s: g_currentMission:getIsServer()=%s | g_currentMission:getIsClient()=%s", ftName, g_currentMission:getIsServer(), g_currentMission:getIsClient())) 23 | end 24 | end 25 | 26 | local function Printf(...) 27 | print(string.format(...)) 28 | end 29 | 30 | VIPOrderManager = {}; -- Class 31 | 32 | -- update delay 33 | VIPOrderManager.updateDelta = 0; -- time since the last update 34 | VIPOrderManager.updateRate = 1000; -- milliseconds until next update 35 | VIPOrderManager.InitDone = false 36 | 37 | -- Info display 38 | VIPOrderManager.showVIPOrder = 1 -- 0=off, 1=Current, 2=Next 39 | VIPOrderManager.infoDisplayPastTime = 0 40 | VIPOrderManager.infoDisplayMaxShowTime = 20000 -- How long the info is displayed 41 | 42 | -- Constants for output 43 | VIPOrderManager.outputStartPoint = {x=0.01, y=0.40} -- links, mitte 44 | VIPOrderManager.outputFontSize = 0.016 -- links, mitte 45 | VIPOrderManager.colors = {} 46 | VIPOrderManager.colors[1] = {'col_white', {1, 1, 1, 1}} 47 | VIPOrderManager.colors[2] = {'col_black', {0, 0, 0, 1}} 48 | VIPOrderManager.colors[3] = {'col_grey', {0.7411, 0.7450, 0.7411, 1}} 49 | VIPOrderManager.colors[4] = {'col_blue', {0.0044, 0.15, 0.6376, 1}} 50 | VIPOrderManager.colors[5] = {'col_red', {0.8796, 0.0061, 0.004, 1}} 51 | VIPOrderManager.colors[6] = {'col_green', {0.0263, 0.3613, 0.0212, 1}} 52 | VIPOrderManager.colors[7] = {'col_yellow', {0.9301, 0.7605, 0.0232, 1}} 53 | VIPOrderManager.colors[8] = {'col_pink', {0.89, 0.03, 0.57, 1}} 54 | VIPOrderManager.colors[9] = {'col_turquoise', {0.07, 0.57, 0.35, 1}} 55 | VIPOrderManager.colors[10] = {'col_brown', {0.1912, 0.1119, 0.0529, 1}} 56 | 57 | -- global variables 58 | VIPOrderManager.dir = g_currentModDirectory 59 | VIPOrderManager.modName = g_currentModName 60 | 61 | VIPOrderManager.existingProductionOutputs = {} -- 1 --> existing | 2 --> self owned 62 | VIPOrderManager.existingAnimalHusbandryOutputs = {} -- 1 --> existing | 2 --> self owned 63 | VIPOrderManager.VIPOrders = {} -- List of orders {level, entries{[Name] = {fillTypeName, title, quantity, fillLevel, payout, targetStation, isAnimal, neededAgeInMonths}}} 64 | 65 | VIPOrderManager.outputLines = {} -- Output lines for the draw() function (text, size, bold, colorId, x, y) 66 | VIPOrderManager.infoHud = nil -- VID Order Info HUD 67 | VIPOrderManager.OrderDlg = nil 68 | 69 | VIPOrderManager.successSound = createSample("success") 70 | loadSample(VIPOrderManager.successSound, "data/sounds/ui/uiSuccess.ogg", false) 71 | VIPOrderManager.failSound = createSample("fail") 72 | loadSample(VIPOrderManager.failSound, "data/sounds/ui/uiFail.ogg", false) 73 | 74 | 75 | 76 | source(Utils.getFilename("MyTools.lua", VIPOrderManager.dir)) 77 | source(Utils.getFilename("VIPOrderManagerDefaults.lua", VIPOrderManager.dir)) 78 | source(Utils.getFilename("InfoHUD.lua", VIPOrderManager.dir)) 79 | source(VIPOrderManager.dir .. "gui/OrderFrame.lua") 80 | 81 | function VIPOrderManager:loadMap(name) 82 | dbPrintHeader("VIPOrderManager:loadMap()") 83 | 84 | if g_currentMission:getIsClient() then 85 | Player.registerActionEvents = Utils.appendedFunction(Player.registerActionEvents, VIPOrderManager.registerActionEvents); 86 | Enterable.onRegisterActionEvents = Utils.appendedFunction(Enterable.onRegisterActionEvents, VIPOrderManager.registerActionEvents); 87 | -- VIPOrderManager.eventName = {}; 88 | 89 | FSBaseMission.saveSavegame = Utils.appendedFunction(FSBaseMission.saveSavegame, VIPOrderManager.saveSettings); 90 | FSBaseMission.onFinishedLoading = Utils.appendedFunction(FSBaseMission.onFinishedLoading, VIPOrderManager.loadSettings); 91 | --VIPOrderManager:loadSettings(); 92 | 93 | SellingStation.addFillLevelFromTool = Utils.overwrittenFunction(SellingStation.addFillLevelFromTool, VIPOrderManager.sellingStation_addFillLevelFromTool) 94 | 95 | g_messageCenter:subscribe(MessageType.HOUR_CHANGED, self.onHourChanged, self) 96 | end 97 | math.randomseed(getDate("%S")+getDate("%M")) 98 | end; 99 | 100 | 101 | function VIPOrderManager:onHourChanged(hour) 102 | dbPrintHeader("VIPOrderManager:onHourChanged()") 103 | 104 | if VIPOrderManager.VIPOrders ~= nil and VIPOrderManager.VIPOrders[1] ~= nil then 105 | local farmId = g_currentMission.player.farmId; 106 | local isWarning = false 107 | local currentVipOrder = VIPOrderManager.VIPOrders[1] 108 | 109 | -- prepare subType to fillType 110 | local subTypeIndexToFillTypeName 111 | 112 | for _,husbandry in pairs(g_currentMission.husbandrySystem.clusterHusbandries) do 113 | local placeable = husbandry:getPlaceable() 114 | if placeable.ownerFarmId == farmId then 115 | local placeableName = placeable:getName() 116 | 117 | dbPrintf(" - husbandry placeables: Name=%s | AnimalType=%s | NumOfAnimals=%s | getNumOfClusters=%s", placeableName, husbandry.animalTypeName, placeable:getNumOfAnimals(), placeable:getNumOfClusters()) 118 | 119 | for idx, cluster in ipairs(placeable:getClusters()) do 120 | dbPrintf(" - Cluster: numAnimals=%s | age=%s | health=%s | subTypeName=%s | subTypeTitle=%s" 121 | , cluster.numAnimals, cluster.age, cluster.health, g_currentMission.animalSystem.subTypes[cluster.subTypeIndex].name, g_currentMission.animalSystem.subTypes[cluster.subTypeIndex].visuals[1].store.name) 122 | 123 | local orderEntry = currentVipOrder.entries[g_currentMission.animalSystem.subTypes[cluster.subTypeIndex].name] 124 | if orderEntry ~= nil then 125 | dbPrintf(" --> fitting order entry exists with: quantity=%s | fillLevel=%s | neededAgeInMonths=%s", orderEntry.quantity, orderEntry.fillLevel, orderEntry.neededAgeInMonths) 126 | if cluster.age >= orderEntry.neededAgeInMonths and cluster.health >= 75 then 127 | local numAninmalsToSell = math.min(orderEntry.quantity - orderEntry.fillLevel, cluster.numAnimals) 128 | 129 | if numAninmalsToSell > 0 then 130 | local sellPrice = cluster:getSellPrice() * numAninmalsToSell 131 | 132 | cluster.numAnimals = cluster.numAnimals - numAninmalsToSell 133 | 134 | -- clean up 135 | if cluster.numAnimals <= 0 then 136 | table.remove(placeable:getClusters(), idx) 137 | end 138 | 139 | local msgTxt = string.format(g_i18n:getText("VIPOrderManager_AnimalsDelivered"), numAninmalsToSell, orderEntry.title) 140 | dbPrintf(" --> " .. msgTxt) 141 | g_currentMission:addIngameNotification(FSBaseMission.INGAME_NOTIFICATION_INFO, msgTxt) 142 | g_currentMission:addMoney(sellPrice, g_currentMission.player.farmId, MoneyType.SOLD_ANIMALS, true, true); 143 | 144 | orderEntry.fillLevel = orderEntry.fillLevel + numAninmalsToSell 145 | 146 | VIPOrderManager.showVIPOrder = 1; 147 | VIPOrderManager.infoDisplayPastTime = 0 148 | VIPOrderManager:UpdateOutputLines() 149 | end 150 | end 151 | end 152 | end 153 | end 154 | end 155 | end 156 | end 157 | 158 | 159 | function VIPOrderManager:registerActionEvents() 160 | -- dbPrintHeader("VIPOrderManager:registerActionEvents()") 161 | 162 | if g_currentMission:getIsClient() then --isOwner 163 | -- local result, actionEventId = InputBinding.registerActionEvent(g_inputBinding, 'ShowCurrentVIPOrder',self, VIPOrderManager.ShowCurrentVIPOrder ,false ,true ,false ,true) 164 | local result, actionEventId = g_inputBinding:registerActionEvent('ShowCurrentVIPOrder',InputBinding.NO_EVENT_TARGET, VIPOrderManager.ShowCurrentVIPOrder ,false ,true ,false ,true) 165 | dbPrintf("Result=%s | actionEventId=%s | g_currentMission:getIsClient()=%s", result, actionEventId, g_currentMission:getIsClient()) 166 | if result and actionEventId then 167 | g_inputBinding:setActionEventTextVisibility(actionEventId, true) 168 | g_inputBinding:setActionEventActive(actionEventId, true) 169 | g_inputBinding:setActionEventTextPriority(actionEventId, GS_PRIO_VERY_LOW) -- GS_PRIO_VERY_HIGH, GS_PRIO_HIGH, GS_PRIO_LOW, GS_PRIO_VERY_LOW 170 | 171 | -- table.insert(VIPOrderManager.eventName, actionEventId); 172 | -- g_inputBinding.events[actionEventId].displayIsVisible = true; 173 | dbPrintf("Action event inserted successfully") 174 | end 175 | local result2, actionEventId2 = g_inputBinding:registerActionEvent('ShowVIPOrderDlg',InputBinding.NO_EVENT_TARGET, VIPOrderManager.ShowVIPOrderDlg ,false ,true ,false ,true) 176 | dbPrintf("Result2=%s | actionEventId2=%s | g_currentMission:getIsClient()=%s", result2, actionEventId2, g_currentMission:getIsClient()) 177 | if result2 and actionEventId2 then 178 | g_inputBinding:setActionEventTextVisibility(actionEventId2, true) 179 | g_inputBinding:setActionEventActive(actionEventId2, true) 180 | g_inputBinding:setActionEventTextPriority(actionEventId2, GS_PRIO_VERY_LOW) -- GS_PRIO_VERY_HIGH, GS_PRIO_HIGH, GS_PRIO_LOW, GS_PRIO_VERY_LOW 181 | 182 | -- table.insert(VIPOrderManager.eventName, actionEventId2); 183 | -- g_inputBinding.events[actionEventId2].displayIsVisible = true; 184 | dbPrintf("Action event inserted successfully") 185 | end 186 | 187 | if infoHud == nil then 188 | ---@diagnostic disable-next-line: lowercase-global 189 | infoHud = InfoHUD.new() 190 | infoHud:setVisible(true) 191 | end 192 | -- hud:delete() 193 | end 194 | end 195 | 196 | 197 | -- 198 | function VIPOrderManager:ShowVIPOrderDlg(actionName, keyStatus, arg3, arg4, arg5) 199 | dbPrintHeader("VIPOrderManager:ShowVIPOrderDlg()") 200 | 201 | VIPOrderManager.OrderDlg = nil 202 | g_gui:loadProfiles(VIPOrderManager.dir .. "gui/guiProfiles.xml") 203 | local orderFrame = OrderFrame.new(g_i18n) 204 | g_gui:loadGui(VIPOrderManager.dir .. "gui/OrderFrame.xml", "OrderFrame", orderFrame) 205 | VIPOrderManager.OrderDlg = g_gui:showDialog("OrderFrame") 206 | 207 | if VIPOrderManager.OrderDlg ~= nil then 208 | VIPOrderManager.OrderDlg.target:setVIPOrders(VIPOrderManager.VIPOrders) 209 | 210 | end 211 | 212 | -- print("** Start DebugUtil.printTableRecursively() ************************************************************") 213 | -- print("g_currentMission:") 214 | -- DebugUtil.printTableRecursively(g_currentMission, ".", 0, 4) 215 | -- print("** End DebugUtil.printTableRecursively() **************************************************************") 216 | 217 | end 218 | 219 | 220 | -- Payout complete orders less a abort fee for incomplete orders. 221 | function VIPOrderManager:AbortCurrentVIPOrder() 222 | dbPrintHeader("VIPOrderManager:AbortCurrentVIPOrder()") 223 | 224 | local sumAbortFee, sumPayout = VIPOrderManager:GetSumAbortFeeAndSumPayout() 225 | 226 | -- g_gui:showYesNoDialog({text=g_i18n:getText("tour_text_start"), title="", callback=self.reactToDialog, target=self}) 227 | local msgText = string.format(g_i18n:getText("VIPOrderManager_DlgMsg_AbortCurrentVIPOrder"), g_i18n:formatMoney(sumAbortFee, 0, true), g_i18n:formatMoney(sumPayout, 0, true)) 228 | g_gui:showYesNoDialog({text=msgText, title=g_i18n:getText("VIPOrderManager_DlgTitel_AbortCurrentVIPOrder"), callback=VIPOrderManager.reactToDialog_AbortCurrentVIPOrder, target=self}) 229 | end 230 | 231 | 232 | function VIPOrderManager:reactToDialog_AbortCurrentVIPOrder(yes) 233 | dbPrintHeader("VIPOrderManager:reactToDialog_AbortCurrentVIPOrder()") 234 | 235 | if yes and VIPOrderManager.VIPOrders[1] ~= nil then 236 | local sumAbortFee, sumPayout = VIPOrderManager:GetSumAbortFeeAndSumPayout() 237 | 238 | playSample(VIPOrderManager.failSound ,1 ,1 ,1 ,0 ,0) 239 | 240 | -- show message and payout 241 | -- dbPrintf(" sumAbortFee=%s | sumPayout=%s", g_i18n:formatMoney(sumAbortFee, 0, true), g_i18n:formatMoney(sumPayout, 0, true)) 242 | g_currentMission:addMoney(sumPayout, g_currentMission.player.farmId, MoneyType.MISSIONS, true, true); 243 | g_currentMission:addMoney(sumAbortFee, g_currentMission.player.farmId, MoneyType.MISSIONS, true, true); 244 | 245 | table.remove(VIPOrderManager.VIPOrders, 1) 246 | VIPOrderManager:RestockVIPOrders() 247 | if VIPOrderManager.OrderDlg ~= nil then 248 | VIPOrderManager.OrderDlg.target:setVIPOrders(VIPOrderManager.VIPOrders) 249 | end 250 | end 251 | end 252 | 253 | 254 | function VIPOrderManager:GetSumAbortFeeAndSumPayout() 255 | dbPrintHeader("VIPOrderManager:GetSumAbortFeeAndSumPayout()") 256 | 257 | local sumPayout = 0 258 | local sumAbortFee = 0 259 | 260 | for _, vipOrderEntry in pairs(VIPOrderManager.VIPOrders[1].entries) do 261 | local requiredQuantity = vipOrderEntry.quantity - math.ceil(vipOrderEntry.fillLevel) 262 | 263 | if requiredQuantity > 0 then 264 | -- incomplete order ==> calculate fee (10%) 265 | sumAbortFee = sumAbortFee - (vipOrderEntry.payout / 100 * VIPOrderManager.abortFeeInPercent) 266 | else 267 | -- complete order ==> calculate payout 268 | sumPayout = sumPayout + vipOrderEntry.payout 269 | end 270 | end 271 | return sumAbortFee, sumPayout 272 | end 273 | 274 | 275 | function VIPOrderManager:RestockVIPOrders() 276 | dbPrintHeader("VIPOrderManager:RestockVIPOrders()") 277 | 278 | if g_currentMission:getIsClient() and g_currentMission.player.farmId > 0 then 279 | -- new VIPOrder 280 | local orderLevel = 0 281 | if #VIPOrderManager.VIPOrders > 0 then 282 | orderLevel = VIPOrderManager.VIPOrders[#VIPOrderManager.VIPOrders].level 283 | end 284 | while (#VIPOrderManager.VIPOrders < VIPOrderManager.maxVIPOrdersCount) do 285 | local newEntries = {} 286 | orderLevel = orderLevel + 1 287 | dbPrintf(" - Create new VIPOrder with level " .. orderLevel) 288 | VIPOrderManager:calculateAndFillOrder(newEntries, orderLevel) 289 | table.insert(VIPOrderManager.VIPOrders, {level = orderLevel, entries = newEntries}) 290 | end 291 | self.showVIPOrder = 1 292 | self.infoDisplayPastTime = 0 293 | VIPOrderManager:UpdateOutputLines() 294 | end 295 | -- print("** Start DebugUtil.printTableRecursively() ************************************************************") 296 | -- DebugUtil.printTableRecursively(VIPOrderManager.VIPOrders, ".", 0, 3) 297 | -- print("** End DebugUtil.printTableRecursively() **************************************************************") 298 | end 299 | 300 | 301 | function VIPOrderManager:GetExistingProductionAndAnimalHusbandryOutputs() 302 | dbPrintHeader("VIPOrderManager:GetExistingProductionAndAnimalHusbandryOutputs()") 303 | 304 | VIPOrderManager.existingProductionOutputs = {} 305 | VIPOrderManager.existingAnimalHusbandryOutputs = {} 306 | local farmId = g_currentMission.player.farmId; 307 | local isMilk = 0 308 | local isLiquidManure = 0 309 | local isManure = 0 310 | local foundAnimalTypeNames = {} 311 | 312 | -- look for own husbandries 313 | dbPrintf(" - Num cluster Husbandries: %s", MyTools:getCountElements(g_currentMission.husbandrySystem.clusterHusbandries)) 314 | for _,husbandry in pairs(g_currentMission.husbandrySystem.clusterHusbandries) do 315 | local placeable = husbandry:getPlaceable() 316 | local selfOwned = placeable.ownerFarmId == farmId 317 | 318 | local name = placeable:getName() 319 | local specHusbandryLiquidManure = placeable.spec_husbandryLiquidManure 320 | local specHusbandryMilk = placeable.spec_husbandryMilk 321 | local specHusbandryStraw = placeable.spec_husbandryStraw 322 | local isManureActive = false 323 | if specHusbandryStraw ~= nil then 324 | isManureActive = specHusbandryStraw.isManureActive 325 | end 326 | 327 | dbPrintf(" - husbandry placeables: Name=%s | selfOwned=%s | AnimalType=%s | specMilk=%s | specLiquidManure=%s | specStraw=%s | isManureActive=%s", name, selfOwned, husbandry.animalTypeName, tostring(specHusbandryMilk), tostring(specHusbandryLiquidManure), tostring(specHusbandryStraw), isManureActive) 328 | 329 | -- remember for later to list all animal subtypes 330 | foundAnimalTypeNames[husbandry.animalTypeName] = math.max(foundAnimalTypeNames[husbandry.animalTypeName] or 0, selfOwned and 2 or 1) 331 | 332 | isMilk = specHusbandryMilk ~= nil and math.max(isMilk, selfOwned and 2 or 1) or isMilk 333 | isLiquidManure = specHusbandryLiquidManure ~= nil and math.max(isLiquidManure, selfOwned and 2 or 1) or isLiquidManure 334 | isManure = isManureActive and math.max(isManure, selfOwned and 2 or 1) or isManure 335 | end 336 | 337 | -- insert animal output products 338 | if isMilk > 0 then 339 | VIPOrderManager.existingAnimalHusbandryOutputs.MILK = isMilk 340 | end 341 | if isLiquidManure > 0 then 342 | VIPOrderManager.existingAnimalHusbandryOutputs.LIQUIDMANURE = isLiquidManure 343 | end 344 | if isManure > 0 then 345 | VIPOrderManager.existingAnimalHusbandryOutputs.MANURE = isManure 346 | end 347 | if foundAnimalTypeNames["CHICKEN"] ~= nil then 348 | VIPOrderManager.existingAnimalHusbandryOutputs.EGG = foundAnimalTypeNames["CHICKEN"] 349 | end 350 | if foundAnimalTypeNames["SHEEP"] ~= nil then 351 | VIPOrderManager.existingAnimalHusbandryOutputs.WOOL = foundAnimalTypeNames["SHEEP"] 352 | end 353 | if foundAnimalTypeNames["GOAT"] ~= nil then 354 | VIPOrderManager.existingAnimalHusbandryOutputs.GOATMILK = foundAnimalTypeNames["GOAT"] 355 | end 356 | 357 | -- insert animal fill types 358 | for i, fillTypeIdx in pairs(g_fillTypeManager:getFillTypesByCategoryNames("ANIMAL HORSE")) do 359 | local fillType = g_fillTypeManager:getFillTypeByIndex(fillTypeIdx) 360 | local animalSubType = g_currentMission.animalSystem.fillTypeIndexToSubType[fillTypeIdx] 361 | 362 | if animalSubType ~= nil then 363 | local animalName = g_currentMission.animalSystem.typeIndexToName[animalSubType.typeIndex] 364 | if foundAnimalTypeNames[animalName] ~= nil then 365 | VIPOrderManager.existingAnimalHusbandryOutputs[fillType.name] = foundAnimalTypeNames[animalName] 366 | end 367 | end 368 | end 369 | 370 | -- look for own productions and insert output products 371 | dbPrintf("") 372 | dbPrintf(" - Num Production Points: %s", g_currentMission.productionChainManager:getNumOfProductionPoints()) 373 | -- if g_currentMission.productionChainManager.farmIds[farmId] ~= nil and g_currentMission.productionChainManager.farmIds[farmId].productionPoints ~= nil then 374 | -- for _, productionPoint in pairs(g_currentMission.productionChainManager.farmIds[farmId].productionPoints) do 375 | if g_currentMission.productionChainManager.productionPoints ~= nil then 376 | for _, productionPoint in pairs(g_currentMission.productionChainManager.productionPoints) do 377 | 378 | local selfOwned = productionPoint:getOwnerFarmId() == farmId 379 | local name = productionPoint.owningPlaceable:getName() 380 | dbPrintf(" - Production: Name=%s | farmId=%s | selfOwned=%s", name, productionPoint:getOwnerFarmId(), selfOwned) 381 | 382 | for fillTypeId, fillLevel in pairs(productionPoint.storage.fillLevels) do 383 | local fillTypeId = fillTypeId 384 | local fillTypeName = g_currentMission.fillTypeManager.fillTypes[fillTypeId].name 385 | local fillTypeTitle = g_currentMission.fillTypeManager.fillTypes[fillTypeId].title 386 | local isInput = false 387 | 388 | -- prüfen ob input type 389 | if productionPoint.inputFillTypeIds[fillTypeId] ~= nil then 390 | isInput = productionPoint.inputFillTypeIds[fillTypeId] 391 | end 392 | 393 | for _, production in pairs(productionPoint.activeProductions) do 394 | for _, input in pairs(production.inputs) do 395 | -- status 3 = läuft nicht weil ausgang voll 396 | if input.type == fillTypeId then 397 | isInput = true 398 | end 399 | end 400 | end 401 | if not isInput then 402 | dbPrintf(" - fillTypeName=%s | fillTypeTitle=%s | isInput=%s", fillTypeName, fillTypeTitle, isInput) 403 | VIPOrderManager.existingProductionOutputs[fillTypeName] = math.max(VIPOrderManager.existingProductionOutputs[fillTypeName] or 0, selfOwned and 2 or 1) 404 | end 405 | end 406 | end 407 | end 408 | 409 | -- if dbPrintfOn then 410 | -- DebugUtil.printTableRecursively(VIPOrderManager.existingAnimalHusbandryOutputs, ".", 0, 3) 411 | -- DebugUtil.printTableRecursively(VIPOrderManager.existingProductionOutputs, ".", 0, 3) 412 | -- end 413 | end 414 | 415 | 416 | function VIPOrderManager:calculateAndFillOrder(VIPOrder, orderLevel) 417 | dbPrintHeader("VIPOrderManager:calculateAndFillOrder()") 418 | 419 | local relevantFillTypes = {}; 420 | VIPOrderManager:GetRelevantFillTypes(relevantFillTypes) 421 | 422 | -- set the special corrections faktors depending on the current order level and the own field area 423 | -- for level=1, 20, 1 do 424 | -- local factorCount = ((1 + level*0.04)-0.04) 425 | -- local factorQuantity = ((1 + level*level*0.005) - 0.005) 426 | -- local factorPayout = 1/ ((1 + level*0.05) - 0.05) 427 | -- dbPrintf("Level %2i: factorCount=%f | factorQuantity=%f | factorPayout=%f", 428 | -- level, factorCount, factorQuantity, factorPayout) 429 | -- end 430 | 431 | 432 | local specCorFactorCount = orderLevel^(1/4) 433 | local specCorFactorQuantity = orderLevel^(1/3) 434 | local specCorFactorPayout = (1.0 / (specCorFactorQuantity*specCorFactorCount))*1.1 435 | dbPrintf("Create new VIP Order: Level %s", orderLevel) 436 | dbPrintf(" Initial basic correction factors:") 437 | dbPrintf(" - Count factor = %.2f", specCorFactorCount) 438 | dbPrintf(" - Quantity factor = %.2f", specCorFactorQuantity) 439 | dbPrintf(" - Payout factor = %.2f", specCorFactorPayout) 440 | 441 | local ownFieldSizeFactor = math.max(1, VIPOrderManager.ownFieldArea^(1/2)) 442 | dbPrintf(" Basic correction factors adjusted by the size of the own fields:") 443 | dbPrintf(" - own field size = " .. VIPOrderManager.ownFieldArea) 444 | dbPrintf(" - own field size factor = " .. ownFieldSizeFactor) 445 | dbPrintf(" - adjusted quantity factor from %.2f to %.2f", specCorFactorQuantity, specCorFactorQuantity * ownFieldSizeFactor) 446 | dbPrintf(" - adjusted payout factor from %.2f to %.2f", specCorFactorPayout, (1.0 / (specCorFactorQuantity*specCorFactorCount))*1.1) 447 | local specCorFactorQuantity = specCorFactorQuantity * ownFieldSizeFactor 448 | local specCorFactorPayout = (1.0 / (specCorFactorQuantity*specCorFactorCount))*1.1 449 | 450 | -- if necessary overright by Correction factors for easier beginning 451 | if VIPOrderManager.orderLevelCorrectionFactors[orderLevel] ~= nil then 452 | specCorFactorCount = VIPOrderManager.orderLevelCorrectionFactors[orderLevel][1] 453 | specCorFactorQuantity = VIPOrderManager.orderLevelCorrectionFactors[orderLevel][2] 454 | specCorFactorPayout = VIPOrderManager.orderLevelCorrectionFactors[orderLevel][3] 455 | dbPrintf(" If necessary overright by Correction factors for easier beginning:") 456 | dbPrintf(" - Count factor = %.2f", specCorFactorCount) 457 | dbPrintf(" - Quantity factor = %.2f", specCorFactorQuantity) 458 | dbPrintf(" - Payout factor = %.2f", specCorFactorPayout) 459 | end 460 | 461 | -- create random order items 462 | local countFillTypes = #relevantFillTypes 463 | local countOrderItems = math.floor(math.random(VIPOrderManager.countOrderItemsRange.min, VIPOrderManager.countOrderItemsRange.max) * specCorFactorCount + 0.5) 464 | dbPrintf(" Calculate order item count:") 465 | dbPrintf(" - min count = " .. VIPOrderManager.countOrderItemsRange.min) 466 | dbPrintf(" - max count = " .. VIPOrderManager.countOrderItemsRange.max) 467 | dbPrintf(" - Count factor = " .. specCorFactorCount) 468 | dbPrintf(" ==> Count order items = " .. countOrderItems) 469 | 470 | -- local maxLimitedOrderItems = math.floor(orderLevel / 100 * VIPOrderManager.isLimitedPercentage) 471 | local activeLimits ={} 472 | -- dbPrintf(" Max allowed limited order items: %s percent from %s = %s", VIPOrderManager.isLimitedPercentage, orderLevel, maxLimitedOrderItems) 473 | 474 | local i = 0 475 | while (i < countOrderItems) do 476 | i = i + 1 477 | dbPrintf(string.format(" %s. Order Item:", i)) 478 | 479 | -- dice group name 480 | local groupNameSetting = nil 481 | repeat 482 | local isNextTryForGroup = false 483 | groupNameSetting = VIPOrderManager.groupNameSettings[math.random(1, #VIPOrderManager.groupNameSettings)] 484 | 485 | local random = math.random() * 100 486 | isNextTryForGroup = random > groupNameSetting.probability 487 | 488 | until(not isNextTryForGroup) 489 | 490 | dbPrintf(" - diced group: %s", groupNameSetting.groupName) 491 | 492 | 493 | -- dice fill type 494 | local fillType = nil 495 | local relevantFillType = nil 496 | local numPrioTrysForGroup = VIPOrderManager.numPrioTrysForGroup 497 | repeat 498 | local isNextTry = false 499 | relevantFillType = relevantFillTypes[math.random(1, countFillTypes)] 500 | local ftConfig = relevantFillType.ftConfig 501 | 502 | -- is animal but not first subtype 503 | if not isNextTry and relevantFillType.isAnimal then 504 | if relevantFillType.animalTypeCount == 1 then 505 | -- select animal sub type to be used 506 | local searchAnimalTypeIndex = relevantFillType.animalTypeIndex 507 | repeat 508 | relevantFillType = relevantFillTypes[math.random(1, countFillTypes)] 509 | until(relevantFillType.isAnimal == nil or not relevantFillType.isAnimal or relevantFillType.animalTypeIndex ~= searchAnimalTypeIndex) 510 | ftConfig = relevantFillType.ftConfig 511 | else 512 | dbPrintf(" - animal %s (%s) is not first subtype of '%s '(Count=%s)", relevantFillType.name, relevantFillType.title, relevantFillType.animalTypeName, relevantFillType.animalTypeCount) 513 | isNextTry = true 514 | end 515 | end 516 | 517 | -- is not usable 518 | if not isNextTry and not relevantFillType.isUsable ~= nil and not relevantFillType.isUsable then 519 | isNextTry = true 520 | dbPrintf(" - ft %s (%s) is not usable because: %s", relevantFillType.name, relevantFillType.title, relevantFillType.notUsableMsg) 521 | end 522 | 523 | -- is order-level high enough? 524 | if not isNextTry and ftConfig.minOrderLevel > orderLevel then 525 | isNextTry = true 526 | dbPrintf(" - ft %s (%s) requireds a minimum order-level from %s. The current order-level is %s --> isNextTry=%s", relevantFillType.name, relevantFillType.title, ftConfig.minOrderLevel, orderLevel, isNextTry) 527 | end 528 | 529 | -- animal orders wished? 530 | if not isNextTry and not VIPOrderManager.isAnimalOrdersWished and relevantFillType.isAnimal then 531 | isNextTry = true 532 | dbPrintf(" - ft %s (%s) is animal but animals are not wished --> isNextTry=%s", relevantFillType.name, relevantFillType.title, isNextTry) 533 | end 534 | 535 | -- Exists probability 536 | if not isNextTry and ftConfig.probability ~= nil and ftConfig.probability < 100 then 537 | local probability = ftConfig.probability 538 | local random = math.random() * 100 539 | isNextTry = random > probability 540 | dbPrintf(" - ft %s (%s) has probability: probability=%s, random=%s --> isNextTry=%s", relevantFillType.name, relevantFillType.title, probability, random, isNextTry) 541 | end 542 | 543 | -- limited group? 544 | if not isNextTry and ftConfig.groupName ~= nil and VIPOrderManager.limitedGroupsPercent[ftConfig.groupName] ~= nil then 545 | if activeLimits[ftConfig.groupName] == nil then 546 | activeLimits[ftConfig.groupName] = math.max(1, math.floor(countOrderItems / 100 * VIPOrderManager.limitedGroupsPercent[ftConfig.groupName])) 547 | end 548 | 549 | dbPrintf(" - Existing limited order for group '%s': %s percent from %s (min 1) --> even more available: %s", ftConfig.groupName, VIPOrderManager.limitedGroupsPercent[ftConfig.groupName], countOrderItems, activeLimits[ftConfig.groupName]) 550 | if activeLimits[ftConfig.groupName] <= 0 then 551 | isNextTry = true 552 | dbPrintf(" - ft %s (%s) is limited by group '%s' --> next try", relevantFillType.name, relevantFillType.title, ftConfig.groupName) 553 | else 554 | activeLimits[ftConfig.groupName] = activeLimits[ftConfig.groupName] -1 555 | dbPrintf(" --> choose limited filltype: %s (%s)", relevantFillType.name, relevantFillType.title) 556 | end 557 | end 558 | 559 | if not isNextTry and groupNameSetting.groupName ~= ftConfig.groupName then 560 | if numPrioTrysForGroup > 0 then 561 | numPrioTrysForGroup = numPrioTrysForGroup - 1 562 | dbPrintf(" -> Searching for '%s', diced %s (%s) = '%s' -> try again", groupNameSetting.groupName, relevantFillType.name, relevantFillType.title, ftConfig.groupName) 563 | isNextTry = true 564 | else 565 | dbPrintf(" -> Last searching for '%s' failed!", groupNameSetting.groupName) 566 | end 567 | end 568 | 569 | until(not isNextTry) 570 | 571 | local quantityCorrectionFactor = 1 572 | if relevantFillType.ftConfig.quantityCorrectionFactor ~= nil then 573 | quantityCorrectionFactor = relevantFillType.ftConfig.quantityCorrectionFactor 574 | end 575 | 576 | dbPrintf(" - FillType: %s (%s)| groupName = %s | filltype quantity factor = %.2f", relevantFillType.name, relevantFillType.title, relevantFillType.ftConfig.groupName, quantityCorrectionFactor) 577 | 578 | local randomQuantityFaktor = math.random(VIPOrderManager.quantityFactor.min, VIPOrderManager.quantityFactor.max) * specCorFactorQuantity 579 | local randomPayoutFactor = math.random(VIPOrderManager.payoutFactor.min, VIPOrderManager.payoutFactor.max) * specCorFactorPayout / quantityCorrectionFactor 580 | local orderItemQuantity = math.floor(randomQuantityFaktor * 1000 / relevantFillType.priceMax * quantityCorrectionFactor) 581 | 582 | -- special animal calculations 583 | local orderItemNeededAgeInMonths = nil 584 | if relevantFillType.isAnimal then 585 | orderItemNeededAgeInMonths = VIPOrderManager:getRandomNeededAgeInMonth(relevantFillType.name) 586 | -- 587 | -- relevantFillType.priceMax = VIPOrderManager:GetAnimalSellPriceByFillTypeIdxAndAge(g_fillTypeManager:getFillTypeIndexByName(relevantFillType.name), orderItemNeededAgeInMonths) 588 | -- orderItemQuantity = math.floor(randomQuantityFaktor * 1000 / relevantFillType.priceMax * quantityCorrectionFactor) -- keine Verwendung von SellPrice, da zu Sprunghaft! 589 | end 590 | 591 | dbPrintf(" - final quantity factor = %.2f", randomQuantityFaktor) 592 | dbPrintf(" - final payout factor = %.2f", randomPayoutFactor) 593 | 594 | 595 | if orderItemQuantity > 1000 then 596 | orderItemQuantity = math.floor(orderItemQuantity / 1000) * 1000 597 | elseif orderItemQuantity > 100 then 598 | orderItemQuantity = math.floor(orderItemQuantity / 100) * 100 599 | elseif orderItemQuantity > 10 then 600 | orderItemQuantity = math.floor(orderItemQuantity / 10) * 10 601 | end 602 | dbPrintf(" ==> Quantity = %.2f * 1000 / %.2f * %.2f = %s", randomQuantityFaktor, relevantFillType.priceMax, quantityCorrectionFactor, orderItemQuantity) 603 | 604 | local orderItemPayout = math.floor(orderItemQuantity * relevantFillType.priceMax * randomPayoutFactor/100)*100 605 | dbPrintf(" ==> Payout = %.2f * %.2f * %.2f = %s", orderItemQuantity, relevantFillType.priceMax, randomPayoutFactor, orderItemPayout) 606 | 607 | -- target station 608 | local orderItemTargetStation = nil 609 | if #relevantFillType.acceptingStations > 0 then 610 | orderItemTargetStation = relevantFillType.acceptingStations[math.random(1, #relevantFillType.acceptingStations)] 611 | dbPrintf(" ==> target station = %s", orderItemTargetStation.owningPlaceable:getName()) 612 | end 613 | 614 | if VIPOrder[relevantFillType.name] ~= nil then 615 | if VIPOrderManager.allowSumQuantitySameFT and not relevantFillType.isAnimal then 616 | -- Summ double entries 617 | VIPOrder[relevantFillType.name].quantity = VIPOrder[relevantFillType.name].quantity + orderItemQuantity/2 618 | VIPOrder[relevantFillType.name].payout = VIPOrder[relevantFillType.name].payout + orderItemPayout/2 619 | dbPrintf(" Double --> Sum order items") 620 | else 621 | i = i - 1 -- try again 622 | dbPrintf(" Double --> discard current order item and try again") 623 | end 624 | else 625 | local orderItemTitle = relevantFillType.title 626 | if relevantFillType.isAnimal then 627 | orderItemTitle = VIPOrderManager:GetAnimalTitleByFillTypeIdx(g_fillTypeManager:getFillTypeIndexByName(relevantFillType.name), orderItemNeededAgeInMonths) 628 | end 629 | 630 | VIPOrder[relevantFillType.name] = {fillTypeName=relevantFillType.name, title=orderItemTitle, quantity=orderItemQuantity, fillLevel=0, payout=orderItemPayout, targetStation=orderItemTargetStation, isAnimal=relevantFillType.isAnimal, neededAgeInMonths=orderItemNeededAgeInMonths} 631 | end 632 | end 633 | end 634 | 635 | 636 | -- animalSubType.sellPrice.keyframes[] 637 | -- [1] = verkaufspreis 638 | -- time = ab alter 639 | function VIPOrderManager:GetAnimalSellPriceByFillTypeIdxAndAge(fillTypeIdx, neededAgeInMonths) 640 | local animalSubType = g_currentMission.animalSystem.fillTypeIndexToSubType[fillTypeIdx] 641 | local animalSellPrice = 0 642 | local animalAge = neededAgeInMonths == nil and 0 or neededAgeInMonths 643 | 644 | for i, sellPriceKeyframe in pairs(animalSubType.sellPrice.keyframes) do 645 | if animalAge >= sellPriceKeyframe.time then 646 | animalSellPrice = sellPriceKeyframe[1] 647 | end 648 | end 649 | return animalSellPrice 650 | end 651 | 652 | -- animalSubType.input.food.keyframes[] 653 | -- [1] = menge futter 654 | -- time = ab alter 655 | function VIPOrderManager:GetAnimalFoodConsumptionPerMonthByFillTypeIdxAndAge(fillTypeIdx, neededAgeInMonths) 656 | local animalSubType = g_currentMission.animalSystem.fillTypeIndexToSubType[fillTypeIdx] 657 | local animalFoodConsumptionPerMonth = 0 658 | local animalAge = neededAgeInMonths == nil and 0 or neededAgeInMonths 659 | 660 | for i, foodKeyframe in pairs(animalSubType.input.food.keyframes) do 661 | if animalAge >= foodKeyframe.time then 662 | animalFoodConsumptionPerMonth = foodKeyframe[1] 663 | end 664 | end 665 | return animalFoodConsumptionPerMonth 666 | end 667 | 668 | 669 | function VIPOrderManager:GetAnimalFoodConsumptionPerMonthStringByFillTypeIdx(fillTypeIdx) 670 | local animalSubType = g_currentMission.animalSystem.fillTypeIndexToSubType[fillTypeIdx] 671 | local animalFoodConsumptionPerMonth = 0 672 | local animalAge = neededAgeInMonths == nil and 0 or neededAgeInMonths 673 | 674 | local output = "Monthly Food Consumption per Age:" 675 | for i, foodKeyframe in pairs(animalSubType.input.food.keyframes) do 676 | local str = string.format("%s->%s | ", foodKeyframe.time, foodKeyframe[1]) 677 | output = output .. str 678 | end 679 | return output 680 | end 681 | 682 | 683 | 684 | function VIPOrderManager:getRandomNeededAgeInMonth(fillTypeName) 685 | local animalSubType = g_currentMission.animalSystem.nameToSubType[fillTypeName] 686 | local maxMinAge = animalSubType.visuals[#animalSubType.visuals].minAge 687 | 688 | local desiredDiff = math.random(VIPOrderManager.rangeAnimalAgeDifInMonths.min, VIPOrderManager.rangeAnimalAgeDifInMonths.max) 689 | return maxMinAge + desiredDiff 690 | end 691 | 692 | 693 | function VIPOrderManager:CalculateOwnFieldArea() 694 | dbPrintHeader("VIPOrderManager:CalculateOwnFieldArea()") 695 | 696 | -- Calculate full farmland 697 | local farmlands = g_farmlandManager:getOwnedFarmlandIdsByFarmId(g_currentMission.player.farmId) 698 | 699 | local fieldAreaOverall = 0.0 700 | for i, id in pairs(farmlands) do 701 | local farmland = g_farmlandManager:getFarmlandById(id) 702 | 703 | -- Fields area 704 | local fieldCount = 0 705 | local fieldAreaSum = 0.0 706 | local fields = g_fieldManager.farmlandIdFieldMapping[farmland.id] 707 | if fields ~= nil then 708 | for fieldIndex, field in pairs(fields) do 709 | fieldCount = fieldCount + 1 710 | fieldAreaSum = fieldAreaSum + field.fieldArea 711 | dbPrintf(" Field: fieldId=%s | name=%s | fieldArea =%s", field.fieldId, field.name, g_i18n:formatArea(field.fieldArea, 2)) 712 | end 713 | end 714 | 715 | if fieldCount > 0 and fieldAreaSum <= 0.01 and farmland.totalFieldArea ~= nil then 716 | dbPrintf(" sum single field sizes to small --> using farmland.totalFieldArea") 717 | fieldAreaSum = farmland.totalFieldArea 718 | end 719 | 720 | fieldAreaOverall = fieldAreaOverall + fieldAreaSum 721 | 722 | dbPrintf(" --> %s. Owned Farmland: id=%s | FieldCount=%s | FieldAreaSum=%s", i, farmland.id, fieldCount, g_i18n:formatArea(fieldAreaSum, 2)) 723 | end 724 | dbPrintf(" ==> Field Area Overall: %s", g_i18n:formatArea(fieldAreaOverall, 2)) 725 | 726 | -- if fieldAreaOverall > 0.01 then 727 | -- return math.ceil(fieldAreaOverall*100)/100 728 | -- else 729 | -- return 0 730 | -- end 731 | 732 | return MyTools:round(fieldAreaOverall, 2) 733 | end 734 | 735 | 736 | function VIPOrderManager:GetFillTypeConfig(possibleFT) 737 | -- dbPrintHeader("VIPOrderManager:GetFillTypeConfig()") 738 | 739 | local ftName = possibleFT.name 740 | local isAnimal = possibleFT.isAnimal 741 | local ftConfig = VIPOrderManager.ftConfigs[ftName] 742 | 743 | if ftConfig == nil then 744 | if g_fruitTypeManager:getFruitTypeByName(ftName) ~= nil and not isAnimal then 745 | ftConfig = VIPOrderManager.ftConfigs["DEFAULT_FRUITTYPE"] 746 | dbInfoPrintf("VIPOrderManager - '%s': fruit type without config. Take config 'DEFAULT_FRUITTYPE'", ftName) 747 | elseif isAnimal then 748 | local configName = "ANIMALTYPE_" .. string.upper(possibleFT.animalTypeName) 749 | if VIPOrderManager.ftConfigs[configName] == nil then 750 | configName = "DEFAULT_ANIMALTYPE" 751 | if possibleFT.animalTypeCount == 1 then -- print only once 752 | dbInfoPrintf("VIPOrderManager - '%s': animal type without config. Take config 'DEFAULT_ANIMALTYPE'", animalTypeName) 753 | end 754 | end 755 | 756 | ftConfig = VIPOrderManager.ftConfigs[configName] 757 | else 758 | ftConfig = VIPOrderManager.ftConfigs["DEFAULT_FILLTYPE"] 759 | dbInfoPrintf("VIPOrderManager - '%s': fill type without config. Take config 'DEFAULT_FILLTYPE'", ftName) 760 | end 761 | 762 | VIPOrderManager.ftConfigs[ftName] = ftConfig 763 | end 764 | 765 | local ftConfigCopy = MyTools:deepcopy(ftConfig) 766 | ftConfigCopy.minOrderLevel = ftConfig.minOrderLevel[1] 767 | ftConfigCopy.probability = ftConfig.probability[1] 768 | ftConfigCopy.msg = {} 769 | 770 | if VIPOrderManager.defaultGroupNameOverwriting[ftName] ~= nil then 771 | ftConfigCopy.groupName = VIPOrderManager.defaultGroupNameOverwriting[ftName] 772 | end 773 | 774 | 775 | -- ftconfig overwrite for minOrderLevel and probability if fitting AnimalHusbandry already exists 776 | if VIPOrderManager.existingAnimalHusbandryOutputs[ftName] and (possibleFT.isUsable == nil or possibleFT.isUsable) then 777 | local existingOrSelfOwnedLevel = VIPOrderManager.existingAnimalHusbandryOutputs[ftName] 778 | 779 | if ftConfig.minOrderLevel ~= nil and ftConfig.minOrderLevel[2] ~= nil and ftConfig.minOrderLevel[3] ~= nil then 780 | local msg 781 | ftConfigCopy.minOrderLevel = ftConfig.minOrderLevel[existingOrSelfOwnedLevel+1] 782 | if existingOrSelfOwnedLevel == 1 then 783 | msg = string.format("Decrease 'minOrderLevel' as animal husbandry already exists but is not owned: %s --> %s", ftConfig.minOrderLevel[1], ftConfigCopy.minOrderLevel) 784 | else 785 | msg = string.format("Decrease 'minOrderLevel' as animal husbandry is already owned: %s --> %s", ftConfig.minOrderLevel[1], ftConfigCopy.minOrderLevel) 786 | end 787 | dbPrintf(" - " .. msg) 788 | table.insert(ftConfigCopy.msg, msg) 789 | end 790 | 791 | if ftConfig.probability ~= nil and ftConfig.probability[2] ~= nil and ftConfig.probability[3] ~= nil then 792 | local msg 793 | ftConfigCopy.probability = ftConfig.probability[existingOrSelfOwnedLevel+1] 794 | if existingOrSelfOwnedLevel == 1 then 795 | msg = string.format("Increase 'Probability' as animal husbandry already exists but is not owned: %s --> %s", ftConfig.probability[1], ftConfigCopy.probability) 796 | else 797 | msg = string.format("Increase 'Probability' as animal husbandry is already owned: %s --> %s", ftConfig.probability[1], ftConfigCopy.probability) 798 | end 799 | dbPrintf(" - " .. msg) 800 | table.insert(ftConfigCopy.msg, msg) 801 | end 802 | end 803 | 804 | -- ftconfig overwrite for minOrderLevel and probability if fitting Production already exists 805 | if VIPOrderManager.existingProductionOutputs[ftName] and ftConfigCopy.msg[1] == nil and (possibleFT.isUsable == nil or possibleFT.isUsable) then 806 | local existingOrSelfOwnedLevel = VIPOrderManager.existingProductionOutputs[ftName] 807 | 808 | if ftConfig.minOrderLevel ~= nil and ftConfig.minOrderLevel[2] ~= nil and ftConfig.minOrderLevel[3] ~= nil then 809 | local msg 810 | ftConfigCopy.minOrderLevel = ftConfig.minOrderLevel[existingOrSelfOwnedLevel+1] 811 | if existingOrSelfOwnedLevel == 1 then 812 | msg = string.format("Decrease 'minOrderLevel' as production already exists but is not owned: %s --> %s", ftConfig.minOrderLevel[1], ftConfigCopy.minOrderLevel) 813 | else 814 | msg = string.format("Decrease 'minOrderLevel' as production is already owned: %s --> %s", ftConfig.minOrderLevel[1], ftConfigCopy.minOrderLevel) 815 | end 816 | dbPrintf(" - " .. msg) 817 | table.insert(ftConfigCopy.msg, msg) 818 | end 819 | 820 | if ftConfig.probability ~= nil and ftConfig.probability[2] ~= nil and ftConfig.probability[3] ~= nil then 821 | local msg 822 | ftConfigCopy.probability = ftConfig.probability[existingOrSelfOwnedLevel+1] 823 | if existingOrSelfOwnedLevel == 1 then 824 | msg = string.format("Increase 'Probability' as production already exists but is not owned: %s --> %s", ftConfig.probability[1], ftConfigCopy.probability) 825 | else 826 | msg = string.format("Increase 'Probability' as production is already owned: %s --> %s", ftConfig.probability[1], ftConfigCopy.probability) 827 | end 828 | dbPrintf(" - " .. msg) 829 | table.insert(ftConfigCopy.msg, msg) 830 | end 831 | end 832 | 833 | -- ftconfig overwrite for quantityCorrectionFactor if FS22_MaizePlus mod is present and loaded 834 | local isMaizePlus = g_modManager:getModByName("FS22_MaizePlus") ~= nil and g_modIsLoaded["FS22_MaizePlus"] 835 | local isTerraLifePlus = g_modManager:getModByName("FS22_TerraLifePlus") ~= nil and g_modIsLoaded["FS22_TerraLifePlus"] and VIPOrderManager:isTerraLife() 836 | if isMaizePlus or isTerraLifePlus then 837 | if ftConfig.quantityCorrectionFactorMaizePlus ~= nil then 838 | ftConfigCopy.quantityCorrectionFactor = ftConfig.quantityCorrectionFactorMaizePlus 839 | local msg = string.format("Overwrite 'quantityCorrectionFactor' as MOD MaizePlus/TerraLifePlus is in use: %s --> %s", ftConfig.quantityCorrectionFactor, ftConfigCopy.quantityCorrectionFactor) 840 | dbPrintf(" - " .. msg) 841 | table.insert(ftConfigCopy.msg, msg) 842 | end 843 | 844 | if ftConfig.probabilityMaizePlus ~= nil then 845 | local msg = string.format("Overwrite 'probability' as MOD MaizePlus/TerraLifePlus is in use: %s --> %s", ftConfigCopy.probability, ftConfig.probabilityMaizePlus) 846 | ftConfigCopy.probability = ftConfig.probabilityMaizePlus 847 | dbPrintf(" - " .. msg) 848 | table.insert(ftConfigCopy.msg, msg) 849 | end 850 | end 851 | 852 | return ftConfigCopy 853 | end 854 | 855 | 856 | function VIPOrderManager:GetRelevantFillTypes(relevantFillTypes) 857 | dbPrintHeader("VIPOrderManager:GetRelevantFillTypes()") 858 | 859 | VIPOrderManager.ownFieldArea = VIPOrderManager:CalculateOwnFieldArea() 860 | VIPOrderManager:GetExistingProductionAndAnimalHusbandryOutputs() 861 | 862 | 863 | local possibleFillTypes = {} 864 | VIPOrderManager:addAllSellableFillTypes(possibleFillTypes) 865 | VIPOrderManager:addAllAnimalFillTypes(possibleFillTypes) 866 | 867 | if dbPrintfOn then 868 | dbPrintf(" Possible filltypes:") 869 | for index, possibleFT in pairs(possibleFillTypes) do 870 | local tempNameOutput = string.format("%s (%s)", possibleFT.name, possibleFT.title) 871 | dbPrintf(" - %-50s: priceMax=%5.3f | pricePerLiter=%5.3f | literPerSqm=%5.3f| Stations=%s", tempNameOutput, possibleFT.priceMax, possibleFT.pricePerLiter, possibleFT.literPerSqm, possibleFT.acceptingStationsString) 872 | end 873 | dbPrintf("") 874 | end 875 | 876 | -- Validate FillTypes 877 | dbPrintf("Validating filltypes:") 878 | for index, possibleFT in pairs(possibleFillTypes) do 879 | dbPrintf(" Validate FillTypes: " .. index .. " --> " .. possibleFT.name .. " (" .. possibleFT.title .. ")") 880 | local notUsableWarning = nil 881 | local tempNameOutput = string.format("%s (%s)", possibleFT.name, possibleFT.title) 882 | local defaultWarningText = string.format(" - %-50s | pricePerLiterMax=%f | ", tempNameOutput, possibleFT.priceMax) 883 | local ftConfig = VIPOrderManager:GetFillTypeConfig(possibleFT) 884 | possibleFT.ftConfig = ftConfig 885 | 886 | -- not allowed 887 | if notUsableWarning == nil and not ftConfig.isAllowed then 888 | notUsableWarning = "Not usable, because is not allowed per definition" 889 | end 890 | 891 | -- not allowed because probability == 0 892 | if notUsableWarning == nil and ftConfig.probability == 0 then 893 | notUsableWarning = "Not usable, because probability = 0" 894 | end 895 | 896 | 897 | -- existing fruittype is not useable 898 | local fruitType = g_fruitTypeManager:getFruitTypeByName(possibleFT.name) 899 | if notUsableWarning == nil and fruitType ~= nil and not fruitType.shownOnMap then 900 | notUsableWarning = string.format("Not usable, because the current map does not support this existing fruittype (not shown on map)") 901 | end 902 | 903 | -- needed original fruit type not available on this map 904 | local neededFruitType = ftConfig.neededFruittype 905 | if notUsableWarning == nil and neededFruitType ~= nil and g_fruitTypeManager:getFruitTypeByName(neededFruitType) == nil then 906 | notUsableWarning = string.format("Not usable, because needed fruittype (%s) is missing", neededFruitType) 907 | end 908 | 909 | -- not sell able 910 | if notUsableWarning == nil and not possibleFT.showOnPriceTable then 911 | notUsableWarning = "Not usable, because not show on price list" 912 | end 913 | 914 | -- without sell price 915 | if notUsableWarning == nil and possibleFT.priceMax <= 0 then 916 | if VIPOrderManager.fillTypesNoPriceList[possibleFT.name] == 1 and possibleFT.pricePerLiter > 0 then 917 | possibleFT.priceMax = possibleFT.pricePerLiter 918 | else 919 | notUsableWarning = "Not usable, because no or negative price per liter defined" 920 | end 921 | end 922 | 923 | possibleFT.isUsable = true 924 | possibleFT.notUsableMsg = "" 925 | if notUsableWarning ~= nil then 926 | dbPrintf(defaultWarningText .. notUsableWarning) 927 | possibleFT.isUsable = false 928 | possibleFT.notUsableMsg = notUsableWarning 929 | end 930 | table.insert(relevantFillTypes, possibleFT) 931 | end 932 | 933 | -- output relevant filltypes 934 | dbPrintf("") 935 | dbPrintf("Relevant filltypes:") 936 | for _, v in pairs(relevantFillTypes) do 937 | local tempNameOutput = string.format("%s (%s)", v.name, v.title) 938 | dbPrintf(" - %-50s | isUsable=%-5s | price=%9s | minOrderLevel=%s | probability=%3s | Stations=%s | ConfigMsg=%s | notUsableMsg=%s", tempNameOutput, v.isUsable, string.format("%.4f", v.priceMax), v.ftConfig.minOrderLevel, v.ftConfig.probability, tostring(v.acceptingStationsString), v.ftConfig.msg, v.notUsableMsg) 939 | end 940 | dbPrintf("") 941 | dbPrintf("") 942 | end 943 | 944 | 945 | function VIPOrderManager:addAllSellableFillTypes(possibleFillTypes) 946 | dbPrintHeader("VIPOrderManager:addAllSellableFillTypes()") 947 | 948 | for _, station in pairs(g_currentMission.storageSystem.unloadingStations) do 949 | local placeable = station.owningPlaceable 950 | local production = placeable.spec_productionPoint 951 | dbPrintf("Station: getName=%s | typeName=%s | categoryName=%s | isSellingPoint=%s | currentSavegameId=%s | placeable.ownerFarmId=%s | g_currentMission:getFarmId()=%s", 952 | placeable:getName(), tostring(placeable.typeName), tostring(placeable.storeItem.categoryName), tostring(station.isSellingPoint), placeable.currentSavegameId, placeable.ownerFarmId, g_currentMission:getFarmId()) 953 | -- PRODUCTIONPOINTS, SILOS, ANIMALPENS 954 | 955 | if station.isSellingPoint ~= nil and station.isSellingPoint == true and (VIPOrderManager.acceptOwnPlaceableProductionPointsAsSellingStation or placeable.ownerFarmId ~= g_currentMission:getFarmId()) then 956 | for fillTypeIndex, isAccepted in pairs(station.acceptedFillTypes) do 957 | local fillType = g_fillTypeManager:getFillTypeByIndex(fillTypeIndex) 958 | 959 | -- accept for own placeable production points only fill types that are not also loadable at the same time 960 | if isAccepted 961 | and placeable.ownerFarmId == g_currentMission:getFarmId() 962 | and production ~= nil 963 | and production.productionPoint.loadingStation ~= nil 964 | and production.productionPoint.loadingStation.supportedFillTypes[fillTypeIndex] then 965 | isAccepted = false 966 | dbPrintf(" - own placeable production point: filltype %s-%s (%s) is not supported as it is also loadable", fillTypeIndex, fillType.name, fillType.title) 967 | end 968 | 969 | if isAccepted == true then 970 | 971 | -- Unknown filltype 972 | local extraMsg = "" 973 | if VIPOrderManager.ftConfigs[fillType.name] == nil then 974 | extraMsg = " *** Unknown filltype without configuration ***" 975 | end 976 | 977 | dbPrintf(" - filltype: %s-%s (%s)%s", fillTypeIndex, fillType.name, fillType.title, extraMsg) 978 | local price = station:getEffectiveFillTypePrice(fillTypeIndex) 979 | 980 | if possibleFillTypes[fillTypeIndex] == nil then 981 | possibleFillTypes[fillTypeIndex] = {} 982 | possibleFillTypes[fillTypeIndex].priceMax = price 983 | possibleFillTypes[fillTypeIndex].acceptingStations = {} 984 | possibleFillTypes[fillTypeIndex].acceptingStationsString ="" 985 | possibleFillTypes[fillTypeIndex].name = fillType.name 986 | possibleFillTypes[fillTypeIndex].title = fillType.title 987 | possibleFillTypes[fillTypeIndex].pricePerLiter = fillType.pricePerLiter 988 | possibleFillTypes[fillTypeIndex].showOnPriceTable = fillType.showOnPriceTable 989 | possibleFillTypes[fillTypeIndex].literPerSqm = g_fruitTypeManager:getFillTypeLiterPerSqm(fillTypeIndex, 0) 990 | possibleFillTypes[fillTypeIndex].isFruitType = g_fruitTypeManager:getFruitTypeByName(fillType.name) ~= nil 991 | else 992 | if price > possibleFillTypes[fillTypeIndex].priceMax then 993 | possibleFillTypes[fillTypeIndex].priceMax = price 994 | end 995 | end 996 | 997 | -- append station to station list and to stationString 998 | table.insert(possibleFillTypes[fillTypeIndex].acceptingStations, station) 999 | if possibleFillTypes[fillTypeIndex].acceptingStationsString ~= "" then 1000 | possibleFillTypes[fillTypeIndex].acceptingStationsString = possibleFillTypes[fillTypeIndex].acceptingStationsString .. ", " 1001 | end 1002 | possibleFillTypes[fillTypeIndex].acceptingStationsString = possibleFillTypes[fillTypeIndex].acceptingStationsString .. station.owningPlaceable:getName() 1003 | end 1004 | end 1005 | else 1006 | dbPrintf(" - Station not relevant: Name=%s | isSellingPoint=%s | placeable.ownerFarmId=%s", placeable:getName(), station.isSellingPoint, placeable.ownerFarmId) 1007 | end 1008 | end 1009 | return possibleFillTypes 1010 | end 1011 | 1012 | 1013 | function VIPOrderManager:addAllAnimalFillTypes(possibleFillTypes) 1014 | dbPrintHeader("VIPOrderManager:addAllAnimalFillTypes()") 1015 | 1016 | local animalTypeIndexes = {} 1017 | 1018 | for i, fillTypeIdx in pairs(g_fillTypeManager:getFillTypesByCategoryNames("ANIMAL HORSE")) do 1019 | local fillType = g_fillTypeManager:getFillTypeByIndex(fillTypeIdx) 1020 | local animalSubType = g_currentMission.animalSystem.fillTypeIndexToSubType[fillTypeIdx] 1021 | if animalSubType == nil then 1022 | dbPrintf("VIPOrderManager:addAllAnimalFillTypes warning: animal filltype without animalSubType: %s-%s (%s)",fillTypeIdx, fillType.name, fillType.title) 1023 | else 1024 | local animalStoreTitle = VIPOrderManager:GetAnimalTitleByFillTypeIdx(fillTypeIdx) 1025 | 1026 | -- get animal species 1027 | local animalType = g_currentMission.animalSystem:getTypeByIndex(animalSubType.typeIndex) 1028 | local animalTypeName = animalType.name 1029 | 1030 | 1031 | -- print("** Start DebugUtil.printTableRecursively() ************************************************************") 1032 | -- print("fillType:") 1033 | -- DebugUtil.printTableRecursively(fillType, ".", 0, 3) 1034 | -- print("** End DebugUtil.printTableRecursively() **************************************************************") 1035 | 1036 | -- print("** Start DebugUtil.printTableRecursively() ************************************************************") 1037 | -- print("g_currentMission.animalSystem:") 1038 | -- DebugUtil.printTableRecursively(g_currentMission.animalSystem, ".", 0, 1) 1039 | -- print("** End DebugUtil.printTableRecursively() **************************************************************") 1040 | 1041 | -- printf("FillType: %s (%s) - animalTypeIndex=%s | MinBuyPrice=%s", fillType.name, fillType.title, animalSubType.typeIndex, animalSubType.buyPrice.keyframes[1][1]) 1042 | -- for ii, visual in pairs(animalSubType.visuals) do 1043 | -- printf(" - canBeBought=%s | minAge=%s | name=%s", visual.store.canBeBought, visual.minAge, visual.store.name) 1044 | -- end 1045 | 1046 | -- Unknown filltype 1047 | local extraMsg = "" 1048 | if VIPOrderManager.ftConfigs[fillType.name] == nil then 1049 | extraMsg = " *** Unknown filltype without configuration ***" 1050 | end 1051 | 1052 | dbPrintf(" - filltype: %s-%s (%s) %s", fillTypeIdx, fillType.name, animalStoreTitle, extraMsg) 1053 | -- local price = animalSubType.buyPrice.keyframes[1][1] 1054 | local price = math.floor(math.random(VIPOrderManager.rangeAnimalDummyPrice.min, VIPOrderManager.rangeAnimalDummyPrice.max)) 1055 | 1056 | if possibleFillTypes[fillTypeIdx] == nil then 1057 | possibleFillTypes[fillTypeIdx] = {} 1058 | else 1059 | dbPrintf("VIPOrderManager:addAllAnimalFillTypes warning: animal filltype already exists: %s-%s (%s)", fillTypeIdx, fillType.name, animalStoreTitle) 1060 | end 1061 | possibleFillTypes[fillTypeIdx].priceMax = price 1062 | possibleFillTypes[fillTypeIdx].acceptingStations = {} 1063 | possibleFillTypes[fillTypeIdx].name = fillType.name 1064 | possibleFillTypes[fillTypeIdx].title = animalStoreTitle 1065 | possibleFillTypes[fillTypeIdx].pricePerLiter = fillType.pricePerLiter 1066 | possibleFillTypes[fillTypeIdx].showOnPriceTable = true 1067 | possibleFillTypes[fillTypeIdx].literPerSqm = 0 1068 | -- only for animals 1069 | possibleFillTypes[fillTypeIdx].isAnimal = true 1070 | possibleFillTypes[fillTypeIdx].animalTypeIndex = animalSubType.typeIndex 1071 | possibleFillTypes[fillTypeIdx].animalTypeName = animalTypeName 1072 | 1073 | -- count animal subtypes 1074 | if animalTypeIndexes[animalSubType.typeIndex] == nil then 1075 | animalTypeIndexes[animalSubType.typeIndex] = 1 1076 | else 1077 | animalTypeIndexes[animalSubType.typeIndex] = animalTypeIndexes[animalSubType.typeIndex] + 1 1078 | end 1079 | possibleFillTypes[fillTypeIdx].animalTypeCount = animalTypeIndexes[animalSubType.typeIndex] 1080 | end 1081 | end 1082 | end 1083 | 1084 | 1085 | function VIPOrderManager:ShowCurrentVIPOrder() 1086 | dbPrintHeader("VIPOrderManager:ShowCurrentVIPOrder()") 1087 | 1088 | -- dbPrintf(" current showVIPOrder=%s | new showVIPOrder=%s", VIPOrderManager.showVIPOrder, (VIPOrderManager.showVIPOrder + 1) % 4) 1089 | 1090 | VIPOrderManager.showVIPOrder = (VIPOrderManager.showVIPOrder + 1) % 3 -- only 0, 1 or 2 1091 | if VIPOrderManager.showVIPOrder > 0 then 1092 | VIPOrderManager:UpdateOutputLines(); 1093 | end 1094 | VIPOrderManager.infoDisplayPastTime = 0 1095 | end 1096 | 1097 | 1098 | function VIPOrderManager:GetPayoutTotal(orderEntries) 1099 | dbPrintHeader("VIPOrderManager:GetPayoutTotal()") 1100 | 1101 | local payoutTotal = 0 1102 | for _, entry in pairs(orderEntries) do 1103 | payoutTotal = payoutTotal + entry.payout 1104 | end 1105 | return payoutTotal 1106 | end 1107 | 1108 | -- return: boolean, IsOrderCompleted 1109 | function VIPOrderManager:UpdateOutputLines() 1110 | -- dbPrintHeader("VIPOrderManager:UpdateOutputLines()") 1111 | 1112 | if #VIPOrderManager.VIPOrders < 2 then 1113 | return 1114 | end 1115 | 1116 | local posX = VIPOrderManager.outputStartPoint.x 1117 | local posY = VIPOrderManager.outputStartPoint.y 1118 | local fontSize = VIPOrderManager.outputFontSize 1119 | local isOrderCompleted = true 1120 | local payoutTotal = 0 1121 | VIPOrderManager.outputLines = {} -- Output lines for the draw() function (text, size, bold, colorId, x, y) 1122 | 1123 | local title = g_i18n:getText("VIPOrderManager_CurrentVIPOrder") 1124 | local VIPOrder = VIPOrderManager.VIPOrders[1] 1125 | 1126 | if VIPOrderManager.showVIPOrder == 2 then 1127 | VIPOrder = VIPOrderManager.VIPOrders[2] 1128 | title = g_i18n:getText("VIPOrderManager_NextVIPOrder") 1129 | end 1130 | local level = VIPOrder.level 1131 | 1132 | -- calculate max text widths 1133 | -- local maxTitelTextWidth = 0 1134 | -- local maxQuantityTextWidth = 0 1135 | -- for _, vipOrderEntry in pairs(VIPOrder) do 1136 | -- local fillTypeTitle = vipOrderEntry.title 1137 | -- local titelTextWidth = getTextWidth(fontSize, " " .. fillTypeTitle .. " ") 1138 | -- local requiredQuantity = vipOrderEntry.quantity - math.ceil(vipOrderEntry.fillLevel) 1139 | -- local quantityTextWidth = getTextWidth(fontSize, g_i18n:formatNumber(requiredQuantity, 0)) 1140 | 1141 | -- if titelTextWidth > maxTitelTextWidth then 1142 | -- maxTitelTextWidth = titelTextWidth 1143 | -- end 1144 | 1145 | -- if quantityTextWidth > maxQuantityTextWidth then 1146 | -- maxQuantityTextWidth = quantityTextWidth 1147 | -- end 1148 | -- end 1149 | local headerLine = string.format("%s (Level: %s):", title, level) 1150 | table.insert(VIPOrderManager.outputLines, {text = headerLine, size = fontSize, bold = true, align=RenderText.ALIGN_LEFT, colorId = 7, x = posX, y = posY}) 1151 | posY = posY - fontSize 1152 | 1153 | local maxTextWidth = getTextWidth(fontSize, headerLine) + 0.005 1154 | local posXIncrease = getTextWidth(fontSize, " 999.999 ") 1155 | 1156 | for _, vipOrderEntry in pairs(VIPOrder.entries) do 1157 | local fillTypeTitle = vipOrderEntry.title 1158 | local requiredQuantity = vipOrderEntry.quantity - math.ceil(vipOrderEntry.fillLevel) 1159 | 1160 | local line = string.format(" %s ", g_i18n:formatNumber(requiredQuantity, 0)) 1161 | local fillLevelColor = 7; 1162 | if requiredQuantity <= 0 then 1163 | fillLevelColor = 6 1164 | end 1165 | table.insert(VIPOrderManager.outputLines, {text = line, size = fontSize, bold = false, align=RenderText.ALIGN_RIGHT, colorId = fillLevelColor, x = posX + posXIncrease, y = posY}) 1166 | 1167 | local line = string.format(" %s", fillTypeTitle) 1168 | if vipOrderEntry.targetStation ~= nil then 1169 | line = line .. " --> " .. vipOrderEntry.targetStation.owningPlaceable:getName() 1170 | end 1171 | table.insert(VIPOrderManager.outputLines, {text = line, size = fontSize, bold = false, align=RenderText.ALIGN_LEFT, colorId = fillLevelColor, x = posX + posXIncrease, y = posY}) 1172 | posY = posY - fontSize 1173 | local textWidth = getTextWidth(fontSize, line) 1174 | if (textWidth + posXIncrease > maxTextWidth) then 1175 | maxTextWidth = textWidth + posXIncrease 1176 | end 1177 | 1178 | isOrderCompleted = isOrderCompleted and requiredQuantity <= 0 1179 | payoutTotal = payoutTotal + vipOrderEntry.payout 1180 | end 1181 | 1182 | local line = string.format(g_i18n:getText("VIPOrderManager_Payout"), g_i18n:formatMoney(payoutTotal, 0, true)) --, false)) -- g_i18n:formatMoney(value, bool Währung ausgeben, bool Währung vor dem Betrag?) 1183 | table.insert(VIPOrderManager.outputLines, {text = line, size = fontSize, bold = true, align=RenderText.ALIGN_LEFT, colorId = 7, x = posX, y = posY}) 1184 | posY = posY - fontSize 1185 | 1186 | if infoHud ~= nil then 1187 | infoHud:setPosition(VIPOrderManager.outputStartPoint.x - 0.005, VIPOrderManager.outputStartPoint.y + 0.005 + fontSize) 1188 | infoHud:setDimension(maxTextWidth + 0.01, VIPOrderManager.outputStartPoint.y - posY + fontSize) 1189 | end 1190 | 1191 | return isOrderCompleted and MyTools:getCountElements(VIPOrder.entries) > 0 1192 | end 1193 | 1194 | 1195 | function VIPOrderManager:MakePayout(orderEntries) 1196 | dbPrintHeader("VIPOrderManager:MakePayout()") 1197 | 1198 | playSample(VIPOrderManager.successSound ,1 ,1 ,1 ,0 ,0) 1199 | 1200 | -- show message 1201 | g_currentMission:addIngameNotification(FSBaseMission.INGAME_NOTIFICATION_OK, g_i18n:getText("VIPOrderManager_OrderCompleted")) 1202 | 1203 | -- Pay out profit 1204 | local payoutTotal = VIPOrderManager:GetPayoutTotal(orderEntries) 1205 | g_currentMission:addMoney(payoutTotal, g_currentMission.player.farmId, MoneyType.MISSIONS, true, true); 1206 | end 1207 | 1208 | 1209 | function VIPOrderManager:update(dt) 1210 | -- dbPrintHeader("VIPOrderManager:update()") 1211 | 1212 | VIPOrderManager.updateDelta = VIPOrderManager.updateDelta + dt; 1213 | VIPOrderManager.infoDisplayPastTime = VIPOrderManager.infoDisplayPastTime + dt 1214 | 1215 | if VIPOrderManager.updateDelta > VIPOrderManager.updateRate and VIPOrderManager.InitDone then 1216 | VIPOrderManager.updateDelta = 0; 1217 | 1218 | if VIPOrderManager.infoDisplayPastTime > VIPOrderManager.infoDisplayMaxShowTime then 1219 | VIPOrderManager.showVIPOrder = 0; 1220 | VIPOrderManager.infoDisplayPastTime = 0 1221 | end 1222 | 1223 | if g_currentMission:getIsClient() and g_gui.currentGui == nil and g_currentMission.player.farmId > 0 then 1224 | local isOrderCompleted = VIPOrderManager:UpdateOutputLines() 1225 | if isOrderCompleted then 1226 | VIPOrderManager:MakePayout(VIPOrderManager.VIPOrders[1].entries) 1227 | table.remove(VIPOrderManager.VIPOrders, 1) 1228 | end 1229 | if #VIPOrderManager.VIPOrders < VIPOrderManager.maxVIPOrdersCount then 1230 | VIPOrderManager:RestockVIPOrders() 1231 | end 1232 | end 1233 | end 1234 | 1235 | if infoHud ~= nil then 1236 | if #VIPOrderManager.VIPOrders > 0 and #VIPOrderManager.outputLines > 0 then 1237 | infoHud:setVisible(VIPOrderManager.showVIPOrder > 0) 1238 | else 1239 | infoHud:setVisible(false) 1240 | end 1241 | end 1242 | end 1243 | 1244 | 1245 | function VIPOrderManager:draw() 1246 | -- dbPrintHeader("VIPOrderManager:draw()") 1247 | 1248 | -- Only render when no other GUI is open 1249 | if g_gui.currentGuiName ~= "InGameMenu" and VIPOrderManager.showVIPOrder > 0 and VIPOrderManager.InitDone then --if g_gui.currentGui == nil 1250 | for _, line in ipairs(VIPOrderManager.outputLines) do 1251 | VIPOrderManager:renderText(line.x, line.y, line.size, line.text, line.bold, line.colorId, line.align) 1252 | end; 1253 | end 1254 | 1255 | if infoHud ~= nil then 1256 | infoHud:draw() 1257 | end 1258 | end 1259 | 1260 | 1261 | function VIPOrderManager:renderText(x, y, size, text, bold, colorId, align) 1262 | -- dbPrintHeader("VIPOrderManager:renderText()") 1263 | 1264 | setTextColor(table.unpack(VIPOrderManager.colors[colorId][2])) 1265 | setTextBold(bold) 1266 | setTextAlignment(align) 1267 | renderText(x, y, size, text) 1268 | 1269 | -- Back to defaults 1270 | setTextBold(false) 1271 | setTextColor(table.unpack(VIPOrderManager.colors[1][2])) --Back to default color which is white 1272 | setTextAlignment(RenderText.ALIGN_LEFT) 1273 | end 1274 | 1275 | 1276 | function VIPOrderManager:saveSettings() 1277 | dbPrintHeader("VIPOrderManager:saveSettings()") 1278 | 1279 | local savegameFolderPath = g_currentMission.missionInfo.savegameDirectory.."/"; 1280 | if savegameFolderPath == nil then 1281 | savegameFolderPath = ('%ssavegame%d'):format(getUserProfileAppPath(), g_currentMission.missionInfo.savegameIndex.."/"); 1282 | end; 1283 | local key = "VIPOrderManager"; 1284 | local storePlace = g_currentMission.storeSpawnPlaces[1]; 1285 | local xmlFile = createXMLFile(key, savegameFolderPath.."VIPOrderManager.xml", key); 1286 | -- setXMLString(xmlFile, key.."#XMLFileVersion", "1.0"); 1287 | setXMLString(xmlFile, key.."#XMLFileVersion", "2.0"); 1288 | 1289 | local settingKey = string.format("%s.Settings", key) 1290 | -- setXMLInt(xmlFile, key.."#orderLevel", VIPOrderManager.currentOrderLevel); 1291 | setXMLInt(xmlFile, settingKey..".maxVIPOrdersCount", VIPOrderManager.maxVIPOrdersCount) 1292 | setXMLBool(xmlFile, settingKey..".isAnimalOrdersWished", VIPOrderManager.isAnimalOrdersWished) 1293 | setXMLInt(xmlFile, settingKey..".countOrderItemsRange#Min", VIPOrderManager.countOrderItemsRange.min) 1294 | setXMLInt(xmlFile, settingKey..".countOrderItemsRange#Max", VIPOrderManager.countOrderItemsRange.max) 1295 | setXMLInt(xmlFile, settingKey..".quantityFactor#Min", VIPOrderManager.quantityFactor.min) 1296 | setXMLInt(xmlFile, settingKey..".quantityFactor#Max", VIPOrderManager.quantityFactor.max) 1297 | setXMLInt(xmlFile, settingKey..".payoutFactor#Min", VIPOrderManager.payoutFactor.min) 1298 | setXMLInt(xmlFile, settingKey..".payoutFactor#Max", VIPOrderManager.payoutFactor.max) 1299 | 1300 | local iOrder = 0 1301 | for _, vipOrder in pairs(VIPOrderManager.VIPOrders) do 1302 | local orderKey = string.format("%s.VIPOrders.VIPOrder(%d)", key, iOrder) 1303 | setXMLInt(xmlFile, orderKey.."#level", vipOrder.level) 1304 | 1305 | local iEntry = 0 1306 | for _, orderEntry in pairs(vipOrder.entries) do 1307 | local entryKey = string.format("%s.entry(%d)", orderKey, iEntry) 1308 | setXMLString(xmlFile, entryKey.."#fillTypeName", orderEntry.fillTypeName) 1309 | setXMLInt(xmlFile, entryKey.."#quantity", orderEntry.quantity) 1310 | setXMLInt(xmlFile, entryKey.."#fillLevel", math.ceil(orderEntry.fillLevel)) 1311 | setXMLInt(xmlFile, entryKey.."#payout", orderEntry.payout) 1312 | 1313 | setXMLString(xmlFile, entryKey.."#fillTypeTitle_OnlyAsInfo", orderEntry.title) 1314 | if orderEntry.targetStation ~= nil then 1315 | setXMLInt(xmlFile, entryKey.."#targetStationSavegameId", orderEntry.targetStation.owningPlaceable.currentSavegameId) 1316 | setXMLString(xmlFile, entryKey.."#targetStationName_OnlyAsInfo", orderEntry.targetStation.owningPlaceable:getName()) 1317 | end 1318 | 1319 | -- for animal 1320 | if orderEntry.isAnimal then 1321 | setXMLBool(xmlFile, entryKey.."#isAnimal", orderEntry.isAnimal) 1322 | setXMLInt(xmlFile, entryKey.."#neededAgeInMonths", orderEntry.neededAgeInMonths) 1323 | end 1324 | 1325 | iEntry = iEntry + 1 1326 | end 1327 | iOrder = iOrder + 1 1328 | end 1329 | saveXMLFile(xmlFile); 1330 | delete(xmlFile); 1331 | end 1332 | 1333 | function VIPOrderManager:loadSettings() 1334 | dbPrintHeader("VIPOrderManager:loadSettings()") 1335 | 1336 | local savegameFolderPath = g_currentMission.missionInfo.savegameDirectory 1337 | if savegameFolderPath == nil then 1338 | savegameFolderPath = ('%ssavegame%d'):format(getUserProfileAppPath(), g_currentMission.missionInfo.savegameIndex) 1339 | end; 1340 | savegameFolderPath = savegameFolderPath.."/" 1341 | local key = "VIPOrderManager" 1342 | 1343 | if fileExists(savegameFolderPath.."VIPOrderManager.xml") then 1344 | local xmlFile = loadXMLFile(key, savegameFolderPath.."VIPOrderManager.xml") 1345 | 1346 | local XMLFileVersion = getXMLString(xmlFile, key.."#XMLFileVersion") 1347 | 1348 | if XMLFileVersion == "2.0" then 1349 | local settingKey = string.format("%s.Settings", key) 1350 | VIPOrderManager.maxVIPOrdersCount = Utils.getNoNil(getXMLInt(xmlFile, settingKey..".maxVIPOrdersCount"), VIPOrderManager.maxVIPOrdersCount) 1351 | VIPOrderManager.isAnimalOrdersWished = Utils.getNoNil(getXMLBool(xmlFile, settingKey..".isAnimalOrdersWished"), VIPOrderManager.isAnimalOrdersWished) 1352 | 1353 | VIPOrderManager.countOrderItemsRange.min = Utils.getNoNil(getXMLInt(xmlFile, settingKey..".countOrderItemsRange#Min"), VIPOrderManager.countOrderItemsRange.min) 1354 | VIPOrderManager.countOrderItemsRange.max = Utils.getNoNil(getXMLInt(xmlFile, settingKey..".countOrderItemsRange#Max"), VIPOrderManager.countOrderItemsRange.max) 1355 | VIPOrderManager.quantityFactor.min = Utils.getNoNil(getXMLInt(xmlFile, settingKey..".quantityFactor#Min"), VIPOrderManager.quantityFactor.min) 1356 | VIPOrderManager.quantityFactor.max = Utils.getNoNil(getXMLInt(xmlFile, settingKey..".quantityFactor#Max"), VIPOrderManager.quantityFactor.max) 1357 | VIPOrderManager.payoutFactor.min = Utils.getNoNil(getXMLInt(xmlFile, settingKey..".payoutFactor#Min"), VIPOrderManager.payoutFactor.min) 1358 | VIPOrderManager.payoutFactor.max = Utils.getNoNil(getXMLInt(xmlFile, settingKey..".payoutFactor#Max"), VIPOrderManager.payoutFactor.max) 1359 | 1360 | local iOrder = 0 1361 | while true do 1362 | local orderKey = string.format("%s.VIPOrders.VIPOrder(%d)", key, iOrder) 1363 | if hasXMLProperty(xmlFile, orderKey) then 1364 | local vipOrder = {level=nil, entries={}} 1365 | local level = getXMLInt(xmlFile, orderKey.."#level") 1366 | vipOrder.level = level 1367 | 1368 | local iEntry = 0 1369 | while true do 1370 | local entryKey = string.format("%s.entry(%d)", orderKey, iEntry) 1371 | if hasXMLProperty(xmlFile, entryKey) then 1372 | local error = false 1373 | local fillTypeName = getXMLString(xmlFile, entryKey.."#fillTypeName") 1374 | local quantity = getXMLInt(xmlFile, entryKey.."#quantity") 1375 | local fillLevel = Utils.getNoNil(getXMLInt(xmlFile, entryKey.."#fillLevel"), 0) 1376 | local payout = getXMLInt(xmlFile, entryKey.."#payout") 1377 | 1378 | -- for animal 1379 | local isAnimal = getXMLBool(xmlFile, entryKey.."#isAnimal") 1380 | local neededAgeInMonths = getXMLInt(xmlFile, entryKey.."#neededAgeInMonths") 1381 | 1382 | local targetStationSavegameId = getXMLInt(xmlFile, entryKey.."#targetStationSavegameId") 1383 | local targetStationName = getXMLString(xmlFile, entryKey.."#targetStationName_OnlyAsInfo") 1384 | -- dbPrintf("loadSettings: %s | %s", targetStationSavegameId, targetStationName) 1385 | local targetStation = VIPOrderManager:getStationBySavegameId(targetStationSavegameId) 1386 | 1387 | -- check if target station still exists 1388 | if targetStationName ~= nil and targetStation == nil then 1389 | print(string.format("VIPOrderManager: Warning, the target station \"%s\" no longer exists", targetStationName)) 1390 | end 1391 | -- check if filltype still exists 1392 | local fillType = g_fillTypeManager:getFillTypeByName(fillTypeName) 1393 | if fillType == nil then 1394 | error = true 1395 | print(string.format("VIPOrderManager: Warning, the filltype \"%s\" no longer exists", fillTypeName)) 1396 | else 1397 | local ftTitle 1398 | if isAnimal then 1399 | ftTitle = VIPOrderManager:GetAnimalTitleByFillTypeIdx(fillType.index, neededAgeInMonths) 1400 | else 1401 | ftTitle = fillType.title 1402 | end 1403 | vipOrder.entries[fillTypeName] = {fillTypeName=fillTypeName, title=ftTitle, quantity=quantity, fillLevel=fillLevel, payout=payout, targetStation=targetStation, isAnimal=isAnimal, neededAgeInMonths=neededAgeInMonths} 1404 | end 1405 | iEntry = iEntry + 1 1406 | else 1407 | break 1408 | end 1409 | end 1410 | table.insert(VIPOrderManager.VIPOrders, vipOrder) 1411 | iOrder = iOrder + 1 1412 | else 1413 | break 1414 | end 1415 | end 1416 | end 1417 | 1418 | delete(xmlFile); 1419 | end; 1420 | 1421 | VIPOrderManager.InitDone = true 1422 | return VIPOrderManager.isLoaded; 1423 | end 1424 | 1425 | 1426 | function VIPOrderManager:getStationBySavegameId(targetStationSavegameId) 1427 | dbPrintHeader("VIPOrderManager:getStationBySavegameId()") 1428 | 1429 | for _, station in pairs(g_currentMission.storageSystem.unloadingStations) do 1430 | if station.owningPlaceable ~= nil and station.owningPlaceable.currentSavegameId == targetStationSavegameId then 1431 | return station 1432 | end 1433 | end 1434 | return nil 1435 | end 1436 | 1437 | 1438 | function VIPOrderManager:GetAnimalTitleByFillTypeIdx(fillTypeIdx, neededAgeInMonths) 1439 | local animalSubType = g_currentMission.animalSystem.fillTypeIndexToSubType[fillTypeIdx] 1440 | local animalStoreTitle = "Unknown animal title" 1441 | local animalAge = neededAgeInMonths == nil and 0 or neededAgeInMonths 1442 | 1443 | for i, visual in pairs(animalSubType.visuals) do 1444 | if animalAge >= visual.minAge then 1445 | animalStoreTitle = visual.store.name 1446 | end 1447 | end 1448 | 1449 | if neededAgeInMonths ~= nil then 1450 | animalStoreTitle = animalStoreTitle .. string.format(" (%s %s)", neededAgeInMonths, g_i18n:getText("VIPOrderManager_Months")) 1451 | end 1452 | 1453 | return animalStoreTitle 1454 | end 1455 | 1456 | 1457 | -- Observe "SellingStation.addFillLevelFromTool" when products are sold at points of sale 1458 | function VIPOrderManager.sellingStation_addFillLevelFromTool(station, superFunc, farmId, deltaFillLevel, fillType, fillInfo, toolType) 1459 | dbPrintHeader("VIPOrderManager:sellingStation_addFillLevelFromTool()") 1460 | 1461 | local moved = 0 1462 | moved = superFunc(station, farmId, deltaFillLevel, fillType, fillInfo, toolType) 1463 | 1464 | local ft = g_fillTypeManager:getFillTypeByIndex(fillType) 1465 | local stationCategoryName = "" 1466 | if station.owningPlaceable ~= nil and station.owningPlaceable.storeItem ~= nil then 1467 | stationCategoryName = station.owningPlaceable.storeItem.categoryName 1468 | end 1469 | -- dbPrintf(" stationCategoryName=%s | moved=%s | deltaFillLevel=%s | ftName=%s (%s) | ftIndex=%s | toolType=%s", tostring(stationCategoryName), tostring(moved), tostring(deltaFillLevel), ft.name, ft.title, tostring(fillType), tostring(toolType)) 1470 | 1471 | if moved > 0 and VIPOrderManager.VIPOrders ~= nil and VIPOrderManager.VIPOrders[1] ~= nil then 1472 | local orderEntry = VIPOrderManager.VIPOrders[1].entries[ft.name] 1473 | -- dbPrintf(" Anzahl Order Items=%s", TyTools:getCountElements(VIPOrderManager.currentVIPOrder)) 1474 | if orderEntry ~= nil then 1475 | if orderEntry.targetStation == nil or orderEntry.targetStation == station then 1476 | orderEntry.fillLevel = math.min(orderEntry.fillLevel + moved, orderEntry.quantity) 1477 | VIPOrderManager.showVIPOrder = 1; 1478 | VIPOrderManager.infoDisplayPastTime = 0 1479 | VIPOrderManager:UpdateOutputLines() 1480 | end 1481 | end 1482 | end 1483 | 1484 | return moved 1485 | end 1486 | 1487 | 1488 | function VIPOrderManager:isTerraLife() 1489 | local mapDirectory = g_mpLoadingScreen.missionInfo.map.baseDirectory 1490 | if mapDirectory == "" then 1491 | --wenn mapDirectory leer ist, handelt es sich um die Basemaps 1492 | return false 1493 | elseif fileExists(mapDirectory .. "dlcDesc.xml") then 1494 | --wenn dlcDesc existiert, handelt es sich um DLC-Map 1495 | return false 1496 | else 1497 | local path = mapDirectory .. "modDesc.xml" 1498 | local xmlFile = XMLFile.load("TempDesc", path) 1499 | if xmlFile:hasProperty("moddesc.terraLife") then 1500 | return true 1501 | else 1502 | return false 1503 | end 1504 | xmlFile:delete() 1505 | end 1506 | end 1507 | 1508 | 1509 | function VIPOrderManager:onLoad(savegame)end; 1510 | function VIPOrderManager:onUpdate(dt)end; 1511 | function VIPOrderManager:deleteMap()end; 1512 | function VIPOrderManager:keyEvent(unicode, sym, modifier, isDown)end; 1513 | function VIPOrderManager:mouseEvent(posX, posY, isDown, isUp, button)end; 1514 | 1515 | addModEventListener(VIPOrderManager); 1516 | 1517 | 1518 | --------------------------------------------------------------------------------