/
plant_genes.dm
944 lines (803 loc) · 34.5 KB
/
plant_genes.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
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
/// Plant gene datums - things that build and modify a plant or seed.
/datum/plant_gene
/// The name of the gene.
var/name
/// The font awesome icon name representing the gene in the seed extractor UI
var/icon = "dna"
/// Flags that determine if a gene can be modified.
var/mutability_flags
/*
* Returns the formatted name of the plant gene.
*
* Overridden by the various subtypes of plant genes to format their respective names.
*/
/datum/plant_gene/proc/get_name()
return name
/*
* Check if the seed can accept this plant gene.
*
* our_seed - the seed we're adding the gene to
*
* Returns TRUE if the seed can take the gene, and FALSE otherwise.
*/
/datum/plant_gene/proc/can_add(obj/item/seeds/our_seed)
SHOULD_CALL_PARENT(TRUE)
return TRUE
/// Copies over vars and information about our current gene to a new gene and returns the new instance of gene.
/datum/plant_gene/proc/Copy()
var/datum/plant_gene/new_gene = new type
new_gene.mutability_flags = mutability_flags
return new_gene
/*
* on_new_seed is called when seed genes are initialized on the /obj/seed.
*
* new_seed - the seed being created
*/
/datum/plant_gene/proc/on_new_seed(obj/item/seeds/new_seed)
return // Not implemented
/*
* on_removed is called when the gene is removed from a seed.
* Also called when a seed is qdel'd (and all the genes are removed and deleted).
*
* old_seed - our seed, before being removed
*/
/datum/plant_gene/proc/on_removed(obj/item/seeds/old_seed)
return // Not implemented
/// Reagent genes store a reagent ID and reagent ratio.
/datum/plant_gene/reagent
name = "UNKNOWN"
mutability_flags = PLANT_GENE_REMOVABLE
/// The typepath of the actual reagent that this gene is tied to.
var/reagent_id = /datum/reagent/consumable/nutriment
/// The amount of reagent generated by the plant. The equation is [1 + ((max_volume*(potency/100)) * rate)]
var/rate = 0.04
/datum/plant_gene/reagent/get_name()
var/formatted_name
if(!(mutability_flags & PLANT_GENE_REMOVABLE))
formatted_name += "Fragile "
formatted_name += "[name] production [rate*100]%"
return formatted_name
/*
* Set our reagent's ID and name to the passed reagent.
*
* new_reagent_id - typepath of the reagent we're setting this gene to
*/
/datum/plant_gene/reagent/proc/set_reagent(new_reagent_id)
reagent_id = new_reagent_id
var/datum/reagent/found_reagent = GLOB.chemical_reagents_list[new_reagent_id]
if(found_reagent?.type == reagent_id)
name = found_reagent.name
/datum/plant_gene/reagent/New(new_reagent_id, new_reagent_rate = 0.04)
. = ..()
if(new_reagent_id)
set_reagent(new_reagent_id)
rate = new_reagent_rate
/datum/plant_gene/reagent/Copy()
. = ..()
var/datum/plant_gene/reagent/new_reagent_gene = .
new_reagent_gene.name = name
new_reagent_gene.reagent_id = reagent_id
new_reagent_gene.rate = rate
return
/datum/plant_gene/reagent/can_add(obj/item/seeds/our_seed)
. = ..()
if(!.)
return FALSE
for(var/datum/plant_gene/reagent/seed_reagent in our_seed.genes)
if(seed_reagent.reagent_id == reagent_id && seed_reagent.rate <= rate)
return FALSE // We can upgrade reagent genes if our rate is greater than the one already in the plant.
return TRUE
/**
* Intends to compare a reagent gene with a set of seeds, and if the seeds contain the same gene, with more production rate, upgrades the rate to the highest of the two.
*
* Called when plants are crossbreeding, this looks for two matching reagent_ids, where the rates are greater, in order to upgrade.
*/
/datum/plant_gene/reagent/proc/try_upgrade_gene(obj/item/seeds/seed)
for(var/datum/plant_gene/reagent/reagent in seed.genes)
if(reagent.reagent_id != reagent_id || reagent.rate <= rate)
continue
rate = reagent.rate
return TRUE
return FALSE
/// Traits that affect the grown product.
/datum/plant_gene/trait
/// The rate at which this trait affects something. This can be anything really - why? I dunno.
var/rate = 0.05
/// Bonus lines displayed on examine.
var/description = ""
/// Flag - Traits that share an ID cannot be placed on the same plant.
var/trait_ids
/// Flag - Modifications made to the final product.
var/trait_flags
/// A blacklist of seeds that a trait cannot be attached to.
var/list/obj/item/seeds/seed_blacklist
/datum/plant_gene/trait/Copy()
. = ..()
var/datum/plant_gene/trait/new_trait_gene = .
new_trait_gene.rate = rate
return
/datum/plant_gene/trait/get_name() // Used for manipulator display and gene disk name.
var/formatted_name
if(!(mutability_flags & PLANT_GENE_REMOVABLE))
if(!(mutability_flags & PLANT_GENE_GRAFTABLE))
formatted_name += "Immutable "
else
formatted_name += "Essential "
formatted_name += name
return formatted_name
/*
* Checks if we can add the trait to the seed in question.
*
* source_seed - the seed genes we're adding the trait too
*/
/datum/plant_gene/trait/can_add(obj/item/seeds/source_seed)
. = ..()
if(!.)
return FALSE
if(is_type_in_list(source_seed, seed_blacklist))
return FALSE
for(var/datum/plant_gene/trait/trait in source_seed.genes)
if(trait_ids & trait.trait_ids)
return FALSE
if(type == trait.type)
return FALSE
return TRUE
/*
* on_new_plant is called for every plant trait on an /obj/item/grown or /obj/item/food/grown when initialized.
*
* our_plant - the source plant being created
* newloc - the loc of the plant
*/
/datum/plant_gene/trait/proc/on_new_plant(obj/item/our_plant, newloc)
// Plants should always have seeds, but if a plant gene is somehow being instantiated on a plant with no seed, stop initializing genes
// (Plants hold their genes on their seeds, so we can't really add them to something that doesn't exist)
if(isnull(our_plant.get_plant_seed()))
stack_trace("[our_plant] ([our_plant.type]) has a nulled seed value while trying to initialize [src]!")
return FALSE
// Add on any bonus lines on examine
if(description)
RegisterSignal(our_plant, COMSIG_ATOM_EXAMINE, PROC_REF(examine))
return TRUE
/// Add on any unique examine text to the plant's examine text.
/datum/plant_gene/trait/proc/examine(obj/item/our_plant, mob/examiner, list/examine_list)
SIGNAL_HANDLER
examine_list += span_info("[description]")
/// Allows the plant to be squashed when thrown or slipped on, leaving a colored mess and trash type item behind.
/datum/plant_gene/trait/squash
name = "Liquid Contents"
icon = "droplet"
description = "It may burst open from the internal pressure on impact."
trait_ids = THROW_IMPACT_ID | REAGENT_TRANSFER_ID | ATTACK_SELF_ID
mutability_flags = PLANT_GENE_REMOVABLE | PLANT_GENE_MUTATABLE | PLANT_GENE_GRAFTABLE
// Register a signal that our plant can be squashed on add.
/datum/plant_gene/trait/squash/on_new_plant(obj/item/food/grown/our_plant, newloc)
. = ..()
if(!.)
return
RegisterSignal(our_plant, COMSIG_PLANT_ON_SLIP, PROC_REF(squash_plant))
RegisterSignal(our_plant, COMSIG_MOVABLE_IMPACT, PROC_REF(squash_plant))
RegisterSignal(our_plant, COMSIG_ITEM_ATTACK_SELF, PROC_REF(squash_plant))
/*
* Signal proc to squash the plant this trait belongs to, causing a smudge, exposing the target to reagents, and deleting it,
*
* Arguments
* our_plant - the plant this trait belongs to.
* target - the atom being hit by this squashed plant.
*/
/datum/plant_gene/trait/squash/proc/squash_plant(obj/item/food/grown/our_plant, atom/target)
SIGNAL_HANDLER
var/turf/our_turf = get_turf(target)
our_plant.forceMove(our_turf)
if(istype(our_plant))
if(ispath(our_plant.splat_type, /obj/effect/decal/cleanable/food/plant_smudge))
var/obj/plant_smudge = new our_plant.splat_type(our_turf)
plant_smudge.name = "[our_plant.name] smudge"
if(our_plant.filling_color)
plant_smudge.color = our_plant.filling_color
else if(our_plant.splat_type)
new our_plant.splat_type(our_turf)
else
var/obj/effect/decal/cleanable/food/plant_smudge/misc_smudge = new(our_turf)
misc_smudge.name = "[our_plant.name] smudge"
misc_smudge.color = "#82b900"
our_plant.visible_message(span_warning("[our_plant] is squashed."),span_hear("You hear a smack."))
SEND_SIGNAL(our_plant, COMSIG_PLANT_ON_SQUASH, target)
our_plant.reagents?.expose(our_turf)
for(var/things in our_turf)
our_plant.reagents?.expose(things)
qdel(our_plant)
/*
* Makes plant slippery, unless it has a grown-type trash. Then the trash gets slippery.
* Applies other trait effects (teleporting, etc) to the target by signal.
*/
/datum/plant_gene/trait/slip
name = "Slippery Skin"
description = "Watch your step around this."
icon = "person-falling"
rate = 1.6
mutability_flags = PLANT_GENE_REMOVABLE | PLANT_GENE_MUTATABLE | PLANT_GENE_GRAFTABLE
/datum/plant_gene/trait/slip/on_new_plant(obj/item/our_plant, newloc)
. = ..()
if(!.)
return
var/obj/item/food/grown/grown_plant = our_plant
if(istype(grown_plant) && ispath(grown_plant.trash_type, /obj/item/grown))
return
var/obj/item/seeds/our_seed = our_plant.get_plant_seed()
var/stun_len = our_seed.potency * rate
if(!istype(our_plant, /obj/item/grown/bananapeel) && (!our_plant.reagents || !our_plant.reagents.has_reagent(/datum/reagent/lube)))
stun_len /= 3
our_plant.AddComponent(/datum/component/slippery, min(stun_len, 140), NONE, CALLBACK(src, PROC_REF(handle_slip), our_plant))
/// On slip, sends a signal that our plant was slipped on out.
/datum/plant_gene/trait/slip/proc/handle_slip(obj/item/food/grown/our_plant, mob/slipped_target)
SEND_SIGNAL(our_plant, COMSIG_PLANT_ON_SLIP, slipped_target)
/*
* Cell recharging trait. Charges all mob's power cells to (potency*rate)% mark when eaten.
* Generates sparks on squash.
* Small (potency * rate) chance to shock squish or slip target for (potency * rate) damage.
* Also affects plant batteries see capatative cell production datum
*/
/datum/plant_gene/trait/cell_charge
name = "Electrical Activity"
description = "It can electrocute on interaction or recharge batteries when eaten."
icon = "bolt"
rate = 0.2
mutability_flags = PLANT_GENE_REMOVABLE | PLANT_GENE_MUTATABLE | PLANT_GENE_GRAFTABLE
/datum/plant_gene/trait/cell_charge/on_new_plant(obj/item/our_plant, newloc)
. = ..()
if(!.)
return
var/obj/item/seeds/our_seed = our_plant.get_plant_seed()
if(our_seed.get_gene(/datum/plant_gene/trait/squash))
// If we have the squash gene, let that handle slipping
RegisterSignal(our_plant, COMSIG_PLANT_ON_SQUASH, PROC_REF(zap_target))
else
RegisterSignal(our_plant, COMSIG_PLANT_ON_SLIP, PROC_REF(zap_target))
RegisterSignal(our_plant, COMSIG_FOOD_EATEN, PROC_REF(recharge_cells))
/*
* Zaps the target with a stunning shock.
*
* our_plant - our source plant, shocking the target
* target - the atom being zapped by our plant
*/
/datum/plant_gene/trait/cell_charge/proc/zap_target(obj/item/our_plant, atom/target)
SIGNAL_HANDLER
if(!iscarbon(target))
return
our_plant.investigate_log("zapped [key_name(target)] at [AREACOORD(target)]. Last touched by: [our_plant.fingerprintslast].", INVESTIGATE_BOTANY)
var/mob/living/carbon/target_carbon = target
var/obj/item/seeds/our_seed = our_plant.get_plant_seed()
var/power = our_seed.potency * rate
if(prob(power))
target_carbon.electrocute_act(round(power), our_plant, 1, SHOCK_NOGLOVES)
/*
* Recharges every cell the person is holding for a bit based on plant potency.
*
* our_plant - our source plant, that we consumed to charge the cells
* eater - the mob that bit the plant
* feeder - the mob that feed the eater the plant
*/
/datum/plant_gene/trait/cell_charge/proc/recharge_cells(obj/item/our_plant, mob/living/eater, mob/feeder)
SIGNAL_HANDLER
to_chat(eater, span_notice("You feel energized as you bite into [our_plant]."))
var/batteries_recharged = FALSE
var/obj/item/seeds/our_seed = our_plant.get_plant_seed()
for(var/obj/item/stock_parts/cell/found_cell in eater.get_all_contents())
var/newcharge = min(our_seed.potency * 0.01 * found_cell.maxcharge, found_cell.maxcharge)
if(found_cell.charge < newcharge)
found_cell.charge = newcharge
if(isobj(found_cell.loc))
var/obj/cell_location = found_cell.loc
cell_location.update_appearance() //update power meters and such
found_cell.update_appearance()
batteries_recharged = TRUE
if(batteries_recharged)
to_chat(eater, span_notice("Your batteries are recharged!"))
/*
* Makes the plant glow. Makes the plant in tray glow, too.
* Adds (1.4 + potency * rate) light range and (potency * (rate + 0.01)) light_power to products.
*/
/datum/plant_gene/trait/glow
name = "Bioluminescence"
icon = "lightbulb"
rate = 0.03
description = "It emits a soft glow."
trait_ids = GLOW_ID
mutability_flags = PLANT_GENE_REMOVABLE | PLANT_GENE_MUTATABLE | PLANT_GENE_GRAFTABLE
/// The color of our bioluminescence.
var/glow_color = COLOR_BIOLUMINESCENCE_STANDARD
/datum/plant_gene/trait/glow/proc/glow_range(obj/item/seeds/seed)
return 1.4 + seed.potency * rate
/datum/plant_gene/trait/glow/proc/glow_power(obj/item/seeds/seed)
return max(seed.potency * (rate + 0.01), 0.1)
/datum/plant_gene/trait/glow/on_new_plant(obj/item/our_plant, newloc)
. = ..()
if(!.)
return
var/obj/item/seeds/our_seed = our_plant.get_plant_seed()
our_plant.light_system = OVERLAY_LIGHT
our_plant.AddComponent(/datum/component/overlay_lighting, glow_range(our_seed), glow_power(our_seed), glow_color)
/*
* Makes plant emit darkness. (Purple-ish shadows)
* Adds - (potency * (rate * 0.2)) light power to products.
*/
/datum/plant_gene/trait/glow/shadow
name = "Shadow Emission"
icon = "lightbulb-o"
rate = 0.04
glow_color = COLOR_BIOLUMINESCENCE_SHADOW
/datum/plant_gene/trait/glow/shadow/glow_power(obj/item/seeds/seed)
return -max(seed.potency*(rate*0.2), 0.2)
/// Colored versions of bioluminescence.
/// White
/datum/plant_gene/trait/glow/white
name = "White Bioluminescence"
glow_color = COLOR_WHITE
/// Red
/datum/plant_gene/trait/glow/red
name = "Red Bioluminescence"
glow_color = COLOR_RED_LIGHT
/// Yellow (not the disgusting glowshroom yellow hopefully)
/datum/plant_gene/trait/glow/yellow
name = "Yellow Bioluminescence"
glow_color = COLOR_BIOLUMINESCENCE_YELLOW
/// Green (oh no, now i'm radioactive)
/datum/plant_gene/trait/glow/green
name = "Green Bioluminescence"
glow_color = COLOR_BIOLUMINESCENCE_GREEN
/// Blue (the best one)
/datum/plant_gene/trait/glow/blue
name = "Blue Bioluminescence"
glow_color = COLOR_BIOLUMINESCENCE_BLUE
/// Purple (did you know that notepad++ doesnt think bioluminescence is a word) (was the person who wrote this using notepad++ for dm?)
/datum/plant_gene/trait/glow/purple
name = "Purple Bioluminescence"
glow_color = COLOR_BIOLUMINESCENCE_PURPLE
// Pink (gay tide station pride)
/datum/plant_gene/trait/glow/pink
name = "Pink Bioluminescence"
glow_color = COLOR_BIOLUMINESCENCE_PINK
/*
* Makes plant teleport people when squashed or slipped on.
* Teleport radius is roughly potency / 10.
*/
/datum/plant_gene/trait/teleport
name = "Bluespace Activity"
description = "It causes people to teleport on interaction."
icon = "right-left"
rate = 0.1
mutability_flags = PLANT_GENE_REMOVABLE | PLANT_GENE_MUTATABLE | PLANT_GENE_GRAFTABLE
/datum/plant_gene/trait/teleport/on_new_plant(obj/item/our_plant, newloc)
. = ..()
if(!.)
return
var/obj/item/seeds/our_seed = our_plant.get_plant_seed()
if(our_seed.get_gene(/datum/plant_gene/trait/squash))
// If we have the squash gene, let that handle slipping
RegisterSignal(our_plant, COMSIG_PLANT_ON_SQUASH, PROC_REF(squash_teleport))
else
RegisterSignal(our_plant, COMSIG_PLANT_ON_SLIP, PROC_REF(slip_teleport))
/*
* When squashed, makes the target teleport.
*
* our_plant - our plant, being squashed, and teleporting the target
* target - the atom targeted by the squash
*/
/datum/plant_gene/trait/teleport/proc/squash_teleport(obj/item/our_plant, atom/target)
SIGNAL_HANDLER
if(!isliving(target))
return
our_plant.investigate_log("squash-teleported [key_name(target)] at [AREACOORD(target)]. Last touched by: [our_plant.fingerprintslast].", INVESTIGATE_BOTANY)
var/obj/item/seeds/our_seed = our_plant.get_plant_seed()
var/teleport_radius = max(round(our_seed.potency / 10), 1)
var/turf/T = get_turf(target)
new /obj/effect/decal/cleanable/molten_object(T) //Leave a pile of goo behind for dramatic effect...
do_teleport(target, T, teleport_radius, channel = TELEPORT_CHANNEL_BLUESPACE)
/*
* When slipped on, makes the target teleport and either teleport the source again or delete it.
*
* our_plant - our plant being slipped on
* target - the carbon targeted that was slipped and was teleported
*/
/datum/plant_gene/trait/teleport/proc/slip_teleport(obj/item/our_plant, mob/living/carbon/target)
SIGNAL_HANDLER
our_plant.investigate_log("slip-teleported [key_name(target)] at [AREACOORD(target)]. Last touched by: [our_plant.fingerprintslast].", INVESTIGATE_BOTANY)
var/obj/item/seeds/our_seed = our_plant.get_plant_seed()
var/teleport_radius = max(round(our_seed.potency / 10), 1)
var/turf/T = get_turf(target)
to_chat(target, span_warning("You slip through spacetime!"))
do_teleport(target, T, teleport_radius, channel = TELEPORT_CHANNEL_BLUESPACE)
if(prob(50))
do_teleport(our_plant, T, teleport_radius, channel = TELEPORT_CHANNEL_BLUESPACE)
else
new /obj/effect/decal/cleanable/molten_object(T) //Leave a pile of goo behind for dramatic effect...
qdel(our_plant)
/**
* A plant trait that causes the plant's capacity to double.
*
* When harvested, the plant's individual capacity is set to double it's default.
* However, the plant's maximum yield is also halved, only up to 5.
*/
/datum/plant_gene/trait/maxchem
name = "Densified Chemicals"
description = "The reagent volume is doubled, halving the plant yield instead."
icon = "flask-vial"
rate = 2
trait_flags = TRAIT_HALVES_YIELD
mutability_flags = PLANT_GENE_REMOVABLE | PLANT_GENE_MUTATABLE | PLANT_GENE_GRAFTABLE
/datum/plant_gene/trait/maxchem/on_new_plant(obj/item/our_plant, newloc)
. = ..()
if(!.)
return
var/obj/item/food/grown/grown_plant = our_plant
if(istype(grown_plant, /obj/item/food/grown))
//Grown foods use the edible component so we need to change their max_volume var
grown_plant.max_volume *= rate
else
//Grown inedibles however just use a reagents holder, so.
our_plant.reagents?.maximum_volume *= rate
/// Allows a plant to be harvested multiple times.
/datum/plant_gene/trait/repeated_harvest
name = "Perennial Growth"
description = "It may be harvested multiple times from the same plant."
icon = "cubes-stacked"
/// Don't allow replica pods to be multi harvested, please.
seed_blacklist = list(/obj/item/seeds/replicapod)
mutability_flags = PLANT_GENE_REMOVABLE | PLANT_GENE_MUTATABLE | PLANT_GENE_GRAFTABLE
/*
* Allows a plant to be turned into a battery when cabling is applied.
* 100 potency plants are made into 2 mj batteries.
* Plants with electrical activity has their capacities massively increased (up to 40 mj at 100 potency)
*/
/datum/plant_gene/trait/battery
name = "Capacitive Cell Production"
description = "It can work like a power cell when wired properly."
icon = "car-battery"
mutability_flags = PLANT_GENE_REMOVABLE | PLANT_GENE_MUTATABLE | PLANT_GENE_GRAFTABLE
/// The number of cables needed to make a battery.
var/cables_needed_per_battery = 5
/datum/plant_gene/trait/battery/on_new_plant(obj/item/our_plant, newloc)
. = ..()
if(!.)
return
our_plant.flags_1 |= HAS_CONTEXTUAL_SCREENTIPS_1
RegisterSignal(our_plant, COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM, PROC_REF(on_requesting_context_from_item))
RegisterSignal(our_plant, COMSIG_ATOM_ATTACKBY, PROC_REF(make_battery))
/*
* Signal proc for [COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM] to add context to plant batteries.
*/
/datum/plant_gene/trait/battery/proc/on_requesting_context_from_item(
obj/item/source,
list/context,
obj/item/held_item,
mob/living/user,
)
SIGNAL_HANDLER
if(!istype(held_item, /obj/item/stack/cable_coil))
return NONE
var/obj/item/stack/cable_coil/cabling = held_item
if(cabling.amount < cables_needed_per_battery)
return NONE
context[SCREENTIP_CONTEXT_LMB] = "Make [source.name] battery"
return CONTEXTUAL_SCREENTIP_SET
/*
* When a plant with this gene is hit (attackby) with cables, we turn it into a battery.
*
* our_plant - our plant being hit
* hit_item - the item we're hitting the plant with
* user - the person hitting the plant with an item
*/
/datum/plant_gene/trait/battery/proc/make_battery(obj/item/our_plant, obj/item/hit_item, mob/user)
SIGNAL_HANDLER
if(!istype(hit_item, /obj/item/stack/cable_coil))
return
var/obj/item/seeds/our_seed = our_plant.get_plant_seed()
var/obj/item/stack/cable_coil/cabling = hit_item
if(!cabling.use(cables_needed_per_battery))
to_chat(user, span_warning("You need five lengths of cable to make a [our_plant] battery!"))
return
to_chat(user, span_notice("You add some cable to [our_plant] and slide it inside the battery encasing."))
var/obj/item/stock_parts/cell/potato/pocell = new /obj/item/stock_parts/cell/potato(user.loc)
pocell.icon = our_plant.icon // Just in case the plant icons get spread out in different files eventually, this trait won't cause error sprites (also yay downstreams)
pocell.icon_state = our_plant.icon_state
pocell.maxcharge = our_seed.potency * 20 KILO JOULES
// The secret of potato supercells!
var/datum/plant_gene/trait/cell_charge/electrical_gene = our_seed.get_gene(/datum/plant_gene/trait/cell_charge)
if(electrical_gene) // Cell charge max is now 40MJ or otherwise known as 400KJ (Same as bluespace power cells)
pocell.maxcharge *= (electrical_gene.rate * 100)
pocell.charge = pocell.maxcharge
pocell.name = "[our_plant.name] battery"
pocell.desc = "A rechargeable plant-based power cell. This one has a rating of [display_energy(pocell.maxcharge)], and you should not swallow it."
if(our_plant.reagents.has_reagent(/datum/reagent/toxin/plasma, 2))
pocell.rigged = TRUE
qdel(our_plant)
/*
* Injects a number of chemicals from the plant when you throw it at someone or they slip on it.
* At 0 potency it can inject 1 unit of its chemicals, while at 100 potency it can inject 20 units.
*/
/datum/plant_gene/trait/stinging
name = "Hypodermic Prickles"
description = "It stings, passing some reagents in the process."
icon = "syringe"
trait_ids = REAGENT_TRANSFER_ID
mutability_flags = PLANT_GENE_REMOVABLE | PLANT_GENE_MUTATABLE | PLANT_GENE_GRAFTABLE
/datum/plant_gene/trait/stinging/on_new_plant(obj/item/our_plant, newloc)
. = ..()
if(!.)
return
RegisterSignal(our_plant, COMSIG_PLANT_ON_SLIP, PROC_REF(prickles_inject))
RegisterSignal(our_plant, COMSIG_MOVABLE_IMPACT, PROC_REF(prickles_inject))
/*
* Injects a target with a number of reagents from our plant.
*
* our_plant - our plant that's injecting someone
* target - the atom being hit on thrown or slipping on our plant
*/
/datum/plant_gene/trait/stinging/proc/prickles_inject(obj/item/our_plant, atom/target)
SIGNAL_HANDLER
if(!isliving(target) || !our_plant.reagents?.total_volume)
return
var/mob/living/living_target = target
var/obj/item/seeds/our_seed = our_plant.get_plant_seed()
if(living_target.reagents && living_target.can_inject())
var/injecting_amount = max(1, our_seed.potency * 0.2) // Minimum of 1, max of 20
our_plant.reagents.trans_to(living_target, injecting_amount, methods = INJECT)
to_chat(target, span_danger("You are pricked by [our_plant]!"))
log_combat(our_plant, living_target, "pricked and attempted to inject reagents from [our_plant] to [living_target]. Last touched by: [our_plant.fingerprintslast].")
our_plant.investigate_log("pricked and injected [key_name(living_target)] and injected [injecting_amount] reagents at [AREACOORD(living_target)]. Last touched by: [our_plant.fingerprintslast].", INVESTIGATE_BOTANY)
/// Explodes into reagent-filled smoke when squashed.
/datum/plant_gene/trait/smoke
name = "Gaseous Decomposition"
description = "It can be smashed to turn its Liquid Contents into smoke."
icon = "cloud"
mutability_flags = PLANT_GENE_REMOVABLE | PLANT_GENE_MUTATABLE | PLANT_GENE_GRAFTABLE
/datum/plant_gene/trait/smoke/on_new_plant(obj/item/our_plant, newloc)
. = ..()
if(!.)
return
RegisterSignal(our_plant, COMSIG_PLANT_ON_SQUASH, PROC_REF(make_smoke))
/*
* Makes a cloud of reagent smoke.
*
* our_plant - our plant being squashed and smoked
* target - the atom the plant was squashed on
*/
/datum/plant_gene/trait/smoke/proc/make_smoke(obj/item/our_plant, atom/target)
SIGNAL_HANDLER
our_plant.investigate_log("made smoke at [AREACOORD(target)]. Last touched by: [our_plant.fingerprintslast].", INVESTIGATE_BOTANY)
var/datum/effect_system/fluid_spread/smoke/chem/smoke = new ()
var/obj/item/seeds/our_seed = our_plant.get_plant_seed()
var/splat_location = get_turf(target)
var/range = sqrt(our_seed.potency * 0.1)
smoke.attach(splat_location)
smoke.set_up(round(range), holder = our_plant, location = splat_location, carry = our_plant.reagents, silent = FALSE)
smoke.start(log = TRUE)
our_plant.reagents.clear_reagents()
/// Makes the plant and its seeds fireproof. From lavaland plants.
/datum/plant_gene/trait/fire_resistance
name = "Fire Resistance"
description = "Makes the seeds, plant and produce fireproof."
icon = "fire"
mutability_flags = PLANT_GENE_REMOVABLE | PLANT_GENE_MUTATABLE | PLANT_GENE_GRAFTABLE
/datum/plant_gene/trait/fire_resistance/on_new_seed(obj/item/seeds/new_seed)
if(!(new_seed.resistance_flags & FIRE_PROOF))
new_seed.resistance_flags |= FIRE_PROOF
/datum/plant_gene/trait/fire_resistance/on_removed(obj/item/seeds/old_seed)
if(old_seed.resistance_flags & FIRE_PROOF)
old_seed.resistance_flags &= ~FIRE_PROOF
/datum/plant_gene/trait/fire_resistance/on_new_plant(obj/item/our_plant, newloc)
. = ..()
if(!.)
return
if(!(our_plant.resistance_flags & FIRE_PROOF))
our_plant.resistance_flags |= FIRE_PROOF
/// Invasive spreading lets the plant jump to other trays, and the spreading plant won't replace plants of the same type.
/datum/plant_gene/trait/invasive
name = "Invasive Spreading"
description = "It attempts to spread around if not contained."
icon = "virus"
mutability_flags = PLANT_GENE_REMOVABLE | PLANT_GENE_MUTATABLE | PLANT_GENE_GRAFTABLE
/datum/plant_gene/trait/invasive/on_new_seed(obj/item/seeds/new_seed)
RegisterSignal(new_seed, COMSIG_SEED_ON_GROW, PROC_REF(try_spread))
/datum/plant_gene/trait/invasive/on_removed(obj/item/seeds/old_seed)
UnregisterSignal(old_seed, COMSIG_SEED_ON_GROW)
/*
* Attempt to find an adjacent tray we can spread to.
*
* our_seed - our plant's seed, what spreads to other trays
* our_tray - the hydroponics tray we're currently in
*/
/datum/plant_gene/trait/invasive/proc/try_spread(obj/item/seeds/our_seed, obj/machinery/hydroponics/our_tray)
SIGNAL_HANDLER
if(prob(100 - (5 * (11 - our_seed.production))))
return
for(var/step_dir in GLOB.alldirs)
var/obj/machinery/hydroponics/spread_tray = locate() in get_step(our_tray, step_dir)
if(spread_tray && prob(15))
if(!our_tray.Adjacent(spread_tray))
continue //Don't spread through things we can't go through.
spread_seed(spread_tray, our_tray)
/*
* Actually spread the plant to the tray we found in try_spread.
*
* target_tray - the tray we're spreading to
* origin_tray - the tray we're currently in
*/
/datum/plant_gene/trait/invasive/proc/spread_seed(obj/machinery/hydroponics/target_tray, obj/machinery/hydroponics/origin_tray)
if(target_tray.myseed) // Check if there's another seed in the next tray.
if(target_tray.myseed.type == origin_tray.myseed.type && target_tray.plant_status != HYDROTRAY_PLANT_DEAD)
return FALSE // It should not destroy its own kind.
target_tray.visible_message(span_warning("The [target_tray.myseed.plantname] is overtaken by [origin_tray.myseed.plantname]!"))
QDEL_NULL(target_tray.myseed)
target_tray.set_seed(origin_tray.myseed.Copy())
target_tray.age = 0
target_tray.set_plant_health(target_tray.myseed.endurance)
target_tray.lastcycle = world.time
target_tray.set_weedlevel(0, update_icon = FALSE) // Reset
target_tray.set_pestlevel(0) // Reset
target_tray.visible_message(span_warning("The [origin_tray.myseed.plantname] spreads!"))
if(target_tray.myseed)
target_tray.name = "[initial(target_tray.name)] ([target_tray.myseed.plantname])"
else
target_tray.name = initial(target_tray.name)
return TRUE
/**
* A plant trait that causes the plant's food reagents to ferment instead.
*
* In practice, it replaces the plant's nutriment and vitamins with half as much of it's fermented reagent.
* This exception is executed in seeds.dm under 'prepare_result'.
*
* Incompatible with auto-juicing composition.
*/
/datum/plant_gene/trait/brewing
name = "Auto-Distilling Composition"
description = "Its nutriments undergo fermentation."
icon = "wine-glass"
trait_ids = CONTENTS_CHANGE_ID
mutability_flags = PLANT_GENE_REMOVABLE | PLANT_GENE_MUTATABLE | PLANT_GENE_GRAFTABLE
/**
* Similar to auto-distilling, but instead of brewing the plant's contents it juices it.
*
* Incompatible with auto-distilling composition.
*/
/datum/plant_gene/trait/juicing
name = "Auto-Juicing Composition"
description = "Its nutriments turn into juice."
icon = "glass-water"
trait_ids = CONTENTS_CHANGE_ID
mutability_flags = PLANT_GENE_REMOVABLE | PLANT_GENE_MUTATABLE | PLANT_GENE_GRAFTABLE
/**
* Plays a laughter sound when someone slips on it.
* Like the sitcom component but for plants.
* Just like slippery skin, if we have a trash type this only functions on that. (Banana peels)
*/
/datum/plant_gene/trait/plant_laughter
name = "Hallucinatory Feedback"
description = "Makes sounds when people slip on it."
icon = "face-laugh-squint"
mutability_flags = PLANT_GENE_REMOVABLE | PLANT_GENE_MUTATABLE | PLANT_GENE_GRAFTABLE
/// Sounds that play when this trait triggers
var/list/sounds = list('sound/items/SitcomLaugh1.ogg', 'sound/items/SitcomLaugh2.ogg', 'sound/items/SitcomLaugh3.ogg')
/datum/plant_gene/trait/plant_laughter/on_new_plant(obj/item/our_plant, newloc)
. = ..()
if(!.)
return
var/obj/item/food/grown/grown_plant = our_plant
if(istype(grown_plant) && ispath(grown_plant.trash_type, /obj/item/grown))
return
RegisterSignal(our_plant, COMSIG_PLANT_ON_SLIP, PROC_REF(laughter))
/*
* Play a sound effect from our plant.
*
* our_plant - the source plant that was slipped on
* target - the atom that slipped on the plant
*/
/datum/plant_gene/trait/plant_laughter/proc/laughter(obj/item/our_plant, atom/target)
SIGNAL_HANDLER
our_plant.audible_message(span_notice("[our_plant] lets out burst of laughter."))
playsound(our_plant, pick(sounds), 100, FALSE, SHORT_RANGE_SOUND_EXTRARANGE)
/**
* A plant trait that causes the plant to gain aesthetic googly eyes.
*
* Has no functional purpose outside of causing japes, adds eyes over the plant's sprite, which are adjusted for size by potency.
*/
/datum/plant_gene/trait/eyes
name = "Oculary Mimicry"
description = "It will watch after you."
icon = "eye"
mutability_flags = PLANT_GENE_REMOVABLE | PLANT_GENE_MUTATABLE | PLANT_GENE_GRAFTABLE
/// Our googly eyes appearance.
var/mutable_appearance/googly
/datum/plant_gene/trait/eyes/on_new_plant(obj/item/our_plant, newloc)
. = ..()
if(!.)
return
googly = mutable_appearance('icons/obj/service/hydroponics/harvest.dmi', "eyes")
googly.appearance_flags = RESET_COLOR
our_plant.add_overlay(googly)
/// Makes the plant embed on thrown impact.
/datum/plant_gene/trait/sticky
name = "Prickly Adhesion"
description = "It sticks to people when thrown, also passing reagents if stingy."
icon = "bandage"
trait_ids = THROW_IMPACT_ID
mutability_flags = PLANT_GENE_REMOVABLE | PLANT_GENE_MUTATABLE | PLANT_GENE_GRAFTABLE
/datum/plant_gene/trait/sticky/on_new_plant(obj/item/our_plant, newloc)
. = ..()
if(!.)
return
var/obj/item/seeds/our_seed = our_plant.get_plant_seed()
if(our_seed.get_gene(/datum/plant_gene/trait/stinging))
our_plant.embedding = EMBED_POINTY
else
our_plant.embedding = EMBED_HARMLESS
our_plant.updateEmbedding()
our_plant.throwforce = (our_seed.potency/20)
/**
* This trait automatically heats up the plant's chemical contents when harvested.
* This requires nutriment to fuel. 1u nutriment = 25 K.
*/
/datum/plant_gene/trait/chem_heating
name = "Exothermic Activity"
description = "It consumes nutriments to heat up other reagents, halving the yield."
icon = "temperatyre-arrow-up"
trait_ids = TEMP_CHANGE_ID
trait_flags = TRAIT_HALVES_YIELD
mutability_flags = PLANT_GENE_REMOVABLE | PLANT_GENE_MUTATABLE | PLANT_GENE_GRAFTABLE
/**
* This trait is the opposite of above - it cools down the plant's chemical contents on harvest.
* This requires nutriment to fuel. 1u nutriment = -5 K.
*/
/datum/plant_gene/trait/chem_cooling
name = "Endothermic Activity"
description = "It consumes nutriments to cool down other reagents, halving the yield."
icon = "temperature-arrow-down"
trait_ids = TEMP_CHANGE_ID
trait_flags = TRAIT_HALVES_YIELD
mutability_flags = PLANT_GENE_REMOVABLE | PLANT_GENE_MUTATABLE | PLANT_GENE_GRAFTABLE
/// Prevents species mutation, while still allowing wild mutation harvest and Floral Somatoray species mutation. Trait acts as a tag for hydroponics.dm to recognise.
/datum/plant_gene/trait/never_mutate
name = "Prosophobic Inclination"
description = "The plant does not mutate normally, but may give a mutated produce."
mutability_flags = PLANT_GENE_REMOVABLE | PLANT_GENE_MUTATABLE | PLANT_GENE_GRAFTABLE
/// Prevents stat mutation caused by instability. Trait acts as a tag for hydroponics.dm to recognise.
/datum/plant_gene/trait/stable_stats
name = "Symbiotic Resilience"
description = "High instability does not affect the plant stats."
mutability_flags = PLANT_GENE_REMOVABLE | PLANT_GENE_MUTATABLE | PLANT_GENE_GRAFTABLE
/// Traits for flowers, makes plants not decompose.
/datum/plant_gene/trait/preserved
name = "Natural Insecticide"
description = "It does not attract ants or decompose."
icon = "bug-slash"
mutability_flags = PLANT_GENE_REMOVABLE | PLANT_GENE_MUTATABLE | PLANT_GENE_GRAFTABLE
/datum/plant_gene/trait/preserved/on_new_plant(obj/item/our_plant, newloc)
. = ..()
if(!.)
return
var/obj/item/food/grown/grown_plant = our_plant
if(istype(grown_plant))
grown_plant.preserved_food = TRUE
/datum/plant_gene/trait/carnivory
name = "Obligate Carnivory"
description = "Pests have positive effect on the plant health."
icon = "spider"
/// Plant type traits. Incompatible with one another.
/datum/plant_gene/trait/plant_type
name = "you shouldn't see this"
trait_ids = PLANT_TYPE_ID
mutability_flags = PLANT_GENE_GRAFTABLE
/// Weeds don't get annoyed by weeds in their tray.
/datum/plant_gene/trait/plant_type/weed_hardy
name = "Weed Adaptation"
description = "It is a weed that needs no nutrients and doesn't suffer from other weeds."
icon = "seedling"
/// Mushrooms need less light and have a minimum yield.
/datum/plant_gene/trait/plant_type/fungal_metabolism
name = "Fungal Vitality"
description = "It is a mushroom that needs no water, less light and can't be overtaken by weeds."
icon = "droplet-slash"
/// Currently unused and does nothing. Appears in strange seeds.
/datum/plant_gene/trait/plant_type/alien_properties
name ="?????"
icon = "reddit-alien"