/
seeds.dm
428 lines (355 loc) · 15.8 KB
/
seeds.dm
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
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
// ********************************************************
// Here's all the seeds (plants) that can be used in hydro
// ********************************************************
/obj/item/seeds
icon = 'icons/obj/hydroponics/seeds.dmi'
icon_state = "seed" // Unknown plant seed - these shouldn't exist in-game.
w_class = WEIGHT_CLASS_TINY
resistance_flags = FLAMMABLE
var/plantname = "Plants" // Name of plant when planted.
var/product // A type path. The thing that is created when the plant is harvested.
var/species = "" // Used to update icons. Should match the name in the sprites unless all icon_* are overriden.
var/variant = null // Optional custom name to track modified plants. Can be set with pen or from gene modder.
var/growing_icon = 'icons/obj/hydroponics/growing.dmi' //the file that stores the sprites of the growing plant from this seed.
var/icon_grow // Used to override grow icon (default is "[species]-grow"). You can use one grow icon for multiple closely related plants with it.
var/icon_dead // Used to override dead icon (default is "[species]-dead"). You can use one dead icon for multiple closely related plants with it.
var/icon_harvest // Used to override harvest icon (default is "[species]-harvest"). If null, plant will use [icon_grow][growthstages].
var/lifespan = 25 // How long before the plant begins to take damage from age.
var/endurance = 15 // Amount of health the plant has.
var/maturation = 6 // Used to determine which sprite to switch to when growing.
var/production = 6 // Changes the amount of time needed for a plant to become harvestable.
var/yield = 3 // Amount of growns created per harvest. If is -1, the plant/shroom/weed is never meant to be harvested.
var/potency = 10 // The 'power' of a plant. Generally effects the amount of reagent in a plant, also used in other ways.
var/growthstages = 6 // Amount of growth sprites the plant has.
var/rarity = 0 // How rare the plant is. Used for giving points to cargo when shipping off to Centcom.
var/list/mutatelist = list() // The type of plants that this plant can mutate into.
var/list/genes = list() // Plant genes are stored here, see plant_genes.dm for more info.
var/list/reagents_add = list()
// A list of reagents to add to product.
// Format: "reagent_id" = potency multiplier
// Stronger reagents must always come first to avoid being displaced by weaker ones.
// Total amount of any reagent in plant is calculated by formula: 1 + round(potency * multiplier)
var/weed_rate = 1 //If the chance below passes, then this many weeds sprout during growth
var/weed_chance = 5 //Percentage chance per tray update to grow weeds
/obj/item/seeds/New(loc, nogenes = 0)
..()
pixel_x = rand(-8, 8)
pixel_y = rand(-8, 8)
if(!icon_grow)
icon_grow = "[species]-grow"
if(!icon_dead)
icon_dead = "[species]-dead"
if(!icon_harvest && !get_gene(/datum/plant_gene/trait/plant_type/fungal_metabolism) && yield != -1)
icon_harvest = "[species]-harvest"
if(!nogenes) // not used on Copy()
genes += new /datum/plant_gene/core/lifespan(lifespan)
genes += new /datum/plant_gene/core/endurance(endurance)
genes += new /datum/plant_gene/core/weed_rate(weed_rate)
genes += new /datum/plant_gene/core/weed_chance(weed_chance)
if(yield != -1)
genes += new /datum/plant_gene/core/yield(yield)
genes += new /datum/plant_gene/core/production(production)
if(potency != -1)
genes += new /datum/plant_gene/core/potency(potency)
for(var/p in genes)
if(ispath(p))
genes -= p
genes += new p
for(var/reag_id in reagents_add)
genes += new /datum/plant_gene/reagent(reag_id, reagents_add[reag_id])
/obj/item/seeds/Destroy()
QDEL_LIST(genes)
return ..()
/obj/item/seeds/proc/Copy()
var/obj/item/seeds/S = new type(null, 1)
// Copy all the stats
S.lifespan = lifespan
S.endurance = endurance
S.maturation = maturation
S.production = production
S.yield = yield
S.potency = potency
S.weed_rate = weed_rate
S.weed_chance = weed_chance
S.variant = variant
S.apply_variant_name()
S.genes = list()
for(var/g in genes)
var/datum/plant_gene/G = g
S.genes += G.Copy()
S.reagents_add = reagents_add.Copy() // Faster than grabbing the list from genes.
return S
/obj/item/seeds/proc/get_gene(typepath)
return (locate(typepath) in genes)
/obj/item/seeds/proc/reagents_from_genes()
reagents_add = list()
for(var/datum/plant_gene/reagent/R in genes)
reagents_add[R.reagent_id] = R.rate
/obj/item/seeds/proc/mutate(lifemut = 2, endmut = 5, productmut = 1, yieldmut = 2, potmut = 25, wrmut = 2, wcmut = 5, traitmut = 0)
adjust_lifespan(rand(-lifemut,lifemut))
adjust_endurance(rand(-endmut,endmut))
adjust_production(rand(-productmut,productmut))
adjust_yield(rand(-yieldmut,yieldmut))
adjust_potency(rand(-potmut,potmut))
adjust_weed_rate(rand(-wrmut, wrmut))
adjust_weed_chance(rand(-wcmut, wcmut))
if(prob(traitmut))
add_random_traits(1, 1)
/obj/item/seeds/bullet_act(obj/item/projectile/Proj) //Works with the Somatoray to modify plant variables.
if(istype(Proj, /obj/item/projectile/energy/florayield))
var/rating = 1
if(istype(loc, /obj/machinery/hydroponics))
var/obj/machinery/hydroponics/H = loc
rating = H.rating
if(yield == 0)//Oh god don't divide by zero you'll doom us all.
adjust_yield(1 * rating)
else if(prob(1/(yield * yield) * 100))//This formula gives you diminishing returns based on yield. 100% with 1 yield, decreasing to 25%, 11%, 6, 4, 2...
adjust_yield(1 * rating)
else
return ..()
// Harvest procs
/obj/item/seeds/proc/getYield()
var/return_yield = yield
var/obj/machinery/hydroponics/parent = loc
if(istype(loc, /obj/machinery/hydroponics))
if(parent.yieldmod == 0)
return_yield = min(return_yield, 1)//1 if above zero, 0 otherwise
else
return_yield *= (parent.yieldmod)
return return_yield
/obj/item/seeds/proc/harvest(mob/user = usr)
var/obj/machinery/hydroponics/parent = loc //for ease of access
var/t_amount = 0
var/list/result = list()
var/output_loc = parent.Adjacent(user) ? user.loc : parent.loc //needed for TK
var/product_name
while(t_amount < getYield())
var/obj/item/reagent_containers/food/snacks/grown/t_prod = new product(output_loc, src)
result.Add(t_prod) // User gets a consumable
if(!t_prod)
return
t_amount++
product_name = t_prod.name
if(getYield() >= 1)
SSblackbox.record_feedback("tally", "food_harvested", getYield(), product_name)
parent.update_tray()
return result
/obj/item/seeds/proc/prepare_result(obj/item/T)
if(!T.reagents)
CRASH("[T] has no reagents.")
for(var/rid in reagents_add)
var/amount = 1 + round(potency * reagents_add[rid], 1)
var/list/data = null
if(rid == "blood") // Hack to make blood in plants always O-
data = list("blood_type" = "O-")
if(rid == "nutriment" || rid == "vitamin" || rid == "protein" || rid == "plantmatter")
// apple tastes of apple.
if(istype(T, /obj/item/reagent_containers/food/snacks/grown))
var/obj/item/reagent_containers/food/snacks/grown/grown_edible = T
data = grown_edible.tastes.Copy()
T.reagents.add_reagent(rid, amount, data)
/// Setters procs ///
/obj/item/seeds/proc/adjust_yield(adjustamt)
if(yield != -1) // Unharvestable shouldn't suddenly turn harvestable
yield = clamp(yield + adjustamt, 0, 10)
if(yield <= 0 && get_gene(/datum/plant_gene/trait/plant_type/fungal_metabolism))
yield = 1 // Mushrooms always have a minimum yield of 1.
var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/yield)
if(C)
C.value = yield
/obj/item/seeds/proc/adjust_lifespan(adjustamt)
lifespan = clamp(lifespan + adjustamt, 10, 100)
var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/lifespan)
if(C)
C.value = lifespan
/obj/item/seeds/proc/adjust_endurance(adjustamt)
endurance = clamp(endurance + adjustamt, 10, 100)
var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/endurance)
if(C)
C.value = endurance
/obj/item/seeds/proc/adjust_production(adjustamt)
if(yield != -1)
production = clamp(production + adjustamt, 1, 10)
var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/production)
if(C)
C.value = production
/obj/item/seeds/proc/adjust_potency(adjustamt)
if(potency != -1)
potency = clamp(potency + adjustamt, 0, 100)
var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/potency)
if(C)
C.value = potency
/obj/item/seeds/proc/adjust_weed_rate(adjustamt)
weed_rate = clamp(weed_rate + adjustamt, 0, 10)
var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/weed_rate)
if(C)
C.value = weed_rate
/obj/item/seeds/proc/adjust_weed_chance(adjustamt)
weed_chance = clamp(weed_chance + adjustamt, 0, 67)
var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/weed_chance)
if(C)
C.value = weed_chance
//Directly setting stats
/obj/item/seeds/proc/set_yield(adjustamt)
if(yield != -1) // Unharvestable shouldn't suddenly turn harvestable
yield = clamp(adjustamt, 0, 10)
if(yield <= 0 && get_gene(/datum/plant_gene/trait/plant_type/fungal_metabolism))
yield = 1 // Mushrooms always have a minimum yield of 1.
var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/yield)
if(C)
C.value = yield
/obj/item/seeds/proc/set_lifespan(adjustamt)
lifespan = clamp(adjustamt, 10, 100)
var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/lifespan)
if(C)
C.value = lifespan
/obj/item/seeds/proc/set_endurance(adjustamt)
endurance = clamp(adjustamt, 10, 100)
var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/endurance)
if(C)
C.value = endurance
/obj/item/seeds/proc/set_production(adjustamt)
if(yield != -1)
production = clamp(adjustamt, 1, 10)
var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/production)
if(C)
C.value = production
/obj/item/seeds/proc/set_potency(adjustamt)
if(potency != -1)
potency = clamp(adjustamt, 0, 100)
var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/potency)
if(C)
C.value = potency
/obj/item/seeds/proc/set_weed_rate(adjustamt)
weed_rate = clamp(adjustamt, 0, 10)
var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/weed_rate)
if(C)
C.value = weed_rate
/obj/item/seeds/proc/set_weed_chance(adjustamt)
weed_chance = clamp(adjustamt, 0, 67)
var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/weed_chance)
if(C)
C.value = weed_chance
/obj/item/seeds/proc/get_analyzer_text() //in case seeds have something special to tell to the analyzer
var/text = ""
if(!get_gene(/datum/plant_gene/trait/plant_type/weed_hardy) && !get_gene(/datum/plant_gene/trait/plant_type/fungal_metabolism) && !get_gene(/datum/plant_gene/trait/plant_type/alien_properties))
text += "- Plant type: Normal plant\n"
if(get_gene(/datum/plant_gene/trait/plant_type/weed_hardy))
text += "- Plant type: Weed. Can grow in nutrient-poor soil.\n"
if(get_gene(/datum/plant_gene/trait/plant_type/fungal_metabolism))
text += "- Plant type: Mushroom. Can grow in dry soil.\n"
if(get_gene(/datum/plant_gene/trait/plant_type/alien_properties))
text += "- Plant type: <span class='warning'>UNKNOWN</span> \n"
if(potency != -1)
text += "- Potency: [potency]\n"
if(yield != -1)
text += "- Yield: [yield]\n"
text += "- Maturation speed: [maturation]\n"
if(yield != -1)
text += "- Production speed: [production]\n"
text += "- Endurance: [endurance]\n"
text += "- Lifespan: [lifespan]\n"
text += "- Weed Growth Rate: [weed_rate]\n"
text += "- Weed Vulnerability: [weed_chance]\n"
if(rarity)
text += "- Species Discovery Value: [rarity]\n"
var/all_traits = ""
for(var/datum/plant_gene/trait/traits in genes)
if(istype(traits, /datum/plant_gene/trait/plant_type))
continue
all_traits += " [traits.get_name()]"
text += "- Plant Traits:[all_traits]\n"
text += "*---------*"
return text
/obj/item/seeds/proc/on_chem_reaction(datum/reagents/S) //in case seeds have some special interaction with special chems
return
/obj/item/seeds/attackby(obj/item/O, mob/user, params)
if(istype(O, /obj/item/plant_analyzer))
to_chat(user, "<span class='info'>*---------*\n This is \a <span class='name'>[src]</span>.</span>")
var/text = get_analyzer_text()
if(text)
to_chat(user, "<span class='notice'>[text]</span>")
return
if(istype(O, /obj/item/pen))
variant_prompt(user)
return
..() // Fallthrough to item/attackby() so that bags can pick seeds up
/obj/item/seeds/proc/variant_prompt(mob/user, obj/item/container = null)
var/prev = variant
var/V = input(user, "Choose variant name:", "Plant Variant Naming", variant) as text|null
if(isnull(V)) // Did the user cancel?
return
if(container && (loc != container)) // Was the seed removed from the container, if there is a container?
return
if(!(container ? container : src).Adjacent(user)) // Is the user next to the seed/container?
return
variant = copytext(sanitize(html_encode(trim(V))), 1, 64) // Sanitization must happen after null check because it converts nulls to empty strings
if(variant == "")
variant = null
if(prev != variant)
to_chat(user, "<span class='notice'>You [variant ? "change" : "remove"] the [plantname]'s variant designation.</span>")
apply_variant_name()
/obj/item/seeds/proc/apply_variant_name()
var/V = variant ? " \[[variant]]" : "" // If we have a non-empty variant add it to the name
var/N = initial(name)
if(copytext(name, 1, 13) == "experimental") // Don't delete 'experimental'
N = "experimental " + N
name = N + V
if(GetComponent(/datum/component/label))
GetComponent(/datum/component/label).apply_label() // Don't delete labels
// Checks plants for broken tray icons. Use Advanced Proc Call to activate.
// Maybe some day it would be used as unit test.
/proc/check_plants_growth_stages_icons()
var/list/states = icon_states('icons/obj/hydroponics/growing.dmi')
states |= icon_states('icons/obj/hydroponics/growing_fruits.dmi')
states |= icon_states('icons/obj/hydroponics/growing_flowers.dmi')
states |= icon_states('icons/obj/hydroponics/growing_mushrooms.dmi')
states |= icon_states('icons/obj/hydroponics/growing_vegetables.dmi')
var/list/paths = typesof(/obj/item/seeds) - /obj/item/seeds - typesof(/obj/item/seeds/sample)
for(var/seedpath in paths)
var/obj/item/seeds/seed = new seedpath
for(var/i in 1 to seed.growthstages)
if("[seed.icon_grow][i]" in states)
continue
log_runtime("[seed.name] ([seed.type]) lacks the [seed.icon_grow][i] icon!")
if(!(seed.icon_dead in states))
log_runtime("[seed.name] ([seed.type]) lacks the [seed.icon_dead] icon!")
if(seed.icon_harvest) // mushrooms have no grown sprites, same for items with no product
if(!(seed.icon_harvest in states))
log_runtime("[seed.name] ([seed.type]) lacks the [seed.icon_harvest] icon!")
/obj/item/seeds/proc/randomize_stats()
set_lifespan(rand(25, 60))
set_endurance(rand(15, 35))
set_production(rand(2, 10))
set_yield(rand(1, 10))
set_potency(rand(10, 35))
set_weed_rate(rand(1, 10))
set_weed_chance(rand(5, 100))
maturation = rand(6, 12)
/obj/item/seeds/proc/add_random_reagents(lower = 0, upper = 2)
var/amount_random_reagents = rand(lower, upper)
for(var/i in 1 to amount_random_reagents)
var/random_amount = rand(4, 15) * 0.01 // this must be multiplied by 0.01, otherwise, it will not properly associate
var/datum/plant_gene/reagent/R = new(get_random_reagent_id(), random_amount)
if(R.can_add(src))
genes += R
else
qdel(R)
reagents_from_genes()
/obj/item/seeds/proc/add_random_traits(lower = 0, upper = 2)
var/amount_random_traits = rand(lower, upper)
for(var/i in 1 to amount_random_traits)
var/random_trait = pick((subtypesof(/datum/plant_gene/trait)-typesof(/datum/plant_gene/trait/plant_type)))
var/datum/plant_gene/trait/T = new random_trait
if(T.can_add(src))
genes += T
else
qdel(T)
/obj/item/seeds/proc/add_random_plant_type(normal_plant_chance = 75)
if(prob(normal_plant_chance))
var/random_plant_type = pick(subtypesof(/datum/plant_gene/trait/plant_type))
var/datum/plant_gene/trait/plant_type/P = new random_plant_type
if(P.can_add(src))
genes += P
else
qdel(P)