This repository has been archived by the owner on Oct 7, 2018. It is now read-only.
/
bodyparts.dm
607 lines (513 loc) · 17.9 KB
/
bodyparts.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
/obj/item/bodypart
name = "limb"
desc = "why is it detached..."
force = 3
throwforce = 3
icon = 'icons/mob/human_parts.dmi'
icon_state = ""
layer = BELOW_MOB_LAYER //so it isn't hidden behind objects when on the floor
var/mob/living/carbon/owner = null
var/mob/living/carbon/original_owner = null
var/status = BODYPART_ORGANIC
var/body_zone //"chest", "l_arm", etc , used for def_zone
var/body_part = null //bitflag used to check which clothes cover this bodypart
var/use_digitigrade = NOT_DIGITIGRADE //Used for alternate legs, useless elsewhere
var/brutestate = 0
var/burnstate = 0
var/brute_dam = 0
var/burn_dam = 0
var/max_damage = 0
var/list/embedded_objects = list()
var/held_index = 0 //are we a hand? if so, which one!
var/is_pseudopart = FALSE //For limbs that don't really exist, eg chainsaws
var/broken = FALSE //For whether...it's broken
var/splinted = FALSE //Whether it's splinted. Movement doesn't deal damage, but you still move slowly.
var/has_bones = FALSE
var/render_like_organic = FALSE // TRUE is for when you want a BODYPART_ROBOTIC to pretend to be a BODYPART_ORGANIC.
//Coloring and proper item icon update
var/skin_tone = ""
var/body_gender = ""
var/species_id = ""
var/should_draw_gender = FALSE
var/should_draw_greyscale = FALSE
var/species_color = ""
var/mutation_color = ""
var/no_update = 0
var/animal_origin = null //for nonhuman bodypart (e.g. monkey)
var/dismemberable = 1 //whether it can be dismembered with a weapon.
var/px_x = 0
var/px_y = 0
var/species_flags_list = list()
var/dmg_overlay_type //the type of damage overlay (if any) to use when this bodypart is bruised/burned.
/obj/item/bodypart/examine(mob/user)
..()
if(brute_dam > 0)
to_chat(user, "<span class='warning'>This limb has [brute_dam > 30 ? "severe" : "minor"] bruising.</span>")
if(burn_dam > 0)
to_chat(user, "<span class='warning'>This limb has [burn_dam > 30 ? "severe" : "minor"] burns.</span>")
/obj/item/bodypart/blob_act()
take_damage(max_damage)
/obj/item/bodypart/Destroy()
if(owner)
owner.bodyparts -= src
owner = null
return ..()
/obj/item/bodypart/attack(mob/living/carbon/C, mob/user)
if(ishuman(C))
var/mob/living/carbon/human/H = C
if(EASYLIMBATTACHMENT in H.dna.species.species_traits)
if(((src.status == BODYPART_ORGANIC) && (!(ROBOTIC_LIMBS in H.dna.species.species_traits))) || ((src.status == BODYPART_ROBOTIC) && (ROBOTIC_LIMBS in H.dna.species.species_traits))) // Can't mix organic and robotic.
if(!H.get_bodypart(body_zone) && !animal_origin)
if(H == user)
H.visible_message("<span class='notice'>[H] is attempting to re-attach [src]...</span>")
do_mob(user, H, 60)
H.visible_message("<span class='warning'>[H] jams [src] into [H.p_their()] empty socket!</span>",\
"<span class='notice'>You force [src] into your empty socket, and it locks into place!</span>")
else
H.visible_message("<span class='warning'>[user] jams [src] into [H]'s empty socket!</span>",\
"<span class='notice'>[user] forces [src] into your empty socket, and it locks into place!</span>")
user.temporarilyRemoveItemFromInventory(src, TRUE)
attach_limb(C)
return
..()
/obj/item/bodypart/attackby(obj/item/W, mob/user, params)
if(W.sharpness)
add_fingerprint(user)
if(!contents.len)
to_chat(user, "<span class='warning'>There is nothing left inside [src]!</span>")
return
playsound(loc, 'sound/weapons/slice.ogg', 50, 1, -1)
user.visible_message("<span class='warning'>[user] begins to cut open [src].</span>",\
"<span class='notice'>You begin to cut open [src]...</span>")
if(do_after(user, 54, target = src))
drop_organs(user)
else
return ..()
/obj/item/bodypart/throw_impact(atom/hit_atom)
..()
if(status != BODYPART_ROBOTIC)
playsound(get_turf(src), 'sound/misc/splort.ogg', 50, 1, -1)
pixel_x = rand(-3, 3)
pixel_y = rand(-3, 3)
//empties the bodypart from its organs and other things inside it
/obj/item/bodypart/proc/drop_organs(mob/user)
var/turf/T = get_turf(src)
if(status != BODYPART_ROBOTIC)
playsound(T, 'sound/misc/splort.ogg', 50, 1, -1)
for(var/obj/item/I in src)
I.forceMove(T)
/obj/item/bodypart/proc/can_break_bone()
if(broken)
return 0
if(status == BODYPART_ROBOTIC)
return 0
if(!has_bones)
return 0
return 1
/obj/item/bodypart/proc/break_bone()
if(!can_break_bone())
return
broken = TRUE
spawn(1)//because otherwise it pops before the punch message; we don't want that
owner.visible_message("<span class='userdanger'>You hear a cracking sound coming from [owner]'s [name].</span>", "<span class='warning'>You feel something crack in your [name]!</span>", "<span class='warning'>You hear an awful cracking sound.</span>")
/obj/item/bodypart/proc/fix_bone()
broken = FALSE
splinted = FALSE
if(owner)
owner.update_inv_splints()
/obj/item/bodypart/on_mob_move()
if(!broken || status == BODYPART_ROBOTIC || !owner || splinted)
return
if(prob(5))
to_chat(owner, "<span class='userdanger'>[pick("You feel broken bones moving around in your [src]!", "There are broken bones moving around in your [src]!", "The bones in your [src] are moving around!")]</span>")
receive_damage(rand(1, 3))
//1-3 damage every 20 tiles for every broken bodypart.
//A single broken bodypart will give you an average of 650 tiles to run before you get a total of 100 damage and fall into crit
//Applies brute and burn damage to the organ. Returns 1 if the damage-icon states changed at all.
//Damage will not exceed max_damage using this proc
//Cannot apply negative damage
/obj/item/bodypart/proc/receive_damage(brute, burn, updating_health = 1, break_modifier = 1)
if(owner && (owner.status_flags & GODMODE))
return 0 //godmode
var/dmg_mlt = CONFIG_GET(number/damage_multiplier)
brute = max(brute * dmg_mlt, 0)
burn = max(burn * dmg_mlt, 0)
if(status == BODYPART_ROBOTIC) //This makes robolimbs not damageable by chems and makes it stronger
brute = max(0, brute - 5)
burn = max(0, burn - 3)
switch(animal_origin)
if(ALIEN_BODYPART,LARVA_BODYPART) //aliens take double burn
burn *= 2
if(prob(brute*break_modifier) && ((brute_dam + burn_dam)/max_damage) > 0.3 )
break_bone()
var/can_inflict = max_damage - (brute_dam + burn_dam)
if(!can_inflict)
return 0
if((brute + burn) < can_inflict)
brute_dam += brute
burn_dam += burn
else
if(brute > 0)
if(burn > 0)
brute = round( (brute/(brute+burn)) * can_inflict, 1 )
burn = can_inflict - brute //gets whatever damage is left over
brute_dam += brute
burn_dam += burn
else
brute_dam += can_inflict
else
if(burn > 0)
burn_dam += can_inflict
else
return 0
if(owner && updating_health)
owner.updatehealth()
return update_bodypart_damage_state()
//Heals brute and burn damage for the organ. Returns 1 if the damage-icon states changed at all.
//Damage cannot go below zero.
//Cannot remove negative damage (i.e. apply damage)
/obj/item/bodypart/proc/heal_damage(brute, burn, only_robotic = 0, only_organic = 1, updating_health = 1)
if(only_robotic && status != BODYPART_ROBOTIC) //This makes organic limbs not heal when the proc is in Robotic mode.
return
if(only_organic && status != BODYPART_ORGANIC) //This makes robolimbs not healable by chems.
return
brute_dam = max(brute_dam - brute, 0)
burn_dam = max(burn_dam - burn, 0)
if(owner && updating_health)
owner.updatehealth()
if(owner.dna && owner.dna.species && (REVIVESBYHEALING in owner.dna.species.species_traits))
if(owner.health > 0 && !owner.hellbound)
owner.revive(0)
owner.cure_husk(0) // If it has REVIVESBYHEALING, it probably can't be cloned. No husk cure.
return update_bodypart_damage_state()
//Returns total damage...kinda pointless really
/obj/item/bodypart/proc/get_damage()
return brute_dam + burn_dam
//Updates an organ's brute/burn states for use by update_damage_overlays()
//Returns 1 if we need to update overlays. 0 otherwise.
/obj/item/bodypart/proc/update_bodypart_damage_state()
var/tbrute = round( (brute_dam/max_damage)*3, 1 )
var/tburn = round( (burn_dam/max_damage)*3, 1 )
if((tbrute != brutestate) || (tburn != burnstate))
brutestate = tbrute
burnstate = tburn
return 1
return 0
//Change organ status
/obj/item/bodypart/proc/change_bodypart_status(new_limb_status, heal_limb, change_icon_to_default)
status = new_limb_status
if(heal_limb)
burn_dam = 0
brute_dam = 0
brutestate = 0
burnstate = 0
if(change_icon_to_default)
if(status == BODYPART_ORGANIC)
icon = DEFAULT_BODYPART_ICON_ORGANIC
else if(status == BODYPART_ROBOTIC)
icon = DEFAULT_BODYPART_ICON_ROBOTIC
if(owner)
owner.updatehealth()
owner.update_body() //if our head becomes robotic, we remove the lizard horns and human hair.
owner.update_hair()
owner.update_damage_overlays()
//we inform the bodypart of the changes that happened to the owner, or give it the informations from a source mob.
/obj/item/bodypart/proc/update_limb(dropping_limb, mob/living/carbon/source)
var/mob/living/carbon/C
if(source)
C = source
if(!original_owner)
original_owner = source
else if(original_owner && owner != original_owner) //Foreign limb
no_update = 1
else
C = owner
no_update = 0
has_bones = C.has_bones//get the carbon's default bone settings
if(C.disabilities & HUSK)
species_id = C.dna.species.husk_id //overrides species_id
dmg_overlay_type = "" //no damage overlay shown when husked
should_draw_gender = FALSE
should_draw_greyscale = FALSE
no_update = 1
if(no_update)
return
if(!animal_origin)
var/mob/living/carbon/human/H = C
should_draw_greyscale = FALSE
var/datum/species/S = H.dna.species
species_id = S.limbs_id
species_flags_list = H.dna.species.species_traits
if(NO_BONES in S.species_traits)
has_bones = FALSE
fix_bone()
else
has_bones = TRUE
if(S.use_skintones)
skin_tone = H.skin_tone
should_draw_greyscale = TRUE
else
skin_tone = ""
body_gender = H.gender
should_draw_gender = S.sexes
if(MUTCOLORS in S.species_traits)
if(S.fixed_mut_color)
species_color = S.fixed_mut_color
else
species_color = H.dna.features["mcolor"]
should_draw_greyscale = TRUE
else
species_color = ""
if(!dropping_limb && H.dna.check_mutation(HULK))
mutation_color = "00aa00"
else
mutation_color = ""
dmg_overlay_type = S.damage_overlay_type
else if(animal_origin == MONKEY_BODYPART) //currently monkeys are the only non human mob to have damage overlays.
dmg_overlay_type = animal_origin
if(status == BODYPART_ROBOTIC)
dmg_overlay_type = "robotic"
if(dropping_limb)
no_update = 1 //when attached, the limb won't be affected by the appearance changes of its mob owner.
//to update the bodypart's icon when not attached to a mob
/obj/item/bodypart/proc/update_icon_dropped()
cut_overlays()
var/list/standing = get_limb_icon(1)
if(!standing.len)
icon_state = initial(icon_state)//no overlays found, we default back to initial icon.
return
for(var/image/I in standing)
I.pixel_x = px_x
I.pixel_y = px_y
add_overlay(standing)
//Gives you a proper icon appearance for the dismembered limb
/obj/item/bodypart/proc/get_limb_icon(dropped)
icon_state = "" //to erase the default sprite, we're building the visual aspects of the bodypart through overlays alone.
. = list()
var/image_dir = 0
if(dropped)
image_dir = SOUTH
if(dmg_overlay_type)
if(brutestate)
. += image('icons/mob/dam_mob.dmi', "[dmg_overlay_type]_[body_zone]_[brutestate]0", -DAMAGE_LAYER, image_dir)
if(burnstate)
. += image('icons/mob/dam_mob.dmi', "[dmg_overlay_type]_[body_zone]_0[burnstate]", -DAMAGE_LAYER, image_dir)
var/image/limb = image(layer = -BODYPARTS_LAYER, dir = image_dir)
. += limb
if(animal_origin)
if(status == BODYPART_ORGANIC)
limb.icon = 'icons/mob/animal_parts.dmi'
if(species_id == "husk")
limb.icon_state = "[animal_origin]_husk_[body_zone]"
else
limb.icon_state = "[animal_origin]_[body_zone]"
else
limb.icon = 'icons/mob/augmentation/augments.dmi'
limb.icon_state = "[animal_origin]_[body_zone]"
return
var/icon_gender = (body_gender == FEMALE) ? "f" : "m" //gender of the icon, if applicable
if((body_zone != "head" && body_zone != "chest"))
should_draw_gender = FALSE
if(status == BODYPART_ORGANIC || (status == BODYPART_ROBOTIC && render_like_organic == TRUE)) // So IPC augments can be colorful without disrupting normal BODYPART_ROBOTIC render code.
if(should_draw_greyscale)
limb.icon = 'icons/mob/human_parts_greyscale.dmi'
if(should_draw_gender)
limb.icon_state = "[species_id]_[body_zone]_[icon_gender]"
else if(use_digitigrade)
limb.icon_state = "digitigrade_[use_digitigrade]_[body_zone]"
else
limb.icon_state = "[species_id]_[body_zone]"
else
limb.icon = 'icons/mob/human_parts.dmi'
if(should_draw_gender)
limb.icon_state = "[species_id]_[body_zone]_[icon_gender]"
else
limb.icon_state = "[species_id]_[body_zone]"
else
limb.icon = icon
if(should_draw_gender)
limb.icon_state = "[body_zone]_[icon_gender]"
else
limb.icon_state = "[body_zone]"
return
if(should_draw_greyscale)
var/draw_color = mutation_color || species_color || (skin_tone && skintone2hex(skin_tone))
if(draw_color)
limb.color = "#[draw_color]"
/obj/item/bodypart/deconstruct(disassembled = TRUE)
drop_organs()
qdel(src)
/obj/item/bodypart/chest
name = "chest"
desc = "It's impolite to stare at a person's chest."
icon_state = "default_human_chest"
max_damage = 200
body_zone = "chest"
body_part = CHEST
px_x = 0
px_y = 0
var/obj/item/cavity_item
/obj/item/bodypart/chest/Destroy()
if(cavity_item)
qdel(cavity_item)
return ..()
/obj/item/bodypart/chest/drop_organs(mob/user)
if(cavity_item)
cavity_item.forceMove(user.loc)
cavity_item = null
..()
/obj/item/bodypart/chest/monkey
icon = 'icons/mob/animal_parts.dmi'
icon_state = "default_monkey_chest"
animal_origin = MONKEY_BODYPART
/obj/item/bodypart/chest/alien
icon = 'icons/mob/animal_parts.dmi'
icon_state = "alien_chest"
dismemberable = 0
max_damage = 500
animal_origin = ALIEN_BODYPART
/obj/item/bodypart/chest/devil
dismemberable = 0
max_damage = 5000
animal_origin = DEVIL_BODYPART
/obj/item/bodypart/chest/larva
icon = 'icons/mob/animal_parts.dmi'
icon_state = "larva_chest"
dismemberable = 0
max_damage = 50
animal_origin = LARVA_BODYPART
/obj/item/bodypart/l_arm
name = "left arm"
desc = "Did you know that the word 'sinister' stems originally from the \
Latin 'sinestra' (left hand), because the left hand was supposed to \
be possessed by the devil? This arm appears to be possessed by no \
one though."
icon_state = "default_human_l_arm"
attack_verb = list("slapped", "punched")
max_damage = 50
body_zone ="l_arm"
body_part = ARM_LEFT
held_index = 1
px_x = -6
px_y = 0
/obj/item/bodypart/l_arm/monkey
icon = 'icons/mob/animal_parts.dmi'
icon_state = "default_monkey_l_arm"
animal_origin = MONKEY_BODYPART
px_x = -5
px_y = -3
/obj/item/bodypart/l_arm/alien
icon = 'icons/mob/animal_parts.dmi'
icon_state = "alien_l_arm"
px_x = 0
px_y = 0
dismemberable = 0
max_damage = 100
animal_origin = ALIEN_BODYPART
/obj/item/bodypart/l_arm/devil
dismemberable = 0
max_damage = 5000
animal_origin = DEVIL_BODYPART
/obj/item/bodypart/r_arm
name = "right arm"
desc = "Over 87% of humans are right handed. That figure is much lower \
among humans missing their right arm."
icon_state = "default_human_r_arm"
attack_verb = list("slapped", "punched")
max_damage = 50
body_zone = "r_arm"
body_part = ARM_RIGHT
held_index = 2
px_x = 6
px_y = 0
/obj/item/bodypart/r_arm/monkey
icon = 'icons/mob/animal_parts.dmi'
icon_state = "default_monkey_r_arm"
animal_origin = MONKEY_BODYPART
px_x = 5
px_y = -3
/obj/item/bodypart/r_arm/alien
icon = 'icons/mob/animal_parts.dmi'
icon_state = "alien_r_arm"
px_x = 0
px_y = 0
dismemberable = 0
max_damage = 100
animal_origin = ALIEN_BODYPART
/obj/item/bodypart/r_arm/devil
dismemberable = 0
max_damage = 5000
animal_origin = DEVIL_BODYPART
/obj/item/bodypart/l_leg
name = "left leg"
desc = "Some athletes prefer to tie their left shoelaces first for good \
luck. In this instance, it probably would not have helped."
icon_state = "default_human_l_leg"
attack_verb = list("kicked", "stomped")
max_damage = 50
body_zone = "l_leg"
body_part = LEG_LEFT
px_x = -2
px_y = 12
/obj/item/bodypart/l_leg/digitigrade
name = "left digitigrade leg"
use_digitigrade = FULL_DIGITIGRADE
/obj/item/bodypart/l_leg/monkey
icon = 'icons/mob/animal_parts.dmi'
icon_state = "default_monkey_l_leg"
animal_origin = MONKEY_BODYPART
px_y = 4
/obj/item/bodypart/l_leg/alien
icon = 'icons/mob/animal_parts.dmi'
icon_state = "alien_l_leg"
px_x = 0
px_y = 0
dismemberable = 0
max_damage = 100
animal_origin = ALIEN_BODYPART
/obj/item/bodypart/l_leg/devil
dismemberable = 0
max_damage = 5000
animal_origin = DEVIL_BODYPART
/obj/item/bodypart/r_leg
name = "right leg"
desc = "You put your right leg in, your right leg out. In, out, in, out, \
shake it all about. And apparently then it detaches.\n\
The hokey pokey has certainly changed a lot since space colonisation."
// alternative spellings of 'pokey' are availible
icon_state = "default_human_r_leg"
attack_verb = list("kicked", "stomped")
max_damage = 50
body_zone = "r_leg"
body_part = LEG_RIGHT
px_x = 2
px_y = 12
/obj/item/bodypart/r_leg/digitigrade
name = "right digitigrade leg"
use_digitigrade = FULL_DIGITIGRADE
/obj/item/bodypart/r_leg/monkey
icon = 'icons/mob/animal_parts.dmi'
icon_state = "default_monkey_r_leg"
animal_origin = MONKEY_BODYPART
px_y = 4
/obj/item/bodypart/r_leg/alien
icon = 'icons/mob/animal_parts.dmi'
icon_state = "alien_r_leg"
px_x = 0
px_y = 0
dismemberable = 0
max_damage = 100
animal_origin = ALIEN_BODYPART
/obj/item/bodypart/r_leg/devil
dismemberable = 0
max_damage = 5000
animal_origin = DEVIL_BODYPART
/////////////////////////////////////////////////////////////////////////
/obj/item/severedtail
name = "tail"
desc = "A severed tail. Somewhere, no doubt, a lizard hater is very \
pleased with themselves."
icon = 'icons/obj/surgery.dmi'
icon_state = "severedtail"
color = "#161"
var/markings = "Smooth"