-
Notifications
You must be signed in to change notification settings - Fork 6
/
chaffMission.lua
314 lines (272 loc) · 11.2 KB
/
chaffMission.lua
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
--=======================================================================================================
-- SCRIPT
--
-- Purpose: Forage contracts.
-- Author: Mmtrx
-- Changelog:
-- v1.0.0.0 01.08.2023 initial
-- v1.0.1.0 14.10.2023 handle fillTypeCategories in selling stations (#3). Allow choppedmaize /Maize+ (#2)
-- v1.0.1.1 15.10.2023 fix MP sync (#3). Russian translation (#5)
-- v1.0.2.0 16.10.2023 adequate sellpoints (#11)
-- v1.0.3.0 04.11.2023 mow header for grain chaff missions, lowered reward/ha,
-- lower prob on forage-ready fields (#16)
--
-- Attribution modIcon harvester from <a href="https://www.freepik.com">Image by macrovector</a>
--=======================================================================================================
ChaffMission = {
debug = true,
maizeplus = false,
REWARD_PER_HA = 2500,
SUCCESS_FACTOR = 0.90,
PROBABILITY = 0.5
}
function debugPrint(text, ...)
if ChaffMission.debug then
Logging.info(text,...)
end
end
local ChaffMission_mt = Class(ChaffMission, HarvestMission)
InitObjectClass(ChaffMission, "ChaffMission")
function ChaffMission.new(isServer, isClient, customMt)
local self = HarvestMission.new(isServer, isClient, customMt or ChaffMission_mt)
self.workAreaTypes = {
[WorkAreaType.CUTTER] = true,
}
self.rewardPerHa = ChaffMission.REWARD_PER_HA
return self
end
function ChaffMission:loadFromXMLFile(xmlFile, key)
if not ChaffMission:superClass().loadFromXMLFile(self, xmlFile, key) then
return false
end
self.orgFillType = self.fillType
self.fillType = FillType.CHAFF
if ChaffMission.maizeplus and self.orgFillType == FillType.MAIZE then
self.fillType = FillType.CHOPPEDMAIZE
end
return true
end
function ChaffMission:writeStream(streamId, connection)
ChaffMission:superClass().writeStream(self, streamId, connection)
streamWriteUIntN(streamId, self.orgFillType, FillTypeManager.SEND_NUM_BITS)
end
function ChaffMission:readStream(streamId, connection)
ChaffMission:superClass().readStream(self, streamId, connection)
self.orgFillType = streamReadUIntN(streamId, FillTypeManager.SEND_NUM_BITS)
end
function ChaffMission:init(field, ...)
local fruitDesc = g_fruitTypeManager:getFruitTypeByIndex(field.fruitType)
self.orgFillType = fruitDesc.fillType.index
self.fillType = FillType.CHAFF
if ChaffMission.maizeplus and self.orgFillType == FillType.MAIZE then
self.fillType = FillType.CHOPPEDMAIZE
end
if not HarvestMission:superClass().init(self, field, ...) then
return false
end
self.depositedLiters = 0
-- multiply expected by fruit converter:
local converter = g_fruitTypeManager:getConverterDataByName("forageHarvester")
local factor = converter[field.fruitType].conversionFactor
self.expectedLiters = factor * self:getMaxCutLiters()
self.sellPoint = self:getHighestSellPointPrice()
if self.sellPoint == nil then
return false
end
return true
end
function ChaffMission.canRunOnField(field, sprayFactor, fieldSpraySet, fieldPlowFactor, limeFactor, maxWeedState, stubbleFactor, rollerFactor)
-- check for forage fruit
local fruitType = field.fruitType
if not table.hasElement(g_fruitTypeManager:getFruitTypesByCategoryNames("MAIZECUTTER"), fruitType) then
return false
end
-- mission can run if growth is in "forage harvest ready" (usually minGrowthState -1), or between min / maxHarvestState
local maxGrowthState = FieldUtil.getMaxGrowthState(field, fruitType)
local maxHarvestState = FieldUtil.getMaxHarvestState(field, fruitType)
if maxGrowthState == nil then -- fruitType not found
return false
end
local fruitDesc = g_fruitTypeManager:getFruitTypeByIndex(fruitType)
if maxGrowthState == fruitDesc.minForageGrowthState and math.random() < ChaffMission.PROBABILITY then
return true, FieldManager.FIELDSTATE_GROWING, maxGrowthState
elseif maxHarvestState ~= nil and math.random() < ChaffMission.PROBABILITY then -- leave some fields for harvest missions
return true, FieldManager.FIELDSTATE_GROWING, maxHarvestState
end
return false
end
function ChaffMission:getData()
if self.sellPointId ~= nil then
self:tryToResolveSellPoint()
end
local name = "Unknown"
if self.sellPoint ~= nil then
name = self.sellPoint:getName()
end
return {
location = string.format(g_i18n:getText("fieldJob_number"), self.field.fieldId),
jobType = g_i18n:getText("fieldJob_jobType_forage"),
action = g_i18n:getText("fieldJob_desc_action_forage"),
description = string.format(g_i18n:getText("fieldJob_desc_forage"), g_fillTypeManager:getFillTypeByIndex(self.orgFillType).title, self.field.fieldId, name)
}
end
function ChaffMission:getCompletion()
local sellCompletion = math.min(self.depositedLiters / self.expectedLiters / ChaffMission.SUCCESS_FACTOR, 1)
local fieldCompletion = self:getFieldCompletion()
local harvestCompletion = math.min(fieldCompletion / AbstractMission.SUCCESS_FACTOR, 1)
return math.min(1, 0.8 * harvestCompletion + 0.2 * sellCompletion)
end
function ChaffMission:validate(event)
return ChaffMission:superClass():validate(event) and
event ~= FieldManager.FIELDEVENT_GROWING -- cancel, if growing from forage-ready to harvest-ready
end
function ChaffMission:updateRewardPerHa()
return nil
end
--function ChaffMission:getVehicleVariant()
-- return nil
--end
-----------------------------------------------------------------------------------------------
function getIsAccessible(self, superf, farmId, x, z, workAreaType)
-- need this to prevent player from combine harvesting a chaff mission field with harvest-ready growth
local accessible, landOwner, canBuy = superf(self, farmId, x, z, workAreaType)
if workAreaType ~= WorkAreaType.CUTTER then
return accessible, landOwner, canBuy
end
local mission = g_missionManager:getMissionAtWorldPosition(x, z)
if mission and mission.type.name ~= "chaff" then
return accessible, landOwner, canBuy
end
-- is mission vehicle:
if self.propertyState == Vehicle.PROPERTY_STATE_MISSION and
g_missionManager:getIsMissionWorkAllowed(farmId, x, z, workAreaType) then
return self.spec_cutter.allowsForageGrowthState, farmId, true
end
-- is owned vehicle
if accessible then
local farmlandId = g_farmlandManager:getFarmlandIdAtWorldPosition(x, z)
local landOwner = g_farmlandManager:getFarmlandOwner(farmlandId)
accessible = landOwner ~= 0 and g_currentMission.accessHandler:canFarmAccessOtherId(farmId, landOwner)
if accessible and mission == nil then -- not on a mission field
return accessible, landOwner, true
end
accessible = g_missionManager:getIsMissionWorkAllowed(farmId, x, z, workAreaType) and
self.spec_cutter.allowsForageGrowthState
end
return accessible, landOwner, canBuy
end
function adjustMissionTypes(name)
-- move last missiontype to pos index in g_missionManager.missionTypes
-- before: mow, plow, cult, sow, harv, weed, spray, fert, trans, lime
-- after : mow, lime, plow, cult, sow, harv, weed, spray, fert, trans
local typeToMove = g_missionManager:getMissionType(name)
if typeToMove == nil then
Logging.error("* invalid mission type %s in adjustMissionTypes()")
return
end
local index = typeToMove.typeId
local types = g_missionManager.missionTypes
local idToType = g_missionManager.missionTypeIdToType
local type = table.remove(types) -- remove last type defined
table.insert(types, index, type)
for i = 1, g_missionManager.nextMissionTypeId -1 do
types[i].typeId = i
idToType[i] = types[i]
end
end
function isTargetFilltype(typeNames)
-- return true if typeNames contain straw or hay
local txt = typeNames.." "
if string.find(txt, "GRASS_WINDROW ") or string.find(txt, "STRAW ") then
return true
end
return false
end
function addSellingStation(self, superFunc, components, xmlFile, key, ...)
-- add chaff only for normal sellingstations that allow missions
local needFtKey = false
if key == "placeable.sellingStation" and xmlFile:getBool(key.."#allowMissions", true)
and not xmlFile:getBool(key.."#hideFromPricesMenu", false) then
debugPrint("*** checking selling station:")
local added = false
xmlFile:iterate(key..".unloadTrigger", function(index, unloadTriggerKey)
local fillTypeNames = xmlFile:getString(unloadTriggerKey.."#fillTypes")
local fillTypeCategories = xmlFile:getValue(unloadTriggerKey .. "#fillTypeCategories")
debugPrint(" * unload %d: %s / %s", index, fillTypeNames, fillTypeCategories)
-- add only to triggers with hay or straw:
if fillTypeNames == nil then
fillTypeNames = ""
local catNames = string.split(fillTypeCategories, " ")
for _, cat in ipairs(catNames) do
if g_fillTypeManager:getIsFillTypeInCategory(FillType.CHAFF, cat) then
-- Chaff already in selling station, can skip this
added = false
break
end
added = added or g_fillTypeManager:getIsFillTypeInCategory(FillType.DRYGRASS_WINDROW, cat)
or g_fillTypeManager:getIsFillTypeInCategory(FillType.GRASS_WINDROW, cat)
or g_fillTypeManager:getIsFillTypeInCategory(FillType.STRAW, cat)
end
else
added = isTargetFilltype(fillTypeNames)
end
if added then
local types = " CHAFF"
if ChaffMission.maizeplus then
types = types .. " CHOPPEDMAIZE"
end
xmlFile:setString(unloadTriggerKey.."#fillTypes", fillTypeNames.. types)
needFtKey = true
end
end)
if needFtKey then
local numberOfFillTypes = -1
xmlFile:iterate(key..".fillType", function(_, _)
numberOfFillTypes = numberOfFillTypes + 1
end)
addFt(xmlFile, key, numberOfFillTypes +1, "CHAFF")
if ChaffMission.maizeplus then
addFt(xmlFile, key, numberOfFillTypes +2, "CHOPPEDMAIZE")
end
end
end
return superFunc(self, components, xmlFile, key, ...)
end
function addFt(xmlFile, key, ix, ftName)
local nextKey = string.format("%s.fillType(%d)", key, ix)
debugPrint("* add %s as fillType(%d) to sellPoint", ftName, ix)
xmlFile:setString(nextKey.."#name", ftName)
xmlFile:setFloat(nextKey.."#priceScale", 1)
xmlFile:setBool(nextKey.."#supportsGreatDemand", false)
xmlFile:setBool(nextKey.."#disablePriceDrop", true)
end
function bcCheck()
bcName = "FS22_BetterContracts"
bcVer = "1.2.8.2"
if g_modIsLoaded[bcName] then
if g_modManager:getModByName(bcName).version < bcVer then
Logging.error("FS22_ChaffMission is incompatible with BetterContracts versions below %s. Mod will shut down.", bcVer)
g_gui:showInfoDialog({
text = string.format(g_i18n:getText("bcCheck"), bcVer)
})
return false
end
end
return true
end
function loadMapFinished( ... )
-- check for MaizePlus:
ChaffMission.maizeplus = g_modIsLoaded.FS22_MaizePlus
end
-----------------------------------------------------------------------------------------------
-- check BetterContracts sufficient version:
if bcCheck() then
WorkArea.getIsAccessibleAtWorldPosition = Utils.overwrittenFunction(WorkArea.getIsAccessibleAtWorldPosition,
getIsAccessible)
SellingStation.load = Utils.overwrittenFunction(SellingStation.load, addSellingStation)
BaseMission.loadMapFinished = Utils.appendedFunction(BaseMission.loadMapFinished, loadMapFinished)
g_missionManager:registerMissionType(ChaffMission, "chaff")
-- move chaff mission type before harvest:
adjustMissionTypes("harvest")
addConsoleCommand("chGenerateFieldMission", "Force generating a new mission for given field", " consoleGenerateFieldMission", g_missionManager)
end