-
Notifications
You must be signed in to change notification settings - Fork 4.9k
/
organ_internal.dm
227 lines (195 loc) · 7.7 KB
/
organ_internal.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
/obj/item/organ
name = "organ"
icon = 'icons/obj/surgery.dmi'
var/mob/living/carbon/owner = null
var/status = ORGAN_ORGANIC
w_class = WEIGHT_CLASS_SMALL
throwforce = 0
var/zone = BODY_ZONE_CHEST
var/slot
// DO NOT add slots with matching names to different zones - it will break internal_organs_slot list!
var/organ_flags = ORGAN_EDIBLE
var/maxHealth = STANDARD_ORGAN_THRESHOLD
var/damage = 0 //total damage this organ has sustained
///Healing factor and decay factor function on % of maxhealth, and do not work by applying a static number per tick
var/healing_factor = 0 //fraction of maxhealth healed per on_life(), set to 0 for generic organs
var/decay_factor = 0 //same as above but when without a living owner, set to 0 for generic organs
var/high_threshold = STANDARD_ORGAN_THRESHOLD * 0.45 //when severe organ damage occurs
var/low_threshold = STANDARD_ORGAN_THRESHOLD * 0.1 //when minor organ damage occurs
var/severe_cooldown //cooldown for severe effects, used for synthetic organ emp effects.
///Organ variables for determining what we alert the owner with when they pass/clear the damage thresholds
var/prev_damage = 0
var/low_threshold_passed
var/high_threshold_passed
var/now_failing
var/now_fixed
var/high_threshold_cleared
var/low_threshold_cleared
///When you take a bite you cant jam it in for surgery anymore.
var/useable = TRUE
var/list/food_reagents = list(/datum/reagent/consumable/nutriment = 5)
/obj/item/organ/Initialize()
. = ..()
if(organ_flags & ORGAN_EDIBLE)
AddComponent(/datum/component/edible, food_reagents, null, RAW | MEAT | GROSS, null, 10, null, null, null, CALLBACK(src, .proc/OnEatFrom))
/obj/item/organ/proc/Insert(mob/living/carbon/M, special = 0, drop_if_replaced = TRUE)
if(!iscarbon(M) || owner == M)
return
var/obj/item/organ/replaced = M.getorganslot(slot)
if(replaced)
replaced.Remove(M, special = 1)
if(drop_if_replaced)
replaced.forceMove(get_turf(M))
else
qdel(replaced)
SEND_SIGNAL(M, COMSIG_CARBON_GAIN_ORGAN, src)
owner = M
M.internal_organs |= src
M.internal_organs_slot[slot] = src
moveToNullspace()
for(var/X in actions)
var/datum/action/A = X
A.Grant(M)
STOP_PROCESSING(SSobj, src)
//Special is for instant replacement like autosurgeons
/obj/item/organ/proc/Remove(mob/living/carbon/M, special = FALSE)
owner = null
if(M)
M.internal_organs -= src
if(M.internal_organs_slot[slot] == src)
M.internal_organs_slot.Remove(slot)
if((organ_flags & ORGAN_VITAL) && !special && !(M.status_flags & GODMODE))
M.death()
for(var/X in actions)
var/datum/action/A = X
A.Remove(M)
SEND_SIGNAL(M, COMSIG_CARBON_LOSE_ORGAN, src)
START_PROCESSING(SSobj, src)
/obj/item/organ/proc/on_find(mob/living/finder)
return
/obj/item/organ/process()
on_death() //Kinda hate doing it like this, but I really don't want to call process directly.
/obj/item/organ/proc/on_death() //runs decay when outside of a person
if(organ_flags & (ORGAN_SYNTHETIC | ORGAN_FROZEN))
return
applyOrganDamage(maxHealth * decay_factor)
/obj/item/organ/proc/on_life() //repair organ damage if the organ is not failing
if(organ_flags & ORGAN_FAILING)
return
if(organ_flags & ORGAN_SYNTHETIC_EMP) //Synthetic organ has been emped, is now failing.
applyOrganDamage(maxHealth * decay_factor)
return
///Damage decrements by a percent of its maxhealth
var/healing_amount = -(maxHealth * healing_factor)
///Damage decrements again by a percent of its maxhealth, up to a total of 4 extra times depending on the owner's health
healing_amount -= owner.satiety > 0 ? 4 * healing_factor * owner.satiety / MAX_SATIETY : 0
applyOrganDamage(healing_amount)
/obj/item/organ/examine(mob/user)
. = ..()
if(organ_flags & ORGAN_FAILING)
if(status == ORGAN_ROBOTIC)
. += "<span class='warning'>[src] seems to be broken.</span>"
return
. += "<span class='warning'>[src] has decayed for too long, and has turned a sickly color. It probably won't work without repairs.</span>"
return
if(damage > high_threshold)
. += "<span class='warning'>[src] is starting to look discolored.</span>"
/obj/item/organ/Initialize()
. = ..()
START_PROCESSING(SSobj, src)
/obj/item/organ/Destroy()
if(owner)
// The special flag is important, because otherwise mobs can die
// while undergoing transformation into different mobs.
Remove(owner, special=TRUE)
else
STOP_PROCESSING(SSobj, src)
return ..()
/obj/item/organ/proc/OnEatFrom(eater, feeder)
useable = FALSE //You can't use it anymore after eating it you spaztic
/obj/item/organ/item_action_slot_check(slot,mob/user)
return //so we don't grant the organ's action to mobs who pick up the organ.
///Adjusts an organ's damage by the amount "d", up to a maximum amount, which is by default max damage
/obj/item/organ/proc/applyOrganDamage(d, maximum = maxHealth) //use for damaging effects
if(!d) //Micro-optimization.
return
if(maximum < damage)
return
damage = clamp(damage + d, 0, maximum)
var/mess = check_damage_thresholds(owner)
prev_damage = damage
if(mess && owner)
to_chat(owner, mess)
///SETS an organ's damage to the amount "d", and in doing so clears or sets the failing flag, good for when you have an effect that should fix an organ if broken
/obj/item/organ/proc/setOrganDamage(d) //use mostly for admin heals
applyOrganDamage(d - damage)
/** check_damage_thresholds
* input: M (a mob, the owner of the organ we call the proc on)
* output: returns a message should get displayed.
* description: By checking our current damage against our previous damage, we can decide whether we've passed an organ threshold.
* If we have, send the corresponding threshold message to the owner, if such a message exists.
*/
/obj/item/organ/proc/check_damage_thresholds(M)
if(damage == prev_damage)
return
var/delta = damage - prev_damage
if(delta > 0)
if(damage >= maxHealth)
organ_flags |= ORGAN_FAILING
return now_failing
if(damage > high_threshold && prev_damage <= high_threshold)
return high_threshold_passed
if(damage > low_threshold && prev_damage <= low_threshold)
return low_threshold_passed
else
organ_flags &= ~ORGAN_FAILING
if(prev_damage > low_threshold && damage <= low_threshold)
return low_threshold_cleared
if(prev_damage > high_threshold && damage <= high_threshold)
return high_threshold_cleared
if(prev_damage == maxHealth)
return now_fixed
//Looking for brains?
//Try code/modules/mob/living/carbon/brain/brain_item.dm
/mob/living/proc/regenerate_organs()
return 0
/mob/living/carbon/regenerate_organs()
if(dna?.species)
dna.species.regenerate_organs(src)
return
else
var/obj/item/organ/lungs/L = getorganslot(ORGAN_SLOT_LUNGS)
if(!L)
L = new()
L.Insert(src)
L.setOrganDamage(0)
var/obj/item/organ/heart/H = getorganslot(ORGAN_SLOT_HEART)
if(!H)
H = new()
H.Insert(src)
H.setOrganDamage(0)
var/obj/item/organ/tongue/T = getorganslot(ORGAN_SLOT_TONGUE)
if(!T)
T = new()
T.Insert(src)
T.setOrganDamage(0)
var/obj/item/organ/eyes/eyes = getorganslot(ORGAN_SLOT_EYES)
if(!eyes)
eyes = new()
eyes.Insert(src)
eyes.setOrganDamage(0)
var/obj/item/organ/ears/ears = getorganslot(ORGAN_SLOT_EARS)
if(!ears)
ears = new()
ears.Insert(src)
ears.setOrganDamage(0)
/** get_availability
* returns whether the species should innately have this organ.
*
* regenerate organs works with generic organs, so we need to get whether it can accept certain organs just by what this returns.
* This is set to return true or false, depending on if a species has a specific organless trait. stomach for example checks if the species has NOSTOMACH and return based on that.
* Arguments:
* S - species, needed to return whether the species has an organ specific trait
*/
/obj/item/organ/proc/get_availability(datum/species/S)
return TRUE