-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathisn_unifiedgrowingtray.lua
307 lines (261 loc) · 9.71 KB
/
isn_unifiedgrowingtray.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
require "/scripts/fu_storageutils.lua"
require "/scripts/kheAA/transferUtil.lua"
require "/scripts/power.lua"
timer = 0
seedslot = 1
waterslot = 2
fertslot = 3
function init()
defaults = {
growthRate = config.getParameter("baseGrowthPerSecond", 4), -- Multiplier on vanilla plant growth speed
seedUse = config.getParameter("defaultSeedUse", 3), -- Amount of seeds consumed per plant (for perennials, starting cost)
yield = config.getParameter("baseYields", 3), -- Multiplier on treasurepools generated
fluidUse = config.getParameter("defaultWaterUse", 1) -- Fluid units consumed per stage
-- geneBonus the bonus granted by X when attempting to mutate the strain
-- seedUseMutation chance for spontaneous mutation/gene treatment
-- yieldMutation chance for spontaneous mutation/gene treatment
-- ??
-- ??
}
multipliers = { growthRate=true } -- Which stats should be calculated as multipliers
if not storage.fert then storage.fert = {} end
if not storage.water then storage.water = {} end
self.requiredPower = config.getParameter("isn_requiredPower", nil)
self.unpoweredGrowthRate = config.getParameter("unpoweredGrowthRate", 0.434782609) -- Multiplier on base growth rate when unpowered
self.liquidInputs = config.getParameter("waterInputs")
self.fertInputs = config.getParameter("fertInputs")
if self.requiredPower then
power.init()
end
transferUtil.init()
object.setInteractive(true)
storage.growth = storage.growth or 0 --Plant growth completed
storage.fluid = storage.fluid or 0 --Stored fluid
storage.currentStage = storage.currentStage or 1 --Current plant stage
storage.hasFluid = storage.hasFluid or false --If false soil is dry and no further growth.
if storage.activeConsumption == nil then storage.activeConsumption = false end
end
--Updates the state of the object.
function update(dt)
-- Updates container status (for ITD management)
if timer >= 1 then
timer = 0
transferUtil.loadSelfContainer()
end
timer = timer + dt
if self.requiredPower then power.update(dt) end
storage.activeConsumption = false
--Try to start growing if data indicates we aren't.
if not storage.currentseed then
if not doSeedIntake() then return end
end
local growthmod = consumePower(dt) and 1 or self.unpoweredGrowthRate
growPlant(growthmod, dt)
storage.activeConsumption = true
updateState()
end
--Returns active seed when tray is removed from world
function die()
if storage.currentseed then
local count = getFertSum("seedUse")
storage.currentseed.count = count
world.spawnItem(storage.currentseed, entity.position(), count)
end
end
-- Consumes power and updates animation
function consumePower(dt)
if self.requiredPower then
if power.consume(self.requiredPower * dt) then
animator.setAnimationState("powlight", "on")
return true
else
animator.setAnimationState("powlight", "off")
return false
end
end
return false
end
-- Upates growth animation
function updateState()
--Compute which graphic should be displayed and update.
local growthperc = isn_getXPercentageOfY(math.min(storage.growth, storage.growthCap), storage.growthCap)
animator.setAnimationState("growth", sb.print(math.min(math.floor(growthperc / 25), 3)))
end
-- Performs a plant growth tick, including water consumption and harvesting
function growPlant(growthmod, dt)
-- Little cheat ;-) (always gets current stage)
local stage = function() return storage.stage[storage.currentStage] end
-- Fluid check
storage.hasFluid = doFluidConsume()
if not storage.hasFluid then return end
-- Add growth
storage.growth = storage.growth + getFertSum("growthRate") * (growthmod or 1) * dt
-- If current stage is complete, consume fluid units and increment stage
if storage.growth >= stage().val then
storage.fluid = storage.fluid - getFertSum("fluidUse")
storage.currentStage = storage.currentStage + 1
end
-- If the new stage is a harvesting stage, harvest and handle perennial
if stage().harvestPool then
local tblmerge = function(tb1, tb2) for k,v in pairs(tb2) do table.insert(tb1, v) end end
local output = {}
for i=1,getFertSum("yield") do
tblmerge(output, root.createTreasure(stage().harvestPool, 1))
end
local avoid = {0, 1, 2} -- Map for avoiding output to input slots
local seedavoid = {1, 2} -- Map for allowing seeds to be output into the input slot
for _,item in ipairs(output) do
-- Preserve customized seeds on output
if item.name == storage.currentseed.name then
item.parameters = storage.currentseed.parameters
end
fu_sendOrStoreItems(0, item, item.name == storage.currentseed.name and seedavoid or avoid)
end
-- Go to reset stage for perennial plants and full reset for others
local seed = world.containerItems(entity.id())[seedslot]
if seed and seed.name ~= storage.currentseed.name and stage().resetToStage then
storage.currentseed.count = getFertSum("seedUse")
fu_sendOrStoreItems(0, storage.currentseed, avoid)
storage.currentStage = 1
storage.growth = 0
storage.currentseed = nil
elseif stage().resetToStage then
storage.currentStage = stage().resetToStage + 1
storage.growth = storage.currentStage == 1 and 0 or storage.stage[storage.currentStage - 1].val
resetBonuses()
local fertName = doFertProcess()
if fertName then
storage.fert = self.fertInputs[fertName]
world.containerConsume(entity.id(), {name = fertName, count = 1, data={}})
end
storage.hasFluid = doFluidConsume()
else
storage.currentStage = 1
storage.growth = 0
storage.currentseed = nil
end
end
end
-- Gets the current effective value of a fertilizer-affected modifier.
function getFertSum(name)
local bonus = (storage.fert[name] or 0) + (storage.water[name] or 0)
if multipliers[name] then
return defaults[name] * (bonus <= 0 and 1 or bonus)
end
return math.max(defaults[name] + bonus, 0)
end
--Updates internal fluid levels, consumes required fluid units, and updates any fluid bonuses.
--optional arg fluidNeed is amount of fluid required to top up to.
function doWaterIntake(fluidNeed)
local water = world.containerItems(entity.id())[waterslot]
if water and self.liquidInputs[water.name] then
storage.water = self.liquidInputs[water.name]
local amt = math.min(water.count, math.ceil(fluidNeed / storage.water.value))
storage.fluid = storage.fluid + (amt * storage.water.value)
world.containerConsume(entity.id(), {name = water.name, count = amt})
return true
end
storage.water = {}
return false
end
--Attempts to use up some fluid
function doFluidConsume()
local useFluid = getFertSum("fluidUse")
if storage.fluid < useFluid then
if not doWaterIntake(useFluid - storage.fluid) then return false end
end
return true
end
--Fetch the seed from the storage slot, also does validity check.
function readContainerSeed()
local seed = world.containerItems(entity.id())[seedslot]
if not seed then return end
--Verify the seed is valid for use.
local seedConfig = root.itemConfig(seed).config
if seedConfig.objectType ~= "farmable" then return nil end
return seed
end
--Reads the currentseed's data. Return false if there was a problem with the
--seed/data.
function readSeedData()
if not storage.currentseed then return false end
if storage.currentseed.name == "sapling" then return false end
local stages = (storage.currentseed.parameters and storage.currentseed.parameters.stages) or root.itemConfig(storage.currentseed).config.stages
storage.stages = #stages
storage.stage = stages
return true
end
--Generates growth data to tell when a plant is ready for harvest and when it
--needs to be watered.
function genGrowthData(initStage)
initStage = initStage or 1
--Make sure some things make sense for a perennial, if not act like it's annual
if initStage > storage.stages then
initStage = 1
storage.resetStage = 1
end
storage.currentStage = initStage
storage.growthCap = 0
for index,stage in ipairs(storage.stage) do
storage.growthCap = storage.growthCap + (stage.duration and stage.duration[1] or 0)
stage.val = storage.growthCap
end
return true
end
--Initialize plant activity (start from scratch)
function doSeedIntake()
storage.growth = 0
animator.setAnimationState("growth", "0")
storage.currentseed = nil
--Read/init seed data
local seed = readContainerSeed()
if not seed then return false end
storage.currentseed = seed
if not readSeedData() then
storage.currentseed = nil
return false
end
--set defaults that fertilizer can change or modify
resetBonuses()
--Since we might need to consume multiple seeds we delay fertilizer USE
--until we know we have enough resources to proceed.
--Otherwise we could end up consuming all the fertilizer without growing anything.
local fertName = doFertProcess()
--verify we have enough seeds to proceed.
if storage.currentseed.count < getFertSum("seedUse") then
storage.currentseed = nil
storage.harvestPool = nil
storage.fert = {}
return false
end
--Generate growth data.
if not genGrowthData() then
storage.currentseed = nil
storage.harvestPool = nil
storage.fert = {}
return false
end
--All state tests passed and we are ready to grow, consume some items.
--Consume a unit of fertilizer.
if fertName then
world.containerConsume(entity.id(), {name = fertName, count = 1, data={}})
end
--Consume seed.
world.containerConsume(entity.id(), {name = seed.name, count = getFertSum("seedUse"), data={}})
return true
end
--Reads the current fertilizer slot and modifies growing state data
--Returns false if nothing to do, true if successful
function doFertProcess()
local fert = world.containerItems(entity.id())[fertslot]
if fert and self.fertInputs[fert.name] and fert.count > 0 then
storage.fert = self.fertInputs[fert.name]
return fert.name
end
storage.fert = {}
return nil
end
function resetBonuses()
storage.fert = {}
storage.water = {}
end