From 443a4501ec575c27fb8a4844ca314c070513e57e Mon Sep 17 00:00:00 2001 From: phil235 Date: Mon, 12 Sep 2016 19:33:50 +0200 Subject: [PATCH] Carbon Dismemberment , second attempt. (#20461) * - I rearranged X_defense.dm mob files, more damage_procs.dm.Here's what's inside: * X_defense.dm: is for the procs of attacks onto the mob, all the XXX_act() proc (things happening to the mob), as well as protection check and get procs (armor, ear prot, projectile dismemberment) * damage_procs.dm: actual damage procs like adjustBruteLoss() getfireloss, any proc that handles damaging. - some bugfixes with gibspawner effects. - monkey's bodyparts can be dismembered and are used to create its icon. - brains are no longer carbons. - all carbon have bodyparts that can be dropped when the mob is gibbed. - adminspawned bodyparts now have a default icon. - robotic parts are now a child of bodyparts. - health analyzer on alien/monkey shows damage on each limb - added admin option to add/remove bodyparts for all carbon (instead of just remove on humans) - Fixes keycheck message spam for janicart and all when trying to move. - Fixes bug with buckling to a scooter while limbless. - removed arg "hit_zone" in proj's on_hit() because we can already use the def_zone var (where hit_zone got its value) - Fixes mob not getting any damage when hit by a projectile on their missing limb, despite a hit message shown). carbon/apply_damage() now when we specify a def_zone and the corresponding BP is missing we default to the chest instead of stopping the proc. Consistently with how human/attacked_by() default to its attack to chest if missing limb. - Fixes mini uzi icon when empty and no mag (typo). - I renamed and changed a bit check_eye_prot and ear prot - renamed flash_eyes to flash_act() - I made a soundbang_act() similar to flash_act but for loud bangs. - added a gib and dust animation to larva. - husked monkeys - no damage overlay for husk or skeleton. - damage overlay for robotic limb now. - no damage overlay when organic bodypart husked. - one handed human with a bloody hand still get a bloody single hand overlay. - fix admin heal being unable to heal robotic bodyparts. - slightly touched robotic bodypart sprites (head one pixel too high) - Fixes 18532 "beheaded husk has hair". - Fixes 18584 "Ling stasis appearance bug" - no more eyes or lipstick on husks. - can remove flashes/wires/cells from robot chest and head with crowbar. - Fixes not being able to surgically amputate robotic arm/leg. * More merge conflict fixes and adding the new files I forgot to add. * of course I forgot birdstation * More typos and stuff I forgot to undo. * Fixing a typo in examine.dm Removing an unnecessary check. Making admin heal regenerate limbs on all carbons. Monkey-human transformation now transfer missing limbs info and presence of a cavity implant. NODISMEMBER species can still lack a limb if the mob lacked a limb and changed into that new species. Changeling Regenerate ability now also regenerate limbs when in monkey form. (and remove some cryptic useless code) * Fixing more conflicts with remie's multihands PR. * Fixes runtime with hud when calling build_hand_slots(). Fixes lightgeist healing not working. Fixes null.handle_fall() runtimes with pirate mobs. Fixes typo in has_left_hadn() and has_right_hand(). * Derp, forgot to remove debug message. --- _maps/RandomZLevels/moonoutpost19.dmm | 2 +- _maps/map_files/BirdStation/BirdStation.dmm | 4 +- .../map_files/DreamStation/dreamstation04.dmm | 28 +- .../EfficiencyStation/EfficiencyStation.dmm | 4 +- _maps/map_files/MetaStation/MetaStation.dmm | 8 +- _maps/map_files/MiniStation/MiniStation.dmm | 4 +- _maps/map_files/TgStation/tgstation.2.1.3.dmm | 4 +- code/__DEFINES/genetics.dm | 8 + code/__DEFINES/is_helpers.dm | 2 +- code/__HELPERS/unsorted.dm | 2 +- code/_onclick/hud/generic_dextrous.dm | 9 + code/_onclick/hud/hud.dm | 4 +- code/_onclick/hud/human.dm | 1 - code/_onclick/hud/other_mobs.dm | 2 +- code/_onclick/item_attack.dm | 45 +- code/_onclick/other_mobs.dm | 69 ++- code/datums/datumvars.dm | 47 +- .../advance/symptoms/damage_converter.dm | 29 +- .../diseases/advance/symptoms/genetics.dm | 10 +- code/datums/diseases/dna_spread.dm | 2 +- code/datums/diseases/flu.dm | 4 +- code/datums/diseases/fluspanish.dm | 4 +- code/datums/dna.dm | 78 ++- code/datums/martial.dm | 2 +- code/datums/mutations.dm | 8 +- code/datums/weather/weather_types.dm | 7 +- code/game/atoms_movable.dm | 2 +- .../gamemodes/changeling/powers/regenerate.dm | 21 +- .../changeling/powers/strained_muscles.dm | 2 +- .../gamemodes/changeling/powers/tiny_prick.dm | 2 +- .../gamemodes/clock_cult/clock_scripture.dm | 8 +- .../gamemodes/clock_cult/clock_structures.dm | 4 +- code/game/gamemodes/cult/cult.dm | 1 - code/game/gamemodes/cult/ritual.dm | 2 +- code/game/gamemodes/cult/talisman.dm | 4 +- .../gamemodes/devil/true_devil/_true_devil.dm | 38 +- code/game/gamemodes/gang/gang.dm | 3 +- .../miniantags/abduction/abduction_gear.dm | 4 +- .../miniantags/abduction/abduction_surgery.dm | 6 +- .../abduction/machinery/experiment.dm | 2 +- code/game/gamemodes/objective.dm | 4 +- code/game/gamemodes/revolution/revolution.dm | 4 +- code/game/gamemodes/traitor/traitor.dm | 1 - code/game/gamemodes/wizard/artefact.dm | 3 +- code/game/gamemodes/wizard/raginmages.dm | 2 +- code/game/gamemodes/wizard/wizard.dm | 1 - code/game/machinery/cloning.dm | 8 +- code/game/machinery/computer/arcade.dm | 4 +- code/game/machinery/doors/airlock.dm | 4 +- code/game/machinery/flasher.dm | 2 +- code/game/machinery/rechargestation.dm | 2 +- code/game/machinery/robot_fabricator.dm | 20 +- .../telecomms/computers/logbrowser.dm | 2 +- .../mecha/equipment/tools/medical_tools.dm | 2 +- .../mecha/equipment/tools/mining_tools.dm | 6 +- code/game/mecha/mecha.dm | 6 +- .../effects/decals/Cleanable/aliens.dm | 36 +- .../effects/decals/Cleanable/humans.dm | 13 +- .../effects/decals/Cleanable/robots.dm | 9 +- code/game/objects/effects/decals/remains.dm | 3 + code/game/objects/effects/gibs.dm | 62 --- .../objects/effects/spawners/gibspawner.dm | 93 +++- code/game/objects/items.dm | 9 +- code/game/objects/items/crayons.dm | 2 +- code/game/objects/items/devices/flashlight.dm | 4 +- .../objects/items/devices/laserpointer.dm | 4 +- code/game/objects/items/devices/scanners.dm | 8 +- code/game/objects/items/robot/robot_items.dm | 53 +- code/game/objects/items/robot/robot_parts.dm | 185 ++----- code/game/objects/items/stacks/medical.dm | 51 +- .../game/objects/items/stacks/sheets/glass.dm | 9 +- .../items/weapons/grenades/flashbang.dm | 22 +- .../objects/items/weapons/grenades/plastic.dm | 2 +- .../items/weapons/grenades/spawnergrenade.dm | 2 +- code/game/objects/items/weapons/handcuffs.dm | 4 +- .../objects/items/weapons/melee/energy.dm | 2 +- code/game/objects/items/weapons/melee/misc.dm | 4 +- code/game/objects/items/weapons/shields.dm | 2 +- .../items/weapons/singularityhammer.dm | 2 +- .../objects/items/weapons/storage/book.dm | 73 +-- .../game/objects/items/weapons/tanks/tanks.dm | 2 +- code/game/objects/items/weapons/tools.dm | 4 +- code/game/objects/items/weapons/twohanded.dm | 2 +- code/modules/admin/verbs/manipulate_organs.dm | 3 +- code/modules/admin/verbs/randomverbs.dm | 8 +- code/modules/assembly/flash.dm | 6 +- code/modules/assembly/mousetrap.dm | 3 +- code/modules/client/verbs/suicide.dm | 2 +- code/modules/clothing/glasses/glasses.dm | 2 +- code/modules/crafting/recipes.dm | 16 +- code/modules/events/anomaly_bluespace.dm | 2 +- code/modules/hydroponics/grown/nettle.dm | 17 +- code/modules/mining/equipment.dm | 2 +- code/modules/mob/interactive.dm | 11 +- .../mob/living/{carbon => }/brain/MMI.dm | 395 +++++++------- .../mob/living/{carbon => }/brain/brain.dm | 130 ++--- .../living/{carbon => }/brain/brain_item.dm | 249 +++++---- .../mob/living/{carbon => }/brain/death.dm | 38 +- .../mob/living/{carbon => }/brain/emote.dm | 140 ++--- .../mob/living/{carbon => }/brain/life.dm | 109 ++-- .../living/{carbon => }/brain/posibrain.dm | 7 +- .../mob/living/{carbon => }/brain/say.dm | 44 +- .../living/{carbon => }/brain/status_procs.dm | 21 +- code/modules/mob/living/carbon/alien/alien.dm | 58 +- .../mob/living/carbon/alien/alien_defense.dm | 34 +- .../mob/living/carbon/alien/damage_procs.dm | 22 + code/modules/mob/living/carbon/alien/death.dm | 7 +- .../carbon/alien/humanoid/caste/drone.dm | 7 +- .../carbon/alien/humanoid/caste/hunter.dm | 2 +- .../carbon/alien/humanoid/caste/praetorian.dm | 8 +- .../carbon/alien/humanoid/caste/sentinel.dm | 10 +- .../living/carbon/alien/humanoid/humanoid.dm | 71 +-- .../carbon/alien/humanoid/humanoid_defense.dm | 59 +++ .../mob/living/carbon/alien/humanoid/queen.dm | 9 +- .../mob/living/carbon/alien/larva/death.dm | 15 + .../mob/living/carbon/alien/larva/larva.dm | 38 +- .../carbon/alien/larva/larva_defense.dm | 29 + code/modules/mob/living/carbon/alien/life.dm | 6 + .../carbon/alien/special/alien_embryo.dm | 2 +- .../living/carbon/alien/special/facehugger.dm | 5 +- .../mob/living/carbon/alien/update_icons.dm | 11 + code/modules/mob/living/carbon/carbon.dm | 220 +++----- .../mob/living/carbon/carbon_defense.dm | 220 ++++++-- .../mob/living/carbon/carbon_defines.dm | 11 +- .../mob/living/carbon/carbon_movement.dm | 9 +- .../modules/mob/living/carbon/damage_procs.dm | 191 +++++++ code/modules/mob/living/carbon/death.dm | 40 +- code/modules/mob/living/carbon/examine.dm | 85 +-- .../mob/living/carbon/human/damage_procs.dm | 5 + code/modules/mob/living/carbon/human/death.dm | 21 +- code/modules/mob/living/carbon/human/human.dm | 228 +------- .../living/carbon/human/human_attackalien.dm | 39 -- .../living/carbon/human/human_attackhand.dm | 14 - .../living/carbon/human/human_attackpaw.dm | 18 - .../mob/living/carbon/human/human_damage.dm | 161 ------ .../mob/living/carbon/human/human_defense.dm | 499 +++++++++++++----- .../mob/living/carbon/human/human_defines.dm | 6 - .../mob/living/carbon/human/human_helpers.dm | 18 - .../mob/living/carbon/human/inventory.dm | 11 +- .../mob/living/carbon/human/species.dm | 88 ++- .../mob/living/carbon/human/species_types.dm | 8 +- .../mob/living/carbon/human/status_procs.dm | 15 + .../mob/living/carbon/human/update_icons.dm | 143 +---- code/modules/mob/living/carbon/life.dm | 3 +- code/modules/mob/living/carbon/monkey/life.dm | 16 +- .../mob/living/carbon/monkey/monkey.dm | 204 +------ .../living/carbon/monkey/monkey_defense.dm | 188 +++++++ .../mob/living/carbon/monkey/update_icons.dm | 42 +- .../modules/mob/living/carbon/status_procs.dm | 19 +- .../modules/mob/living/carbon/update_icons.dm | 144 ++++- code/modules/mob/living/damage_procs.dm | 165 +++++- code/modules/mob/living/death.dm | 19 +- code/modules/mob/living/life.dm | 17 + code/modules/mob/living/living.dm | 279 +++------- code/modules/mob/living/living_defense.dm | 210 +++----- code/modules/mob/living/silicon/ai/ai.dm | 53 -- .../mob/living/silicon/ai/ai_defense.dm | 55 ++ .../mob/living/silicon/damage_procs.dm | 36 ++ code/modules/mob/living/silicon/death.dm | 2 +- code/modules/mob/living/silicon/pai/pai.dm | 55 -- .../mob/living/silicon/pai/pai_defense.dm | 49 ++ .../modules/mob/living/silicon/robot/death.dm | 3 - code/modules/mob/living/silicon/robot/life.dm | 4 - .../modules/mob/living/silicon/robot/robot.dm | 206 +------- .../mob/living/silicon/robot/robot_defense.dm | 182 +++++++ code/modules/mob/living/silicon/silicon.dm | 137 ----- .../mob/living/silicon/silicon_defense.dm | 97 ++++ .../living/simple_animal/animal_defense.dm | 117 ++++ .../mob/living/simple_animal/bot/cleanbot.dm | 2 +- .../living/simple_animal/bot/construction.dm | 17 +- .../mob/living/simple_animal/bot/ed209bot.dm | 4 +- .../mob/living/simple_animal/bot/floorbot.dm | 2 +- .../mob/living/simple_animal/bot/medbot.dm | 2 +- .../mob/living/simple_animal/bot/secbot.dm | 2 +- .../mob/living/simple_animal/damage_procs.dm | 30 ++ .../simple_animal/friendly/drone/_drone.dm | 2 +- .../friendly/drone/interaction.dm | 96 ++-- .../simple_animal/guardian/types/support.dm | 2 +- .../living/simple_animal/hostile/hostile.dm | 6 - .../hostile/megafauna/colossus.dm | 2 +- .../mob/living/simple_animal/simple_animal.dm | 171 +----- code/modules/mob/living/status_procs.dm | 59 ++- code/modules/mob/mob_helpers.dm | 5 +- code/modules/mob/status_procs.dm | 8 +- code/modules/mob/transform_procs.dm | 84 ++- code/modules/mob/update_icons.dm | 6 + .../suit/n_suit_verbs/ninja_sword_recall.dm | 3 - code/modules/power/antimatter/control.dm | 9 +- code/modules/power/cable.dm | 2 +- code/modules/power/lighting.dm | 3 +- code/modules/power/singularity/singularity.dm | 2 +- code/modules/projectiles/guns/projectile.dm | 2 +- .../projectiles/guns/projectile/revolver.dm | 2 +- code/modules/projectiles/projectile.dm | 18 +- code/modules/projectiles/projectile/beams.dm | 2 +- .../modules/projectiles/projectile/bullets.dm | 14 +- .../modules/projectiles/projectile/special.dm | 4 +- .../chemistry/reagents/alcohol_reagents.dm | 6 +- .../chemistry/reagents/drink_reagents.dm | 18 +- .../chemistry/reagents/food_reagents.dm | 8 +- .../chemistry/reagents/medicine_reagents.dm | 4 +- .../chemistry/reagents/other_reagents.dm | 2 +- .../chemistry/reagents/toxin_reagents.dm | 8 +- code/modules/reagents/chemistry/recipes.dm | 2 +- .../chemistry/recipes/pyrotechnics.dm | 27 +- .../chemistry/recipes/slime_extracts.dm | 4 +- .../designs/mechfabricator_designs.dm | 14 +- code/modules/spells/spell_types/barnyard.dm | 2 +- code/modules/spells/spell_types/lichdom.dm | 3 +- code/modules/surgery/amputation.dm | 9 +- code/modules/surgery/bodyparts/bodyparts.dm | 293 +++++++--- .../surgery/bodyparts/dismemberment.dm | 267 +++++----- code/modules/surgery/bodyparts/head.dm | 163 +++--- code/modules/surgery/bodyparts/helpers.dm | 143 +++-- .../surgery/bodyparts/robot_bodyparts.dm | 162 ++++++ code/modules/surgery/generic_steps.dm | 8 +- code/modules/surgery/helpers.dm | 20 +- code/modules/surgery/limb_augmentation.dm | 24 +- code/modules/surgery/organs/augments_eyes.dm | 2 +- code/modules/surgery/organs/helpers.dm | 5 +- .../modules/surgery/prosthetic_replacement.dm | 46 +- .../modules/surgery/remove_embedded_object.dm | 2 +- code/modules/surgery/surgery.dm | 10 +- code/modules/vehicles/scooter.dm | 13 +- code/modules/vehicles/vehicle.dm | 8 +- icons/effects/blood.dmi | Bin 98826 -> 106543 bytes icons/mob/animal_parts.dmi | Bin 0 -> 4681 bytes icons/mob/augments.dmi | Bin 1650 -> 1663 bytes icons/mob/dam_human.dmi | Bin 8883 -> 0 bytes icons/mob/dam_mob.dmi | Bin 0 -> 16165 bytes icons/mob/human_parts.dmi | Bin 9940 -> 11287 bytes icons/mob/mob.dmi | Bin 247205 -> 251564 bytes icons/obj/guns/projectile.dmi | Bin 29279 -> 29276 bytes tgstation.dme | 39 +- 234 files changed, 4926 insertions(+), 4116 deletions(-) delete mode 100644 code/game/objects/effects/gibs.dm rename code/modules/mob/living/{carbon => }/brain/MMI.dm (92%) rename code/modules/mob/living/{carbon => }/brain/brain.dm (50%) rename code/modules/mob/living/{carbon => }/brain/brain_item.dm (65%) rename code/modules/mob/living/{carbon => }/brain/death.dm (83%) rename code/modules/mob/living/{carbon => }/brain/emote.dm (91%) rename code/modules/mob/living/{carbon => }/brain/life.dm (57%) rename code/modules/mob/living/{carbon => }/brain/posibrain.dm (98%) rename code/modules/mob/living/{carbon => }/brain/say.dm (70%) rename code/modules/mob/living/{carbon => }/brain/status_procs.dm (52%) create mode 100644 code/modules/mob/living/carbon/alien/damage_procs.dm create mode 100644 code/modules/mob/living/carbon/alien/humanoid/humanoid_defense.dm create mode 100644 code/modules/mob/living/carbon/alien/larva/larva_defense.dm create mode 100644 code/modules/mob/living/carbon/alien/update_icons.dm create mode 100644 code/modules/mob/living/carbon/damage_procs.dm create mode 100644 code/modules/mob/living/carbon/human/damage_procs.dm delete mode 100644 code/modules/mob/living/carbon/human/human_attackalien.dm delete mode 100644 code/modules/mob/living/carbon/human/human_attackhand.dm delete mode 100644 code/modules/mob/living/carbon/human/human_attackpaw.dm delete mode 100644 code/modules/mob/living/carbon/human/human_damage.dm create mode 100644 code/modules/mob/living/carbon/human/status_procs.dm create mode 100644 code/modules/mob/living/carbon/monkey/monkey_defense.dm create mode 100644 code/modules/mob/living/silicon/ai/ai_defense.dm create mode 100644 code/modules/mob/living/silicon/damage_procs.dm create mode 100644 code/modules/mob/living/silicon/pai/pai_defense.dm create mode 100644 code/modules/mob/living/silicon/robot/robot_defense.dm create mode 100644 code/modules/mob/living/silicon/silicon_defense.dm create mode 100644 code/modules/mob/living/simple_animal/animal_defense.dm create mode 100644 code/modules/mob/living/simple_animal/damage_procs.dm create mode 100644 code/modules/surgery/bodyparts/robot_bodyparts.dm create mode 100644 icons/mob/animal_parts.dmi delete mode 100644 icons/mob/dam_human.dmi create mode 100644 icons/mob/dam_mob.dmi diff --git a/_maps/RandomZLevels/moonoutpost19.dmm b/_maps/RandomZLevels/moonoutpost19.dmm index 16ba61919d5b..e688e19691de 100644 --- a/_maps/RandomZLevels/moonoutpost19.dmm +++ b/_maps/RandomZLevels/moonoutpost19.dmm @@ -5810,7 +5810,7 @@ pixel_x = -5; pixel_y = -2 }, -/obj/item/robot_parts/l_arm, +/obj/item/bodypart/l_arm/robot, /turf/open/floor/plasteel/white{ heat_capacity = 1e+006 }, diff --git a/_maps/map_files/BirdStation/BirdStation.dmm b/_maps/map_files/BirdStation/BirdStation.dmm index 35ae80339e65..8fa869b173d7 100644 --- a/_maps/map_files/BirdStation/BirdStation.dmm +++ b/_maps/map_files/BirdStation/BirdStation.dmm @@ -446,8 +446,8 @@ dir = 1 }, /obj/structure/table, -/obj/item/robot_parts/r_arm, -/obj/item/robot_parts/l_arm, +/obj/item/bodypart/r_arm/robot, +/obj/item/bodypart/l_arm/robot, /turf/open/floor/mineral/titanium, /area/shuttle/syndicate) "abh" = ( diff --git a/_maps/map_files/DreamStation/dreamstation04.dmm b/_maps/map_files/DreamStation/dreamstation04.dmm index d3573c3e30b5..18420d099e97 100644 --- a/_maps/map_files/DreamStation/dreamstation04.dmm +++ b/_maps/map_files/DreamStation/dreamstation04.dmm @@ -1344,8 +1344,8 @@ /area/turret_protected/aisat_interior) "acv" = ( /obj/structure/table, -/obj/item/robot_parts/robot_suit, -/obj/item/robot_parts/head, +/obj/item/robot_suit, +/obj/item/bodypart/head/robot, /obj/machinery/atmospherics/pipe/simple/supply/hidden, /turf/open/floor/bluegrid, /area/turret_protected/aisat_interior) @@ -1418,9 +1418,9 @@ /area/turret_protected/aisat_interior) "acF" = ( /obj/structure/table, -/obj/item/robot_parts/l_arm, -/obj/item/robot_parts/chest, -/obj/item/robot_parts/l_arm, +/obj/item/bodypart/l_arm/robot, +/obj/item/bodypart/chest/robot, +/obj/item/bodypart/l_arm/robot, /obj/structure/cable/blue{ tag = "icon-2-8"; icon_state = "2-8" @@ -1443,7 +1443,7 @@ /area/turret_protected/aisat_interior) "acI" = ( /obj/structure/table, -/obj/item/robot_parts/r_arm, +/obj/item/bodypart/r_arm/robot, /obj/structure/cable/blue{ tag = "icon-2-4"; icon_state = "2-4" @@ -1511,7 +1511,7 @@ }, /obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden, /obj/item/device/assembly/flash/handheld, -/obj/item/robot_parts/r_leg, +/obj/item/bodypart/r_leg/robot, /turf/open/floor/plasteel/black, /area/turret_protected/aisat_interior) "acP" = ( @@ -1575,7 +1575,7 @@ /area/turret_protected/aisat_interior) "acU" = ( /obj/structure/table, -/obj/item/robot_parts/l_leg, +/obj/item/bodypart/l_leg/robot, /obj/structure/cable/blue{ tag = "icon-4-8"; icon_state = "4-8" @@ -3189,8 +3189,8 @@ dir = 1 }, /obj/structure/table, -/obj/item/robot_parts/r_arm, -/obj/item/robot_parts/l_arm, +/obj/item/bodypart/r_arm/robot, +/obj/item/bodypart/l_arm/robot, /turf/open/floor/mineral/titanium, /area/shuttle/syndicate) "agA" = ( @@ -16264,7 +16264,7 @@ /area/maintenance/fore) "aIo" = ( /obj/structure/rack, -/obj/item/robot_parts/l_arm, +/obj/item/bodypart/l_arm/robot, /obj/item/stack/sheet/metal{ amount = 2 }, @@ -17026,7 +17026,7 @@ "aJN" = ( /obj/structure/table, /obj/item/stack/cable_coil/green, -/obj/item/robot_parts/l_arm, +/obj/item/bodypart/l_arm/robot, /obj/item/weapon/storage/fancy/cigarettes/cigpack_robustgold, /obj/item/weapon/reagent_containers/food/drinks/mug/coco, /turf/open/floor/plating, @@ -18024,7 +18024,7 @@ /area/maintenance/port) "aMb" = ( /obj/effect/spawner/lootdrop/maintenance, -/obj/item/robot_parts/l_arm, +/obj/item/bodypart/l_arm/robot, /turf/open/floor/plating, /area/maintenance/port) "aMc" = ( @@ -63145,7 +63145,7 @@ /turf/open/floor/plating, /area/maintenance/apmaint) "cvz" = ( -/obj/item/robot_parts/l_arm, +/obj/item/bodypart/l_arm/robot, /obj/structure/closet, /obj/item/weapon/reagent_containers/glass/beaker/large, /obj/effect/spawner/lootdrop/maintenance, diff --git a/_maps/map_files/EfficiencyStation/EfficiencyStation.dmm b/_maps/map_files/EfficiencyStation/EfficiencyStation.dmm index 45e4e7482849..f7e7e86f1720 100644 --- a/_maps/map_files/EfficiencyStation/EfficiencyStation.dmm +++ b/_maps/map_files/EfficiencyStation/EfficiencyStation.dmm @@ -3505,8 +3505,8 @@ dir = 1 }, /obj/structure/table, -/obj/item/robot_parts/r_arm, -/obj/item/robot_parts/l_arm, +/obj/item/bodypart/r_arm/robot, +/obj/item/bodypart/l_arm/robot, /turf/open/floor/mineral/titanium, /area/shuttle/syndicate) "agJ" = ( diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index 1713fbaec401..ad6d1b744c13 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -55774,12 +55774,12 @@ d2 = 2; icon_state = "1-2" }, -/obj/item/robot_parts/chest{ +/obj/item/bodypart/chest/robot{ name = "cyborg torso"; pixel_x = -2; pixel_y = 2 }, -/obj/item/robot_parts/head{ +/obj/item/bodypart/head/robot{ name = "cyborg head"; pixel_x = 3; pixel_y = 2 @@ -90220,8 +90220,8 @@ dir = 1 }, /obj/structure/table, -/obj/item/robot_parts/r_arm, -/obj/item/robot_parts/l_arm, +/obj/item/bodypart/r_arm/robot, +/obj/item/bodypart/l_arm/robot, /turf/open/floor/mineral/titanium, /area/shuttle/syndicate) "cYu" = ( diff --git a/_maps/map_files/MiniStation/MiniStation.dmm b/_maps/map_files/MiniStation/MiniStation.dmm index 0db7e381bd77..4ce944db0599 100644 --- a/_maps/map_files/MiniStation/MiniStation.dmm +++ b/_maps/map_files/MiniStation/MiniStation.dmm @@ -14145,8 +14145,8 @@ dir = 1 }, /obj/structure/table, -/obj/item/robot_parts/r_arm, -/obj/item/robot_parts/l_arm, +/obj/item/bodypart/r_arm/robot, +/obj/item/bodypart/l_arm/robot, /turf/open/floor/mineral/titanium, /area/shuttle/syndicate) "Gv" = ( diff --git a/_maps/map_files/TgStation/tgstation.2.1.3.dmm b/_maps/map_files/TgStation/tgstation.2.1.3.dmm index d6a019fa8e28..cc62442653f0 100644 --- a/_maps/map_files/TgStation/tgstation.2.1.3.dmm +++ b/_maps/map_files/TgStation/tgstation.2.1.3.dmm @@ -54091,8 +54091,8 @@ dir = 1 }, /obj/structure/table, -/obj/item/robot_parts/r_arm, -/obj/item/robot_parts/l_arm, +/obj/item/bodypart/r_arm/robot, +/obj/item/bodypart/l_arm/robot, /turf/open/floor/mineral/titanium, /area/shuttle/syndicate) "coo" = ( diff --git a/code/__DEFINES/genetics.dm b/code/__DEFINES/genetics.dm index a9c91450c627..de99eca09179 100644 --- a/code/__DEFINES/genetics.dm +++ b/code/__DEFINES/genetics.dm @@ -84,6 +84,14 @@ #define ORGAN_ORGANIC 1 #define ORGAN_ROBOTIC 2 +#define BODYPART_ORGANIC 1 +#define BODYPART_ROBOTIC 2 + +#define MONKEY_BODYPART "monkey" +#define ALIEN_BODYPART "alien" +#define LARVA_BODYPART "larva" +#define DEVIL_BODYPART "devil" + //Nutrition levels for humans. No idea where else to put it #define NUTRITION_LEVEL_FAT 600 #define NUTRITION_LEVEL_FULL 550 diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index 1e66100e5512..fa2ad08b30b5 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -22,7 +22,7 @@ #define ismonkey(A) (istype(A, /mob/living/carbon/monkey)) -#define isbrain(A) (istype(A, /mob/living/carbon/brain)) +#define isbrain(A) (istype(A, /mob/living/brain)) #define isalien(A) (istype(A, /mob/living/carbon/alien)) diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 39892a67e3a9..a8f3703f2f77 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -337,7 +337,7 @@ Turf and target are seperate in case you want to teleport some distance from a t moblist.Add(M) for(var/mob/living/carbon/human/M in sortmob) moblist.Add(M) - for(var/mob/living/carbon/brain/M in sortmob) + for(var/mob/living/brain/M in sortmob) moblist.Add(M) for(var/mob/living/carbon/alien/M in sortmob) moblist.Add(M) diff --git a/code/_onclick/hud/generic_dextrous.dm b/code/_onclick/hud/generic_dextrous.dm index 509af712b902..bb0bac5d4cee 100644 --- a/code/_onclick/hud/generic_dextrous.dm +++ b/code/_onclick/hud/generic_dextrous.dm @@ -60,3 +60,12 @@ for(var/obj/item/I in D.held_items) I.screen_loc = null D.client.screen -= I + + +//Dextrous simple mobs can use hands! +/mob/living/simple_animal/create_mob_hud() + if(client && !hud_used) + if(dextrous) + hud_used = new dextrous_hud_type(src, ui_style2icon(client.prefs.UI_style)) + else + ..() diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm index a7930dc8c2c6..623b49723ae9 100644 --- a/code/_onclick/hud/hud.dm +++ b/code/_onclick/hud/hud.dm @@ -241,5 +241,5 @@ i++ for(var/obj/screen/human/equip/E in static_inventory) E.screen_loc = ui_equip_position(mymob) - - show_hud(HUD_STYLE_STANDARD,mymob) \ No newline at end of file + if(mymob.hud_used) + show_hud(HUD_STYLE_STANDARD,mymob) \ No newline at end of file diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm index 53b7ce8a0c9f..93f36820fd87 100644 --- a/code/_onclick/hud/human.dm +++ b/code/_onclick/hud/human.dm @@ -358,7 +358,6 @@ var/mob/living/carbon/human/H = mymob var/mob/screenmob = viewer || H - if(screenmob.hud_used.hud_shown) if(H.s_store) H.s_store.screen_loc = ui_sstore1 diff --git a/code/_onclick/hud/other_mobs.dm b/code/_onclick/hud/other_mobs.dm index 2bbc92c7cd45..ac42696bc569 100644 --- a/code/_onclick/hud/other_mobs.dm +++ b/code/_onclick/hud/other_mobs.dm @@ -7,7 +7,7 @@ mymob.client.screen = list() mymob.client.screen += mymob.client.void -/mob/living/carbon/brain/create_mob_hud() +/mob/living/brain/create_mob_hud() if(client && !hud_used) hud_used = new /datum/hud/brain(src) diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 838f913536f7..ced66536d873 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -34,6 +34,8 @@ user.lastattacked = M M.lastattacker = user + if(user != M) + user.do_attack_animation(M) M.attacked_by(src, user) add_logs(user, M, "attacked", src.name, "(INTENT: [uppertext(user.a_intent)]) (DAMTYPE: [uppertext(damtype)])") @@ -58,19 +60,27 @@ user.visible_message("[user] has hit [src] with [I]!", "You hit [src] with [I]!") /mob/living/attacked_by(obj/item/I, mob/living/user) - if(user != src) - user.do_attack_animation(src) - if(send_item_attack_message(I, user)) - if(apply_damage(I.force, I.damtype)) - if(I.damtype == BRUTE) - if(prob(33)) - I.add_mob_blood(src) - var/turf/location = get_turf(src) - add_splatter_floor(location) - if(get_dist(user, src) <= 1) //people with TK won't get smeared with blood - user.add_mob_blood(src) - return TRUE + send_item_attack_message(I, user) + if(I.force) + apply_damage(I.force, I.damtype) + if(I.damtype == BRUTE) + if(prob(33)) + I.add_mob_blood(src) + var/turf/location = get_turf(src) + add_splatter_floor(location) + if(get_dist(user, src) <= 1) //people with TK won't get smeared with blood + user.add_mob_blood(src) + return TRUE //successful attack +/mob/living/simple_animal/attacked_by(obj/item/I, mob/living/user) + if(!I.force) + user.visible_message("[user] gently taps [src] with [I].",\ + "This weapon is ineffective, it does no damage!") + else if(I.force < force_threshold || I.damtype == STAMINA) + visible_message("[I] bounces harmlessly off of [src].",\ + "[I] bounces harmlessly off of [src]!") + else + return ..() // Proximity_flag is 1 if this afterattack was called on something adjacent, in your square, or on your person. // Click parameters is the params string from byond Click() code, see that documentation. @@ -90,7 +100,7 @@ if(I.attack_verb && I.attack_verb.len) message_verb = "[pick(I.attack_verb)]" else if(!I.force) - return 0 + return var/message_hit_area = "" if(hit_area) message_hit_area = " in the [hit_area]" @@ -102,12 +112,3 @@ "[attack_message]") return 1 -/mob/living/simple_animal/send_item_attack_message(obj/item/I, mob/living/user, hit_area) - if(!I.force) - user.visible_message("[user] gently taps [src] with [I].",\ - "This weapon is ineffective, it does no damage!") - else if(I.force < force_threshold || I.damtype == STAMINA) - visible_message("[I] bounces harmlessly off of [src].",\ - "[I] bounces harmlessly off of [src]!") - else - return ..() diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm index 95c2ff9836ac..f6986e8d4f13 100644 --- a/code/_onclick/other_mobs.dm +++ b/code/_onclick/other_mobs.dm @@ -50,9 +50,8 @@ for(var/datum/mutation/human/HM in dna.mutations) HM.on_ranged_attack(src, A) - var/turf/T = A - if(istype(T) && get_dist(src,T) <= 1) - src.Move_Pulled(T) + if(isturf(A) && get_dist(src,A) <= 1) + src.Move_Pulled(A) /* Animals & All Unspecified @@ -111,7 +110,7 @@ */ /mob/living/carbon/alien/UnarmedAttack(atom/A) A.attack_alien(src) -/atom/proc/attack_alien(mob/user) +/atom/proc/attack_alien(mob/living/carbon/alien/user) attack_paw(user) return /mob/living/carbon/alien/RestrainedClickOn(atom/A) @@ -135,6 +134,68 @@ /mob/living/simple_animal/slime/RestrainedClickOn(atom/A) return + +/* + Drones +*/ +/mob/living/simple_animal/drone/UnarmedAttack(atom/A) + A.attack_drone(src) + +/atom/proc/attack_drone(mob/living/simple_animal/drone/user) + attack_hand(user) //defaults to attack_hand. Override it when you don't want drones to do same stuff as humans. + +/mob/living/simple_animal/slime/RestrainedClickOn(atom/A) + return + + +/* + True Devil +*/ + +/mob/living/carbon/true_devil/UnarmedAttack(atom/A, proximity) + A.attack_hand(src) + +/* + Brain +*/ + +/mob/living/brain/UnarmedAttack(atom/A)//Stops runtimes due to attack_animal being the default + return + + +/* + pAI +*/ + +/mob/living/silicon/pai/UnarmedAttack(atom/A)//Stops runtimes due to attack_animal being the default + return + + +/* + Simple animals +*/ + +/mob/living/simple_animal/UnarmedAttack(atom/A, proximity) + if(!dextrous) + return ..() + if(!ismob(A)) + A.attack_hand(src) + update_inv_hands() + + +/* + Hostile animals +*/ + +/mob/living/simple_animal/hostile/UnarmedAttack(atom/A) + target = A + if(dextrous && !is_type_in_typecache(A, environment_target_typecache) && !ismob(A)) + ..() + else + AttackingTarget() + + + /* New Players: Have no reason to click on anything at all. diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm index ed93eb9369a7..5b251a3edfa2 100644 --- a/code/datums/datumvars.dm +++ b/code/datums/datumvars.dm @@ -279,11 +279,11 @@ var/global/list/internal_byond_list_vars = list("contents" = TRUE, "verbs" = TRU if(iscarbon(D)) body += "" body += "" + body += "" body += "" if(ishuman(D)) body += "" body += "" - body += "" body += "" body += "" body += "" @@ -898,25 +898,51 @@ body var/newtype = species_list[result] H.set_species(newtype) - else if(href_list["removebodypart"]) + else if(href_list["editbodypart"]) if(!check_rights(R_SPAWN)) return - var/mob/living/carbon/human/H = locate(href_list["removebodypart"]) - if(!istype(H)) - usr << "This can only be done to instances of type /mob/living/carbon/human" + var/mob/living/carbon/C = locate(href_list["editbodypart"]) + if(!istype(C)) + usr << "This can only be done to instances of type /mob/living/carbon" return - var/result = input(usr, "Please choose which body part to remove","Remove Body Part") as null|anything in list("head", "l_arm", "r_arm", "l_leg", "r_leg") + var/edit_action = input(usr, "What would you like to do?","Modify Body Part") as null|anything in list("add","remove", "augment") + if(!edit_action) + return + var/list/limb_list = list("head", "l_arm", "r_arm", "l_leg", "r_leg") + if(edit_action == "augment") + limb_list += "chest" + var/result = input(usr, "Please choose which body part to [edit_action]","[capitalize(edit_action)] Body Part") as null|anything in limb_list - if(!H) + if(!C) usr << "Mob doesn't exist anymore" return if(result) - var/obj/item/bodypart/BP = H.get_bodypart(result) - if(BP) - BP.drop_limb() + var/obj/item/bodypart/BP = C.get_bodypart(result) + switch(edit_action) + if("remove") + if(BP) + BP.drop_limb() + else + usr << "[C] doesn't have such bodypart." + if("add") + if(BP) + usr << "[C] already has such bodypart." + else + if(!C.regenerate_limb(result)) + usr << "[C] cannot have such bodypart." + if("augment") + if(ishuman(C)) + if(BP) + BP.change_bodypart_status(BODYPART_ROBOTIC, 1) + else + usr << "[C] doesn't have such bodypart." + else + usr << "Only humans can be augmented." + + else if(href_list["purrbation"]) if(!check_rights(R_SPAWN)) @@ -985,3 +1011,4 @@ body log_admin("[key_name(usr)] dealt [amount] amount of [Text] damage to [L] ") message_admins("[key_name(usr)] dealt [amount] amount of [Text] damage to [L] ") href_list["datumrefresh"] = href_list["mobToDamage"] + diff --git a/code/datums/diseases/advance/symptoms/damage_converter.dm b/code/datums/diseases/advance/symptoms/damage_converter.dm index ba315278a200..f9109df17c17 100644 --- a/code/datums/diseases/advance/symptoms/damage_converter.dm +++ b/code/datums/diseases/advance/symptoms/damage_converter.dm @@ -33,30 +33,19 @@ Bonus Convert(M) return -/datum/symptom/damage_converter/proc/Convert(mob/living/M) +/datum/symptom/damage_converter/proc/Convert(mob/living/carbon/C) - var/get_damage = rand(1, 2) + var/heal_amt = rand(1, 2) - if(istype(M, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = M + var/list/parts = C.get_damaged_bodyparts(1,1) //1,1 because it needs inputs. - var/list/parts = H.get_damaged_bodyparts(1,1) //1,1 because it needs inputs. - - if(!parts.len) - return - - for(var/obj/item/bodypart/L in parts) - L.heal_damage(get_damage, get_damage, 0) - M.adjustToxLoss(get_damage*parts.len) - - else - if(M.getFireLoss() > 0 || M.getBruteLoss() > 0) - M.adjustFireLoss(-get_damage) - M.adjustBruteLoss(-get_damage) - M.adjustToxLoss(get_damage) - else - return + if(!parts.len) + return + for(var/obj/item/bodypart/L in parts) + if(L.heal_damage(heal_amt, heal_amt)) + C.update_damage_overlays() + C.adjustToxLoss(heal_amt*parts.len) return 1 /* diff --git a/code/datums/diseases/advance/symptoms/genetics.dm b/code/datums/diseases/advance/symptoms/genetics.dm index 3a5dc527f092..e3ffbc868ba5 100644 --- a/code/datums/diseases/advance/symptoms/genetics.dm +++ b/code/datums/diseases/advance/symptoms/genetics.dm @@ -30,14 +30,14 @@ Bonus /datum/symptom/genetic_mutation/Activate(datum/disease/advance/A) ..() if(prob(SYMPTOM_ACTIVATION_PROB * 5)) // 15% chance - var/mob/living/carbon/M = A.affected_mob - if(!M.has_dna()) + var/mob/living/carbon/C = A.affected_mob + if(!C.has_dna()) return switch(A.stage) if(4, 5) - M << "[pick("Your skin feels itchy.", "You feel light headed.")]" - M.dna.remove_mutation_group(possible_mutations) - randmut(M, possible_mutations) + C << "[pick("Your skin feels itchy.", "You feel light headed.")]" + C.dna.remove_mutation_group(possible_mutations) + C.randmut(possible_mutations) return // Archive their DNA before they were infected. diff --git a/code/datums/diseases/dna_spread.dm b/code/datums/diseases/dna_spread.dm index 11a8eebbe5dc..626fb567c3dd 100644 --- a/code/datums/diseases/dna_spread.dm +++ b/code/datums/diseases/dna_spread.dm @@ -38,7 +38,7 @@ if(prob(1)) affected_mob << "Your muscles ache." if(prob(20)) - affected_mob.take_organ_damage(1) + affected_mob.take_bodypart_damage(1) if(prob(1)) affected_mob << "Your stomach hurts." if(prob(20)) diff --git a/code/datums/diseases/flu.dm b/code/datums/diseases/flu.dm index 1df55bbb9d7f..20bea2da9220 100644 --- a/code/datums/diseases/flu.dm +++ b/code/datums/diseases/flu.dm @@ -26,7 +26,7 @@ if(prob(1)) affected_mob << "Your muscles ache." if(prob(20)) - affected_mob.take_organ_damage(1) + affected_mob.take_bodypart_damage(1) if(prob(1)) affected_mob << "Your stomach hurts." if(prob(20)) @@ -45,7 +45,7 @@ if(prob(1)) affected_mob << "Your muscles ache." if(prob(20)) - affected_mob.take_organ_damage(1) + affected_mob.take_bodypart_damage(1) if(prob(1)) affected_mob << "Your stomach hurts." if(prob(20)) diff --git a/code/datums/diseases/fluspanish.dm b/code/datums/diseases/fluspanish.dm index c041f2610de6..57ded9abc309 100644 --- a/code/datums/diseases/fluspanish.dm +++ b/code/datums/diseases/fluspanish.dm @@ -22,7 +22,7 @@ affected_mob.emote("cough") if(prob(1)) affected_mob << "You're burning in your own skin!" - affected_mob.take_organ_damage(0,5) + affected_mob.take_bodypart_damage(0,5) if(3) affected_mob.bodytemperature += 20 @@ -32,5 +32,5 @@ affected_mob.emote("cough") if(prob(5)) affected_mob << "You're burning in your own skin!" - affected_mob.take_organ_damage(0,5) + affected_mob.take_bodypart_damage(0,5) return diff --git a/code/datums/dna.dm b/code/datums/dna.dm index ee19e8483a6e..e3d88e8b15e4 100644 --- a/code/datums/dna.dm +++ b/code/datums/dna.dm @@ -11,13 +11,15 @@ var/list/mutations = list() //All mutations are from now on here var/list/temporary_mutations = list() //Timers for temporary mutations var/list/previous = list() //For temporary name/ui/ue/blood_type modifications - var/mob/living/carbon/holder + var/mob/living/holder -/datum/dna/New(mob/living/carbon/new_holder) +/datum/dna/New(mob/living/new_holder) if(new_holder) holder = new_holder /datum/dna/proc/transfer_identity(mob/living/carbon/destination, transfer_SE = 0) + if(!istype(destination)) + return destination.dna.unique_enzymes = unique_enzymes destination.dna.uni_identity = uni_identity destination.dna.blood_type = blood_type @@ -166,12 +168,36 @@ features = random_features() +/datum/dna/stored //subtype used by brain mob's stored_dna + +/datum/dna/stored/add_mutation(mutation_name) //no mutation changes on stored dna. + return + +/datum/dna/stored/remove_mutation(mutation_name) + return + +/datum/dna/stored/check_mutation(mutation_name) + return + +/datum/dna/stored/remove_all_mutations() + return + +/datum/dna/stored/remove_mutation_group(list/group) + return /////////////////////////// DNA MOB-PROCS ////////////////////// /mob/proc/set_species(datum/species/mrace, icon_update = 1) return +/mob/living/brain/set_species(datum/species/mrace, icon_update = 1) + if(mrace) + if(ispath(mrace)) + stored_dna.species = new mrace() + else + stored_dna.species = mrace //not calling any species update procs since we're a brain, not a monkey/human + + /mob/living/carbon/set_species(datum/species/mrace, icon_update = 1) if(mrace && has_dna()) dna.species.on_species_loss(src) @@ -290,48 +316,46 @@ mob/living/carbon/human/updateappearance(icon_update=1, mutcolor_update=0, mutat return 0 return getleftblocks(istring, blocknumber, blocksize) + replacement + getrightblocks(istring, blocknumber, blocksize) -/proc/randmut(mob/living/carbon/M, list/candidates, difficulty = 2) - if(!M.has_dna()) +/mob/living/carbon/proc/randmut(list/candidates, difficulty = 2) + if(!has_dna()) return var/datum/mutation/human/num = pick(candidates) - . = num.force_give(M) - return + . = num.force_give(src) -/proc/randmutb(mob/living/carbon/M) - if(!M.has_dna()) +/mob/living/carbon/proc/randmutb() + if(!has_dna()) return var/datum/mutation/human/HM = pick((bad_mutations | not_good_mutations) - mutations_list[RACEMUT]) - . = HM.force_give(M) + . = HM.force_give(src) -/proc/randmutg(mob/living/carbon/M) - if(!M.has_dna()) +/mob/living/carbon/proc/randmutg() + if(!has_dna()) return var/datum/mutation/human/HM = pick(good_mutations) - . = HM.force_give(M) + . = HM.force_give(src) -/proc/randmutvg(mob/living/carbon/M) - if(!M.has_dna()) +/mob/living/carbon/proc/randmutvg() + if(!has_dna()) return var/datum/mutation/human/HM = pick((good_mutations) - mutations_list[HULK] - mutations_list[DWARFISM]) - . = HM.force_give(M) + . = HM.force_give(src) -/proc/randmuti(mob/living/carbon/M) - if(!M.has_dna()) +/mob/living/carbon/proc/randmuti() + if(!has_dna()) return var/num = rand(1, DNA_UNI_IDENTITY_BLOCKS) - var/newdna = setblock(M.dna.uni_identity, num, random_string(DNA_BLOCK_SIZE, hex_characters)) - M.dna.uni_identity = newdna - M.updateappearance(mutations_overlay_update=1) - return + var/newdna = setblock(dna.uni_identity, num, random_string(DNA_BLOCK_SIZE, hex_characters)) + dna.uni_identity = newdna + updateappearance(mutations_overlay_update=1) -/proc/clean_dna(mob/living/carbon/M) - if(!M.has_dna()) +/mob/living/carbon/proc/clean_dna() + if(!has_dna()) return - M.dna.remove_all_mutations() + dna.remove_all_mutations() -/proc/clean_randmut(mob/living/carbon/M, list/candidates, difficulty = 2) - clean_dna(M) - randmut(M, candidates, difficulty) +/mob/living/carbon/proc/clean_randmut(list/candidates, difficulty = 2) + clean_dna() + randmut(candidates, difficulty) /proc/scramble_dna(mob/living/carbon/M, ui=FALSE, se=FALSE, probability) if(!M.has_dna()) diff --git a/code/datums/martial.dm b/code/datums/martial.dm index 0a93341a63d2..9b9cfb3c3d68 100644 --- a/code/datums/martial.dm +++ b/code/datums/martial.dm @@ -482,7 +482,7 @@ var/mob/living/carbon/human/H = user H.apply_damage(2*force, BRUTE, "head") else - user.take_organ_damage(2*force) + user.take_bodypart_damage(2*force) return if(isrobot(target)) return ..() diff --git a/code/datums/mutations.dm b/code/datums/mutations.dm index af57e091efa9..6ac88edf0507 100644 --- a/code/datums/mutations.dm +++ b/code/datums/mutations.dm @@ -187,7 +187,7 @@ /datum/mutation/human/cold_resistance/on_life(mob/living/carbon/human/owner) if(owner.getFireLoss()) if(prob(1)) - owner.heal_organ_damage(0,1) //Is this really needed? + owner.heal_bodypart_damage(0,1) //Is this really needed? /datum/mutation/human/x_ray @@ -252,11 +252,11 @@ var/mob/new_mob if(prob(95)) if(prob(50)) - new_mob = randmutb(owner) + new_mob = owner.randmutb() else - new_mob = randmuti(owner) + new_mob = owner.randmuti() else - new_mob = randmutg(owner) + new_mob = owner.randmutg() if(new_mob && ismob(new_mob)) owner = new_mob . = owner diff --git a/code/datums/weather/weather_types.dm b/code/datums/weather/weather_types.dm index 9f75bf714e67..6213eacc75c0 100644 --- a/code/datums/weather/weather_types.dm +++ b/code/datums/weather/weather_types.dm @@ -150,15 +150,14 @@ if(H.dna && H.dna.species) if(!(RADIMMUNE in H.dna.species.specflags)) if(prob(max(0,100-resist))) - randmuti(H) + H.randmuti() if(prob(50)) if(prob(90)) - randmutb(H) + H.randmutb() else - randmutg(H) + H.randmutg() H.domutcheck() L.rad_act(20,1) - /datum/weather/rad_storm/end() if(..()) return diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index ef0611a9cd77..8162b451dc82 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -146,7 +146,7 @@ reset_perspective(destination) update_canmove() //if the mob was asleep inside a container and then got forceMoved out we need to make them fall. -/mob/living/carbon/brain/forceMove(atom/destination) +/mob/living/brain/forceMove(atom/destination) if(container) container.forceMove(destination) else //something went very wrong. diff --git a/code/game/gamemodes/changeling/powers/regenerate.dm b/code/game/gamemodes/changeling/powers/regenerate.dm index f14c1c957807..6d38a58cc471 100644 --- a/code/game/gamemodes/changeling/powers/regenerate.dm +++ b/code/game/gamemodes/changeling/powers/regenerate.dm @@ -13,21 +13,20 @@ /obj/effect/proc_holder/changeling/regenerate/sting_action(mob/living/user) user << "You feel an itching, both inside and \ outside as your tissues knit and reknit." - if(ishuman(user)) - var/mob/living/carbon/human/H = user - H.restore_blood() - H.remove_all_embedded_objects() - var/list/missing = H.get_missing_limbs() + if(iscarbon(user)) + var/mob/living/carbon/C = user + var/list/missing = C.get_missing_limbs() if(missing.len) playsound(user, 'sound/magic/Demon_consume.ogg', 50, 1) - H.visible_message("[user]'s missing limbs \ + C.visible_message("[user]'s missing limbs \ reform, making a loud, grotesque sound!", "Your limbs regrow, making a \ loud, crunchy sound and giving you great pain!", "You hear organic matter ripping \ and tearing!") - H.emote("scream") - H.regenerate_limbs(1) - - CHECK_DNA_AND_SPECIES(H) - H.dna.species.on_species_gain(H, H.dna.species) + C.emote("scream") + C.regenerate_limbs(1) + if(ishuman(user)) + var/mob/living/carbon/human/H = user + H.restore_blood() + H.remove_all_embedded_objects() diff --git a/code/game/gamemodes/changeling/powers/strained_muscles.dm b/code/game/gamemodes/changeling/powers/strained_muscles.dm index 1c7ce8d11a51..79c707bff04d 100644 --- a/code/game/gamemodes/changeling/powers/strained_muscles.dm +++ b/code/game/gamemodes/changeling/powers/strained_muscles.dm @@ -33,7 +33,7 @@ break stacks++ - //user.take_organ_damage(stacks * 0.03, 0) + //user.take_bodypart_damage(stacks * 0.03, 0) user.staminaloss += stacks * 1.3 //At first the changeling may regenerate stamina fast enough to nullify fatigue, but it will stack if(stacks == 11) //Warning message that the stacks are getting too high diff --git a/code/game/gamemodes/changeling/powers/tiny_prick.dm b/code/game/gamemodes/changeling/powers/tiny_prick.dm index ea792abe4b3b..9f3df575613e 100644 --- a/code/game/gamemodes/changeling/powers/tiny_prick.dm +++ b/code/game/gamemodes/changeling/powers/tiny_prick.dm @@ -97,7 +97,7 @@ var/mob/living/carbon/C = target if(C.status_flags & CANWEAKEN) C.do_jitter_animation(500) - C.take_organ_damage(20, 0) //The process is extremely painful + C.take_bodypart_damage(20, 0) //The process is extremely painful target.visible_message("[target] begins to violenty convulse!","You feel a tiny prick and a begin to uncontrollably convulse!") spawn(10) diff --git a/code/game/gamemodes/clock_cult/clock_scripture.dm b/code/game/gamemodes/clock_cult/clock_scripture.dm index 28f3574c91c1..a05c1fe0b7c8 100644 --- a/code/game/gamemodes/clock_cult/clock_scripture.dm +++ b/code/game/gamemodes/clock_cult/clock_scripture.dm @@ -546,10 +546,12 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed var/mob/living/carbon/human/H = invoker for(var/X in H.bodyparts) var/obj/item/bodypart/BP = X - if(ratvar_awakens || BP.status == ORGAN_ROBOTIC && total_power_drained < augument_damage_threshhold) //if ratvar is alive, it won't damage and will always heal augumented limbs - BP.heal_damage(power_damage, power_damage, 1) //heals one point of burn and brute for every ~100W drained on augumented limbs + if(ratvar_awakens || BP.status == BODYPART_ROBOTIC && total_power_drained < augument_damage_threshhold) //if ratvar is alive, it won't damage and will always heal augumented limbs + if(BP.heal_damage(power_damage, power_damage, 1, 0)) //heals one point of burn and brute for every ~100W drained on augumented limbs + H.update_damage_overlays() else - BP.take_damage(0, power_damage) + if(BP.take_damage(0, power_damage)) + H.update_damage_overlays() else if(isanimal(invoker)) var/mob/living/simple_animal/A = invoker A.adjustHealth(-power_damage) //if a simple animal is using volt void, just heal it diff --git a/code/game/gamemodes/clock_cult/clock_structures.dm b/code/game/gamemodes/clock_cult/clock_structures.dm index 83477d09822c..ca63657de887 100644 --- a/code/game/gamemodes/clock_cult/clock_structures.dm +++ b/code/game/gamemodes/clock_cult/clock_structures.dm @@ -711,10 +711,10 @@ color = "#FAE48C" /obj/effect/clockwork/sigil/transgression/sigil_effects(mob/living/L) - var/target_flashed = L.flash_eyes() + var/target_flashed = L.flash_act() for(var/mob/living/M in viewers(5, src)) if(!is_servant_of_ratvar(M) && M != L) - M.flash_eyes() + M.flash_act() if(iscultist(L)) L << "\"Watch your step, wretch.\"" L.adjustBruteLoss(10) diff --git a/code/game/gamemodes/cult/cult.dm b/code/game/gamemodes/cult/cult.dm index 2676bc21aea3..b80a7e692eaa 100644 --- a/code/game/gamemodes/cult/cult.dm +++ b/code/game/gamemodes/cult/cult.dm @@ -150,7 +150,6 @@ return 0 else mob << "You have a [item_name] in your [where]." - mob.update_icons() if(where == "backpack") var/obj/item/weapon/storage/B = mob.back B.orient2hud(mob) diff --git a/code/game/gamemodes/cult/ritual.dm b/code/game/gamemodes/cult/ritual.dm index fb375070f9d5..92922f8e5ba6 100644 --- a/code/game/gamemodes/cult/ritual.dm +++ b/code/game/gamemodes/cult/ritual.dm @@ -34,7 +34,7 @@ This file contains the arcane tome files. M.reagents.add_reagent("unholywater",holy2unholy) add_logs(user, M, "smacked", src, " removing the holy water from them") return - M.take_organ_damage(0, 15) //Used to be a random between 5 and 20 + M.take_bodypart_damage(0, 15) //Used to be a random between 5 and 20 playsound(M, 'sound/weapons/sear.ogg', 50, 1) M.visible_message("[user] strikes [M] with the arcane tome!", \ "[user] strikes you with the tome, searing your flesh!") diff --git a/code/game/gamemodes/cult/talisman.dm b/code/game/gamemodes/cult/talisman.dm index 08e09f57fcba..93a2cb6e18a4 100644 --- a/code/game/gamemodes/cult/talisman.dm +++ b/code/game/gamemodes/cult/talisman.dm @@ -253,7 +253,7 @@ else target.Weaken(10) target.Stun(10) - target.flash_eyes(1,1) + target.flash_act(1,1) if(issilicon(target)) var/mob/living/silicon/S = target S.emp_act(1) @@ -316,7 +316,7 @@ target << "You see a brief but horrible vision of Ratvar, rusted and scrapped, being torn apart." target.emote("scream") target.confused = max(0, target.confused + 3) - target.flash_eyes() + target.flash_act() qdel(src) diff --git a/code/game/gamemodes/devil/true_devil/_true_devil.dm b/code/game/gamemodes/devil/true_devil/_true_devil.dm index 8e91c964dab7..22bb549558d2 100644 --- a/code/game/gamemodes/devil/true_devil/_true_devil.dm +++ b/code/game/gamemodes/devil/true_devil/_true_devil.dm @@ -22,13 +22,20 @@ mob_size = MOB_SIZE_LARGE var/mob/living/oldform var/list/devil_overlays[DEVIL_TOTAL_LAYERS] + bodyparts = list(/obj/item/bodypart/chest/devil, /obj/item/bodypart/head/devil, /obj/item/bodypart/l_arm/devil, + /obj/item/bodypart/r_arm/devil, /obj/item/bodypart/r_leg/devil, /obj/item/bodypart/l_leg/devil) + + /mob/living/carbon/true_devil/New() - internal_organs += new /obj/item/organ/brain/ + create_bodyparts() //initialize bodyparts + + create_internal_organs() + ..() + +/mob/living/carbon/true_devil/create_internal_organs() + internal_organs += new /obj/item/organ/brain internal_organs += new /obj/item/organ/tongue - for(var/X in internal_organs) - var/obj/item/organ/I = X - I.Insert(src) ..() @@ -95,11 +102,17 @@ /mob/living/carbon/true_devil/assess_threat() return 666 -/mob/living/carbon/true_devil/flash_eyes(intensity = 1, override_blindness_check = 0, affect_silicon = 0) +/mob/living/carbon/true_devil/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0) if(mind && has_bane(BANE_LIGHT)) mind.disrupt_spells(-500) return ..() //flashes don't stop devils UNLESS it's their bane. +/mob/living/carbon/true_devil/soundbang_act() + return 0 + +/mob/living/carbon/true_devil/get_ear_protection() + return 2 + /mob/living/carbon/true_devil/attacked_by(obj/item/I, mob/living/user, def_zone) var/weakness = check_weakness(I, user) @@ -120,9 +133,6 @@ "[attack_message]") return TRUE -/mob/living/carbon/true_devil/UnarmedAttack(atom/A, proximity) - A.attack_hand(src) - /mob/living/carbon/true_devil/Process_Spacemove(movement_dir = 0) return 1 @@ -200,4 +210,14 @@ if(has_bane(BANE_LIGHT)) b_loss *=2 adjustBruteLoss(b_loss) - return ..() \ No newline at end of file + return ..() + + +/mob/living/carbon/true_devil/update_body() //we don't use the bodyparts layer for devils. + return + +/mob/living/carbon/true_devil/update_body_parts() + return + +/mob/living/carbon/true_devil/update_damage_overlays() //devils don't have damage overlays. + return \ No newline at end of file diff --git a/code/game/gamemodes/gang/gang.dm b/code/game/gamemodes/gang/gang.dm index 241c16bf56e7..eefbf5689f12 100644 --- a/code/game/gamemodes/gang/gang.dm +++ b/code/game/gamemodes/gang/gang.dm @@ -149,7 +149,6 @@ var/list/gang_colors_pool = list("red","orange","yellow","green","blue","purple" . += 1 else mob << "The chameleon security HUD in your [where4] will help you keep track of who is mindshield-implanted, and unable to be recruited." - mob.update_icons() return . @@ -167,7 +166,7 @@ var/list/gang_colors_pool = list("red","orange","yellow","green","blue","purple" if(iscarbon(gangster_mind.current)) var/mob/living/carbon/carbon_mob = gangster_mind.current carbon_mob.silent = max(carbon_mob.silent, 5) - carbon_mob.flash_eyes(1, 1) + carbon_mob.flash_act(1, 1) gangster_mind.current.Stun(5) gangster_mind.current << "You are now a member of the [G.name] Gang!" gangster_mind.current << "Help your bosses take over the station by claiming territory with special spraycans only they can provide. Simply spray on any unclaimed area of the station." diff --git a/code/game/gamemodes/miniantags/abduction/abduction_gear.dm b/code/game/gamemodes/miniantags/abduction/abduction_gear.dm index c2a7423ef018..116d910e056c 100644 --- a/code/game/gamemodes/miniantags/abduction/abduction_gear.dm +++ b/code/game/gamemodes/miniantags/abduction/abduction_gear.dm @@ -459,11 +459,11 @@ Congratulations! You are now trained for xenobiology research!"} return var/mob/living/carbon/C = L if(!C.handcuffed) - if(C.get_num_arms() >= 2) + if(C.get_num_arms() >= 2 || C.get_arm_ignore()) playsound(loc, 'sound/weapons/cablecuff.ogg', 30, 1, -2) C.visible_message("[user] begins restraining [C] with [src]!", \ "[user] begins shaping an energy field around your hands!") - if(do_mob(user, C, 30) && C.get_num_arms() >= 2) + if(do_mob(user, C, 30) && (C.get_num_arms() >= 2 || C.get_arm_ignore())) if(!C.handcuffed) C.handcuffed = new /obj/item/weapon/restraints/handcuffs/energy/used(C) C.update_handcuffed() diff --git a/code/game/gamemodes/miniantags/abduction/abduction_surgery.dm b/code/game/gamemodes/miniantags/abduction/abduction_surgery.dm index 30f7d7c10e79..d095f67df43c 100644 --- a/code/game/gamemodes/miniantags/abduction/abduction_surgery.dm +++ b/code/game/gamemodes/miniantags/abduction/abduction_surgery.dm @@ -23,9 +23,9 @@ var/list/organ_types = list(/obj/item/organ/heart) /datum/surgery_step/extract_organ/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - for(var/obj/item/I in target.internal_organs) - if(I.type in organ_types) - IC = I + for(var/atom/A in target.internal_organs) + if(A.type in organ_types) + IC = A break user.visible_message("[user] starts to remove [target]'s organs.", "You start to remove [target]'s organs...") diff --git a/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm b/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm index 68449ba4317c..56bc184a7d85 100644 --- a/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm +++ b/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm @@ -66,7 +66,7 @@ if(eyes_s) photo.Blend(eyes_s, ICON_OVERLAY) - var/icon/splat = icon("icon" = 'icons/mob/dam_human.dmi',"icon_state" = "chest30") + var/icon/splat = icon("icon" = 'icons/mob/dam_mob.dmi',"icon_state" = "chest30") photo.Blend(splat,ICON_OVERLAY) return photo diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index 2310d97b66e8..8fd17b07c302 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -528,13 +528,13 @@ var/global/list/possible_items = list() /datum/objective/steal/give_special_equipment() if(owner && owner.current && targetinfo) - if(istype(owner.current, /mob/living/carbon/human)) + if(ishuman(owner.current)) var/mob/living/carbon/human/H = owner.current var/list/slots = list ("backpack" = slot_in_backpack) for(var/eq_path in targetinfo.special_equipment) var/obj/O = new eq_path H.equip_in_one_of_slots(O, slots) - H.update_icons() + var/global/list/possible_items_special = list() /datum/objective/steal/special //ninjas are so special they get their own subtype good for them diff --git a/code/game/gamemodes/revolution/revolution.dm b/code/game/gamemodes/revolution/revolution.dm index 9027a95c1ff4..b67617ae380b 100644 --- a/code/game/gamemodes/revolution/revolution.dm +++ b/code/game/gamemodes/revolution/revolution.dm @@ -143,8 +143,6 @@ var/where2 = mob.equip_in_one_of_slots(C, slots) mob.equip_in_one_of_slots(R,slots) - mob.update_icons() - if (!where2) mob << "The Syndicate were unfortunately unable to get you a chameleon security HUD." else @@ -248,7 +246,7 @@ if(iscarbon(rev_mind.current)) var/mob/living/carbon/carbon_mob = rev_mind.current carbon_mob.silent = max(carbon_mob.silent, 5) - carbon_mob.flash_eyes(1, 1) + carbon_mob.flash_act(1, 1) rev_mind.current.Stun(5) rev_mind.current << " You are now a revolutionary! Help your cause. Do not harm your fellow freedom fighters. You can identify your comrades by the red \"R\" icons, and your leaders by the blue \"R\" icons. Help them kill the heads to win the revolution!" rev_mind.current.attack_log += "\[[time_stamp()]\] Has been converted to the revolution!" diff --git a/code/game/gamemodes/traitor/traitor.dm b/code/game/gamemodes/traitor/traitor.dm index b77bc2894ad1..29d8e89c86b8 100644 --- a/code/game/gamemodes/traitor/traitor.dm +++ b/code/game/gamemodes/traitor/traitor.dm @@ -375,7 +375,6 @@ if (equipped_slot) where = "In your [equipped_slot]" mob << "

[where] is a folder containing secret documents that another Syndicate group wants. We have set up a meeting with one of their agents on station to make an exchange. Exercise extreme caution as they cannot be trusted and may be hostile.
" - mob.update_icons() /datum/game_mode/proc/update_traitor_icons_added(datum/mind/traitor_mind) var/datum/atom_hud/antag/traitorhud = huds[ANTAG_HUD_TRAITOR] diff --git a/code/game/gamemodes/wizard/artefact.dm b/code/game/gamemodes/wizard/artefact.dm index 6d0d742c00ed..75b44b7edc9d 100644 --- a/code/game/gamemodes/wizard/artefact.dm +++ b/code/game/gamemodes/wizard/artefact.dm @@ -357,7 +357,7 @@ var/global/list/multiverse = list() if("cyborg") for(var/X in M.bodyparts) var/obj/item/bodypart/affecting = X - affecting.change_bodypart_status(ORGAN_ROBOTIC) + affecting.change_bodypart_status(BODYPART_ROBOTIC) M.equip_to_slot_or_del(new /obj/item/clothing/glasses/thermal/eyepatch(M), slot_glasses) M.put_in_hands_or_del(sword) @@ -460,7 +460,6 @@ var/global/list/multiverse = list() else return - M.update_icons() M.update_body_parts() var/obj/item/weapon/card/id/W = new /obj/item/weapon/card/id diff --git a/code/game/gamemodes/wizard/raginmages.dm b/code/game/gamemodes/wizard/raginmages.dm index 870854fa3ebe..4805c884929f 100644 --- a/code/game/gamemodes/wizard/raginmages.dm +++ b/code/game/gamemodes/wizard/raginmages.dm @@ -47,7 +47,7 @@ for(var/datum/mind/wizard in wizards) if(!istype(wizard.current,/mob/living/carbon)) continue - if(istype(wizard.current,/mob/living/carbon/brain)) + if(istype(wizard.current,/mob/living/brain)) continue if(wizard.current.stat==DEAD) continue diff --git a/code/game/gamemodes/wizard/wizard.dm b/code/game/gamemodes/wizard/wizard.dm index 82ad4e67cc88..ceb75c29c099 100644 --- a/code/game/gamemodes/wizard/wizard.dm +++ b/code/game/gamemodes/wizard/wizard.dm @@ -160,7 +160,6 @@ wizard_mob << "The spellbook is bound to you, and others cannot use it." wizard_mob << "In your pockets you will find a teleport scroll. Use it as needed." wizard_mob.mind.store_memory("Remember: do not forget to prepare your spells.") - wizard_mob.update_icons() return 1 diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm index 165f8e21e077..45934d850228 100644 --- a/code/game/machinery/cloning.dm +++ b/code/game/machinery/cloning.dm @@ -169,9 +169,9 @@ var/list/unclean_mutations = (not_good_mutations|bad_mutations) H.dna.remove_mutation_group(unclean_mutations) if(efficiency > 5 && prob(20)) - randmutvg(H) + H.randmutvg() if(efficiency < 3 && prob(50)) - var/mob/M = randmutb(H) + var/mob/M = H.randmutb() if(ismob(M)) H = M @@ -325,7 +325,7 @@ if (mess) //Clean that mess and dump those gibs! mess = FALSE - gibs(loc) + new /obj/effect/gibspawner/generic(loc) audible_message("You hear a splat.") icon_state = "pod_0" return @@ -338,7 +338,7 @@ occupant.grab_ghost() occupant << "There is a bright flash!
\ You feel like a new being.
" - occupant.flash_eyes() + occupant.flash_act() var/turf/T = get_turf(src) occupant.forceMove(T) diff --git a/code/game/machinery/computer/arcade.dm b/code/game/machinery/computer/arcade.dm index 7ca75a4bb694..59bff85af250 100644 --- a/code/game/machinery/computer/arcade.dm +++ b/code/game/machinery/computer/arcade.dm @@ -498,7 +498,7 @@ M.hallucination += 30 else usr << "Something strikes you from behind! It hurts like hell and feel like a blunt weapon, but nothing is there..." - M.take_organ_damage(30) + M.take_bodypart_damage(30) playsound(loc, 'sound/weapons/genhit2.ogg', 100, 1) if(ORION_TRAIL_ILLNESS) var/severity = rand(1,3) //pray to RNGesus. PRAY, PIGS @@ -516,7 +516,7 @@ if(prob(75)) M.Weaken(3) say("A sudden gust of powerful wind slams [M] into the floor!") - M.take_organ_damage(25) + M.take_bodypart_damage(25) playsound(src.loc, 'sound/weapons/Genhit.ogg', 100, 1) else M << "A violent gale blows past you, and you barely manage to stay standing!" diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 224d5e231100..89e3a0ffdb43 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -611,11 +611,9 @@ var/list/airlock_overlays = list() if(!istype(H.head, /obj/item/clothing/head/helmet)) H.visible_message("[user] headbutts the airlock.", \ "You headbutt the airlock!") - var/obj/item/bodypart/affecting = H.get_bodypart("head") H.Stun(5) H.Weaken(5) - if(affecting && affecting.take_damage(10, 0)) - H.update_damage_overlays(0) + H.apply_damage(10, BRUTE, "head") else visible_message("[user] headbutts the airlock. Good thing they're wearing a helmet.") return diff --git a/code/game/machinery/flasher.dm b/code/game/machinery/flasher.dm index e1b6209fed90..3dbeadfd33da 100644 --- a/code/game/machinery/flasher.dm +++ b/code/game/machinery/flasher.dm @@ -114,7 +114,7 @@ if (get_dist(src, L) > range) continue - if(L.flash_eyes(affect_silicon = 1)) + if(L.flash_act(affect_silicon = 1)) L.Weaken(strength) if(L.weakeyes) L.Weaken(strength * 1.5) diff --git a/code/game/machinery/rechargestation.dm b/code/game/machinery/rechargestation.dm index 12f665fa17c4..32c60b667591 100644 --- a/code/game/machinery/rechargestation.dm +++ b/code/game/machinery/rechargestation.dm @@ -134,7 +134,7 @@ var/mob/living/silicon/robot/R = occupant restock_modules() if(repairs) - R.heal_organ_damage(repairs, repairs - 1) + R.heal_bodypart_damage(repairs, repairs - 1) if(R.cell) R.cell.charge = min(R.cell.charge + recharge_speed, R.cell.maxcharge) diff --git a/code/game/machinery/robot_fabricator.dm b/code/game/machinery/robot_fabricator.dm index 3b9c43beb803..47f7fe8a0430 100644 --- a/code/game/machinery/robot_fabricator.dm +++ b/code/game/machinery/robot_fabricator.dm @@ -6,7 +6,7 @@ anchored = 1 var/metal_amount = 0 var/operating = 0 - var/obj/item/robot_parts/being_built = null + var/obj/item/being_built = null use_power = 1 idle_power_usage = 20 active_power_usage = 5000 @@ -90,37 +90,37 @@ Please wait until completion...
switch (part_type) if (1) - build_type = "/obj/item/robot_parts/l_arm" + build_type = "/obj/item/bodypart/l_arm/robot" build_time = 200 build_cost = 10000 if (2) - build_type = "/obj/item/robot_parts/r_arm" + build_type = "/obj/item/bodypart/r_arm/robot" build_time = 200 build_cost = 10000 if (3) - build_type = "/obj/item/robot_parts/l_leg" + build_type = "/obj/item/bodypart/l_leg/robot" build_time = 200 build_cost = 10000 if (4) - build_type = "/obj/item/robot_parts/r_leg" + build_type = "/obj/item/bodypart/r_leg/robot" build_time = 200 build_cost = 10000 if (5) - build_type = "/obj/item/robot_parts/chest" + build_type = "/obj/item/bodypart/chest/robot" build_time = 350 build_cost = 40000 if (6) - build_type = "/obj/item/robot_parts/head" + build_type = "/obj/item/bodypart/head/robot" build_time = 350 build_cost = 5000 if (7) - build_type = "/obj/item/robot_parts/robot_suit" + build_type = "/obj/item/robot_suit" build_time = 600 build_cost = 15000 @@ -146,6 +146,4 @@ Please wait until completion...
src.overlays -= "fab-active" return - for (var/mob/M in viewers(1, src)) - if (M.client && M.machine == src) - src.attack_hand(M) + updateUsrDialog() diff --git a/code/game/machinery/telecomms/computers/logbrowser.dm b/code/game/machinery/telecomms/computers/logbrowser.dm index 61598ca32bcb..478ef77fe6f0 100644 --- a/code/game/machinery/telecomms/computers/logbrowser.dm +++ b/code/game/machinery/telecomms/computers/logbrowser.dm @@ -72,7 +72,7 @@ var/language = "Human" // MMIs, pAIs, Cyborgs and humans all speak Human var/mobtype = C.parameters["mobtype"] - var/list/humans = typesof(/mob/living/carbon/human, /mob/living/carbon/brain) + var/list/humans = typesof(/mob/living/carbon/human, /mob/living/brain) var/list/monkeys = typesof(/mob/living/carbon/monkey) var/list/silicons = typesof(/mob/living/silicon) var/list/slimes = typesof(/mob/living/simple_animal/slime) diff --git a/code/game/mecha/equipment/tools/medical_tools.dm b/code/game/mecha/equipment/tools/medical_tools.dm index 36239710c46e..af916014ca2b 100644 --- a/code/game/mecha/equipment/tools/medical_tools.dm +++ b/code/game/mecha/equipment/tools/medical_tools.dm @@ -343,7 +343,7 @@ mechsyringe.icon = initial(mechsyringe.icon) mechsyringe.reagents.reaction(M, INJECT) mechsyringe.reagents.trans_to(M, mechsyringe.reagents.total_volume) - M.take_organ_damage(2) + M.take_bodypart_damage(2) add_logs(originaloccupant, M, "shot", "syringegun") break else if(mechsyringe.loc == trg) diff --git a/code/game/mecha/equipment/tools/mining_tools.dm b/code/game/mecha/equipment/tools/mining_tools.dm index 6ec06406b811..37bde068e28c 100644 --- a/code/game/mecha/equipment/tools/mining_tools.dm +++ b/code/game/mecha/equipment/tools/mining_tools.dm @@ -83,13 +83,11 @@ add_logs(user, target, "attacked", "[name]", "(INTENT: [uppertext(user.a_intent)]) (DAMTYPE: [uppertext(damtype)])") if(ishuman(target)) var/mob/living/carbon/human/H = target - var/obj/item/bodypart/affecting = H.get_bodypart("chest") - affecting.take_damage(drill_damage) - H.update_damage_overlays(0) + H.apply_damage(drill_damage, BRUTE, "chest") else if(target.stat == DEAD && target.butcher_results) target.harvest(chassis) // Butcher the mob with our drill. else - target.take_organ_damage(drill_damage) + target.take_bodypart_damage(drill_damage) if(target) target.Paralyse(10) diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index 2a15a49fdacf..6a04670188ad 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -845,7 +845,7 @@ else if(occupant) user << "Occupant detected!" return 0 - else if(dna_lock && (!mmi_as_oc.brainmob.dna || dna_lock!=mmi_as_oc.brainmob.dna.unique_enzymes)) + else if(dna_lock && (!mmi_as_oc.brainmob.stored_dna || dna_lock!=mmi_as_oc.brainmob.stored_dna.unique_enzymes)) user << "Access denied. [name] is secured with a DNA lock." return 0 @@ -905,8 +905,8 @@ if(ishuman(occupant)) mob_container = occupant RemoveActions(occupant, human_occupant=1) - else if(istype(occupant, /mob/living/carbon/brain)) - var/mob/living/carbon/brain/brain = occupant + else if(istype(occupant, /mob/living/brain)) + var/mob/living/brain/brain = occupant RemoveActions(brain) mob_container = brain.container else if(isAI(occupant) && forced) //This should only happen if there are multiple AIs in a round, and at least one is Malf. diff --git a/code/game/objects/effects/decals/Cleanable/aliens.dm b/code/game/objects/effects/decals/Cleanable/aliens.dm index 36bf7577bb10..a0e5d4a3dc31 100644 --- a/code/game/objects/effects/decals/Cleanable/aliens.dm +++ b/code/game/objects/effects/decals/Cleanable/aliens.dm @@ -21,18 +21,21 @@ return ..() /obj/effect/decal/cleanable/xenoblood/xgibs/proc/streak(list/directions) - spawn (0) - var/direction = pick(directions) - for (var/i = 0, i < pick(1, 200; 2, 150; 3, 50; 4), i++) - sleep(3) - if (i > 0) - var/obj/effect/decal/cleanable/xenoblood/b = new /obj/effect/decal/cleanable/xenoblood/xsplatter(src.loc) - for(var/datum/disease/D in src.viruses) - var/datum/disease/ND = D.Copy(1) - b.viruses += ND - ND.holder = b - if (step_to(src, get_step(src, direction), 0)) - break + set waitfor = 0 + var/direction = pick(directions) + for(var/i = 0, i < pick(1, 200; 2, 150; 3, 50), i++) + sleep(2) + if (i > 0) + var/obj/effect/decal/cleanable/xenoblood/b = new /obj/effect/decal/cleanable/xenoblood/xsplatter(src.loc) + for(var/datum/disease/D in src.viruses) + var/datum/disease/ND = D.Copy(1) + b.viruses += ND + ND.holder = b + if (!step_to(src, get_step(src, direction), 0)) + break + +/obj/effect/decal/cleanable/xenoblood/xgibs/replace_decal(obj/effect/decal/cleanable/C) + return //gibs can stack, so gibspawner can work properly /obj/effect/decal/cleanable/xenoblood/xsplatter random_icon_states = list("xgibbl1", "xgibbl2", "xgibbl3", "xgibbl4", "xgibbl5") @@ -57,12 +60,21 @@ /obj/effect/decal/cleanable/xenoblood/xgibs/body random_icon_states = list("xgibhead", "xgibtorso") +/obj/effect/decal/cleanable/xenoblood/xgibs/torso + random_icon_states = list("xgibtorso") + /obj/effect/decal/cleanable/xenoblood/xgibs/limb random_icon_states = list("xgibleg", "xgibarm") /obj/effect/decal/cleanable/xenoblood/xgibs/core random_icon_states = list("xgibmid1", "xgibmid2", "xgibmid3") +/obj/effect/decal/cleanable/xenoblood/xgibs/larva + random_icon_states = list("xgiblarva1", "xgiblarva2") + +/obj/effect/decal/cleanable/xenoblood/xgibs/larva/body + random_icon_states = list("xgiblarvahead", "xgiblarvatorso") + /obj/effect/decal/cleanable/blood/xtracks icon_state = "xtracks" random_icon_states = null diff --git a/code/game/objects/effects/decals/Cleanable/humans.dm b/code/game/objects/effects/decals/Cleanable/humans.dm index 0e978782a5dc..916bd7d2cf3e 100644 --- a/code/game/objects/effects/decals/Cleanable/humans.dm +++ b/code/game/objects/effects/decals/Cleanable/humans.dm @@ -77,6 +77,10 @@ /obj/effect/decal/cleanable/blood/gibs/body random_icon_states = list("gibhead", "gibtorso") +/obj/effect/decal/cleanable/blood/gibs/torso + random_icon_states = list("gibtorso") + + /obj/effect/decal/cleanable/blood/gibs/limb random_icon_states = list("gibleg", "gibarm") @@ -87,17 +91,20 @@ /obj/effect/decal/cleanable/blood/gibs/proc/streak(list/directions) set waitfor = 0 var/direction = pick(directions) - for (var/i = 0, i < pick(1, 200; 2, 150; 3, 50; 4), i++) - sleep(3) + for (var/i = 0, i < pick(1, 200; 2, 150; 3, 50), i++) + sleep(2) if (i > 0) var/obj/effect/decal/cleanable/blood/b = new /obj/effect/decal/cleanable/blood/splatter(src.loc) for(var/datum/disease/D in src.viruses) var/datum/disease/ND = D.Copy(1) b.viruses += ND ND.holder = b - if (step_to(src, get_step(src, direction), 0)) + if (!step_to(src, get_step(src, direction), 0)) break +/obj/effect/decal/cleanable/blood/gibs/replace_decal(obj/effect/decal/cleanable/C) + return //gibs can stack, so gibspawner can work properly + /obj/effect/decal/cleanable/blood/drip name = "drips of blood" desc = "It's red." diff --git a/code/game/objects/effects/decals/Cleanable/robots.dm b/code/game/objects/effects/decals/Cleanable/robots.dm index e255f497ca20..7c0666a0c6e9 100644 --- a/code/game/objects/effects/decals/Cleanable/robots.dm +++ b/code/game/objects/effects/decals/Cleanable/robots.dm @@ -15,8 +15,8 @@ /obj/effect/decal/cleanable/robot_debris/proc/streak(list/directions) set waitfor = 0 var/direction = pick(directions) - for (var/i = 0, i < pick(1, 200; 2, 150; 3, 50; 4), i++) - sleep(3) + for (var/i = 0, i < pick(1, 200; 2, 150; 3, 50), i++) + sleep(2) if (i > 0) if (prob(40)) new /obj/effect/decal/cleanable/oil/streak(src.loc) @@ -24,9 +24,12 @@ var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread s.set_up(3, 1, src) s.start() - if (step_to(src, get_step(src, direction), 0)) + if (!step_to(src, get_step(src, direction), 0)) break +/obj/effect/decal/cleanable/robot_debris/replace_decal(obj/effect/decal/cleanable/C) + return //robot debris can stack, so gibspawner can work properly + /obj/effect/decal/cleanable/robot_debris/ex_act() return diff --git a/code/game/objects/effects/decals/remains.dm b/code/game/objects/effects/decals/remains.dm index 834c3b4c7dc6..b498217bb8a3 100644 --- a/code/game/objects/effects/decals/remains.dm +++ b/code/game/objects/effects/decals/remains.dm @@ -11,6 +11,9 @@ desc = "They look like the remains of something... alien. They have a strange aura about them." icon_state = "remainsxeno" +/obj/effect/decal/remains/xeno/larva + icon_state = "remainslarva" + /obj/effect/decal/remains/robot desc = "They look like the remains of something mechanical. They have a strange aura about them." icon = 'icons/mob/robots.dmi' diff --git a/code/game/objects/effects/gibs.dm b/code/game/objects/effects/gibs.dm deleted file mode 100644 index 5bac5acd991d..000000000000 --- a/code/game/objects/effects/gibs.dm +++ /dev/null @@ -1,62 +0,0 @@ -/proc/gibs(atom/location, list/viruses, datum/dna/MobDNA) - new /obj/effect/gibspawner/generic(location,viruses,MobDNA) - -/proc/hgibs(atom/location, list/viruses, datum/dna/MobDNA) - new /obj/effect/gibspawner/human(location,viruses,MobDNA) - -/proc/xgibs(atom/location, list/viruses) - new /obj/effect/gibspawner/xeno(location,viruses) - -/proc/robogibs(atom/location, list/viruses) - new /obj/effect/gibspawner/robot(location,viruses) - -/obj/effect/gibspawner - var/sparks = 0 //whether sparks spread on Gib() - var/virusProb = 20 //the chance for viruses to spread on the gibs - var/list/gibtypes = list() - var/list/gibamounts = list() - var/list/gibdirections = list() //of lists - -/obj/effect/gibspawner/New(location, var/list/viruses, var/datum/dna/MobDNA) - ..() - - Gib(loc,viruses,MobDNA) - -/obj/effect/gibspawner/proc/Gib(atom/location, list/viruses = list(), datum/dna/MobDNA = null) - if(gibtypes.len != gibamounts.len || gibamounts.len != gibdirections.len) - world << "Gib list length mismatch!" - return - - var/obj/effect/decal/cleanable/blood/gibs/gib = null - - if(sparks) - var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread - s.set_up(2, 1, location) - s.start() - - for(var/i = 1, i<= gibtypes.len, i++) - if(gibamounts[i]) - for(var/j = 1, j<= gibamounts[i], j++) - var/gibType = gibtypes[i] - gib = new gibType(location) - if(istype(location,/mob/living/carbon)) - var/mob/living/carbon/digester = location - digester.stomach_contents += gib - - if(viruses.len > 0) - for(var/datum/disease/D in viruses) - if(prob(virusProb)) - var/datum/disease/viruus = D.Copy(1) - gib.viruses += viruus - viruus.holder = gib - - if(MobDNA) - gib.blood_DNA[MobDNA.unique_enzymes] = MobDNA.blood_type - else if(istype(src, /obj/effect/gibspawner/generic)) // Probably a monkey - gib.blood_DNA["Non-human DNA"] = "A+" - var/list/directions = gibdirections[i] - if(istype(loc,/turf)) - if(directions.len) - gib.streak(directions) - - qdel(src) diff --git a/code/game/objects/effects/spawners/gibspawner.dm b/code/game/objects/effects/spawners/gibspawner.dm index e6618e62c742..bb6afc8e8eea 100644 --- a/code/game/objects/effects/spawners/gibspawner.dm +++ b/code/game/objects/effects/spawners/gibspawner.dm @@ -1,4 +1,53 @@ + /obj/effect/gibspawner + var/sparks = 0 //whether sparks spread + var/virusProb = 20 //the chance for viruses to spread on the gibs + var/list/gibtypes = list() //typepaths of the gib decals to spawn + var/list/gibamounts = list() //amount to spawn for each gib decal type we'll spawn. + var/list/gibdirections = list() //of lists of possible directions to spread each gib decal type towards. + +/obj/effect/gibspawner/New(location, list/viruses, datum/dna/MobDNA) + ..() + + if(gibtypes.len != gibamounts.len || gibamounts.len != gibdirections.len) + world << "Gib list length mismatch!" + return + + var/obj/effect/decal/cleanable/blood/gibs/gib = null + + if(sparks) + var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread + s.set_up(2, 1, location) + s.start() + + for(var/i = 1, i<= gibtypes.len, i++) + if(gibamounts[i]) + for(var/j = 1, j<= gibamounts[i], j++) + var/gibType = gibtypes[i] + gib = new gibType(location) + if(istype(location,/mob/living/carbon)) + var/mob/living/carbon/digester = location + digester.stomach_contents += gib + + if(viruses && viruses.len > 0) + for(var/datum/disease/D in viruses) + if(prob(virusProb)) + var/datum/disease/viruus = D.Copy(1) + gib.viruses += viruus + viruus.holder = gib + + if(MobDNA) + gib.blood_DNA[MobDNA.unique_enzymes] = MobDNA.blood_type + else if(istype(src, /obj/effect/gibspawner/generic)) // Probably a monkey + gib.blood_DNA["Non-human DNA"] = "A+" + var/list/directions = gibdirections[i] + if(isturf(loc)) + if(directions.len) + gib.streak(directions) + + qdel(src) + + /obj/effect/gibspawner/generic gibtypes = list(/obj/effect/decal/cleanable/blood/gibs,/obj/effect/decal/cleanable/blood/gibs,/obj/effect/decal/cleanable/blood/gibs/core) @@ -16,17 +65,55 @@ /obj/effect/gibspawner/human/New() playsound(src, 'sound/effects/blobattack.ogg', 50, 1) gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST),list(WEST, NORTHWEST, SOUTHWEST),list(EAST, NORTHEAST, SOUTHEAST), alldirs, alldirs, list()) - gibamounts[6] = pick(0,1,2) ..() + +/obj/effect/gibspawner/humanbodypartless //only the gibs that don't look like actual full bodyparts (except torso). + gibtypes = list(/obj/effect/decal/cleanable/blood/gibs, /obj/effect/decal/cleanable/blood/gibs/core,/obj/effect/decal/cleanable/blood/gibs, /obj/effect/decal/cleanable/blood/gibs/core, /obj/effect/decal/cleanable/blood/gibs, /obj/effect/decal/cleanable/blood/gibs/torso) + gibamounts = list(1, 1, 1, 1, 1, 1) + +/obj/effect/gibspawner/humanbodypartless/New() + playsound(src, 'sound/effects/blobattack.ogg', 50, 1) + gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST),list(WEST, NORTHWEST, SOUTHWEST),list(EAST, NORTHEAST, SOUTHEAST), alldirs, list()) + ..() + + /obj/effect/gibspawner/xeno - gibtypes = list(/obj/effect/decal/cleanable/xenoblood/xgibs/up,/obj/effect/decal/cleanable/xenoblood/xgibs/down,/obj/effect/decal/cleanable/xenoblood/xgibs,/obj/effect/decal/cleanable/xenoblood/xgibs,/obj/effect/decal/cleanable/xenoblood/xgibs/body,/obj/effect/decal/cleanable/xenoblood/xgibs/limb,/obj/effect/decal/cleanable/xenoblood/xgibs/core) + gibtypes = list(/obj/effect/decal/cleanable/xenoblood/xgibs/up,/obj/effect/decal/cleanable/xenoblood/xgibs/down,/obj/effect/decal/cleanable/xenoblood/xgibs, /obj/effect/decal/cleanable/xenoblood/xgibs, /obj/effect/decal/cleanable/xenoblood/xgibs/body, /obj/effect/decal/cleanable/xenoblood/xgibs/limb, /obj/effect/decal/cleanable/xenoblood/xgibs/core) gibamounts = list(1,1,1,1,1,1,1) /obj/effect/gibspawner/xeno/New() playsound(src, 'sound/effects/blobattack.ogg', 60, 1) gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST),list(WEST, NORTHWEST, SOUTHWEST),list(EAST, NORTHEAST, SOUTHEAST), alldirs, alldirs, list()) - gibamounts[6] = pick(0,1,2) + ..() + + +/obj/effect/gibspawner/xenobodypartless //only the gibs that don't look like actual full bodyparts (except torso). + gibtypes = list(/obj/effect/decal/cleanable/xenoblood/xgibs, /obj/effect/decal/cleanable/xenoblood/xgibs/core,/obj/effect/decal/cleanable/xenoblood/xgibs, /obj/effect/decal/cleanable/xenoblood/xgibs/core, /obj/effect/decal/cleanable/xenoblood/xgibs, /obj/effect/decal/cleanable/xenoblood/xgibs/torso) + gibamounts = list(1, 1, 1, 1, 1, 1) + + +/obj/effect/gibspawner/xenobodypartless/New() + playsound(src, 'sound/effects/blobattack.ogg', 60, 1) + gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST),list(WEST, NORTHWEST, SOUTHWEST),list(EAST, NORTHEAST, SOUTHEAST), alldirs, list()) + ..() + +/obj/effect/gibspawner/larva + gibtypes = list(/obj/effect/decal/cleanable/xenoblood/xgibs/larva, /obj/effect/decal/cleanable/xenoblood/xgibs/larva, /obj/effect/decal/cleanable/xenoblood/xgibs/larva/body, /obj/effect/decal/cleanable/xenoblood/xgibs/larva/body) + gibamounts = list(1, 1, 1, 1) + +/obj/effect/gibspawner/larva/New() + playsound(src, 'sound/effects/blobattack.ogg', 60, 1) + gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST), list(), alldirs) + ..() + +/obj/effect/gibspawner/larvabodypartless + gibtypes = list(/obj/effect/decal/cleanable/xenoblood/xgibs/larva, /obj/effect/decal/cleanable/xenoblood/xgibs/larva, /obj/effect/decal/cleanable/xenoblood/xgibs/larva) + gibamounts = list(1, 1, 1) + +/obj/effect/gibspawner/larvabodypartless/New() + playsound(src, 'sound/effects/blobattack.ogg', 60, 1) + gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST), list()) ..() /obj/effect/gibspawner/robot diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index efe7edf08e14..8877f17bc510 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -230,8 +230,8 @@ var/global/image/fire_overlay = image("icon" = 'icons/effects/fire.dmi', "icon_s user << "You burn your hand on [src]!" var/obj/item/bodypart/affecting = H.get_bodypart("[(user.active_hand_index % 2 == 0) ? "r" : "l" ]_arm") if(affecting && affecting.take_damage( 0, 5 )) // 5 burn damage - H.update_damage_overlays(0) - H.updatehealth() + H.update_damage_overlays() + return else extinguish() @@ -454,11 +454,10 @@ obj/item/proc/item_action_slot_check(slot, mob/user) ) if(is_human_victim) var/mob/living/carbon/human/U = M - if(affecting.take_damage(7)) - U.update_damage_overlays(0) + U.apply_damage(7, BRUTE, affecting) else - M.take_organ_damage(7) + M.take_bodypart_damage(7) add_logs(user, M, "attacked", "[src.name]", "(INTENT: [uppertext(user.a_intent)])") diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm index a04be038af72..a79ee1e4704c 100644 --- a/code/game/objects/items/crayons.dm +++ b/code/game/objects/items/crayons.dm @@ -640,7 +640,7 @@ if(C.client) C.blur_eyes(3) C.blind_eyes(1) - if(C.check_eye_prot() <= 0) // no eye protection? ARGH IT BURNS. + if(C.get_eye_protection() <= 0) // no eye protection? ARGH IT BURNS. C.confused = max(C.confused, 3) C.Weaken(3) if(ishuman(C) && actually_paints) diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm index b0be84a5209d..f2932a64dd61 100644 --- a/code/game/objects/items/devices/flashlight.dm +++ b/code/game/objects/items/devices/flashlight.dm @@ -61,7 +61,7 @@ return if(M == user) //they're using it on themselves - if(M.flash_eyes(visual = 1)) + if(M.flash_act(visual = 1)) M.visible_message("[M] directs [src] to \his eyes.", \ "You wave the light in front of your eyes! Trippy!") else @@ -77,7 +77,7 @@ else if(C.dna.check_mutation(XRAY)) //mob has X-RAY vision user << "[C] pupils give an eerie glow!" else //they're okay! - if(C.flash_eyes(visual = 1)) + if(C.flash_act(visual = 1)) user << "[C]'s pupils narrow." else return ..() diff --git a/code/game/objects/items/devices/laserpointer.dm b/code/game/objects/items/devices/laserpointer.dm index 65a73271e416..dfdccf1b8d15 100644 --- a/code/game/objects/items/devices/laserpointer.dm +++ b/code/game/objects/items/devices/laserpointer.dm @@ -98,7 +98,7 @@ severity = 0 //20% chance to actually hit the eyes - if(prob(effectchance * diode.rating) && C.flash_eyes(severity)) + if(prob(effectchance * diode.rating) && C.flash_act(severity)) outmsg = "You blind [C] by shining [src] in their eyes." if(C.weakeyes) C.Stun(1) @@ -110,7 +110,7 @@ var/mob/living/silicon/S = target //20% chance to actually hit the sensors if(prob(effectchance * diode.rating)) - S.flash_eyes(affect_silicon = 1) + S.flash_act(affect_silicon = 1) S.Weaken(rand(5,10)) S << "Your sensors were overloaded by a laser!" outmsg = "You overload [S] by shining [src] at their sensors." diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index c39791c03504..e5bb68ef23c4 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -114,7 +114,7 @@ MASS SPECTROMETER // Used by the PDA medical scanner too /proc/healthscan(mob/living/user, mob/living/M, mode = 1) - if(user.stat || user.eye_blind) + if(user.incapacitated() || user.eye_blind) return //Damage specifics var/oxy_loss = M.getOxyLoss() @@ -156,9 +156,9 @@ MASS SPECTROMETER user << "\tBrain damage detected. Subject may have had a concussion." // Organ damage report - if(istype(M, /mob/living/carbon/human) && mode == 1) - var/mob/living/carbon/human/H = M - var/list/damaged = H.get_damaged_bodyparts(1,1) + if(iscarbon(M) && mode == 1) + var/mob/living/carbon/C = M + var/list/damaged = C.get_damaged_bodyparts(1,1) if(length(damaged)>0 || oxy_loss>0 || tox_loss>0 || fire_loss>0) user << "\tDamage: Brute-Burn-Toxin-Suffocation\n\t\tSpecifics: [brute_loss]-[fire_loss]-[tox_loss]-[oxy_loss]" for(var/obj/item/bodypart/org in damaged) diff --git a/code/game/objects/items/robot/robot_items.dm b/code/game/objects/items/robot/robot_items.dm index d898405a1d87..5e8b75b987a9 100644 --- a/code/game/objects/items/robot/robot_items.dm +++ b/code/game/objects/items/robot/robot_items.dm @@ -294,14 +294,10 @@ user.visible_message("[user] blares out a near-deafening siren from its speakers!", \ "The siren pierces your hearing and confuses you!", \ "The siren pierces your hearing!") - for(var/mob/living/M in get_hearers_in_view(9, user)) - if(iscarbon(M)) - if(istype(M, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = M - if(istype(H.ears, /obj/item/clothing/ears/earmuffs)) - continue + for(var/mob/living/carbon/M in get_hearers_in_view(9, user)) + if(M.get_ear_protection() == 0) M.confused += 6 - M << "HUMAN HARM" + audible_message("HUMAN HARM") playsound(get_turf(src), 'sound/AI/harmalarm.ogg', 70, 3) cooldown = world.time + 200 log_game("[user.ckey]([user]) used a Cyborg Harm Alarm in ([user.x],[user.y],[user.z])") @@ -312,35 +308,20 @@ return if(safety == 0) - for(var/mob/living/M in get_hearers_in_view(9, user)) - if(iscarbon(M)) - var/earsafety = 0 - if(istype(M, /mob/living/carbon/alien)) - continue - if(ishuman(M)) - var/mob/living/carbon/human/S = M - if(istype(S.ears, /obj/item/clothing/ears/earmuffs)) - continue - if(S.check_ear_prot()) - earsafety = 1 - if(earsafety) - M.confused += 5 - M.stuttering += 10 - M.adjustEarDamage(0, 5) - M.Jitter(10) - user.visible_message("[user] blares out a sonic screech from its speakers!", \ - "You hear a sharp screech, before your thoughts are interrupted and you find yourself extremely disorientated.", \ - "You hear a sonic screech and suddenly can't seem to walk straight!") - else - M.Weaken(2) - M.confused += 10 - M.stuttering += 15 - M.adjustEarDamage(0, 20) - M.Jitter(25) - user.visible_message("[user] blares out a sonic screech from its speakers!", \ - "You hear a sharp screech before your thoughts are interrupted and you collapse, your ears ringing!", \ - "You hear a sonic screech and collapse, your ears riniging!") - M << "BZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZT" + for(var/mob/living/carbon/C in get_hearers_in_view(9, user)) + var/bang_effect = C.soundbang_act(2, 0, 0, 5) + switch(bang_effect) + if(1) + C.confused += 5 + C.stuttering += 10 + C.Jitter(10) + if(2) + C.Weaken(2) + C.confused += 10 + C.stuttering += 15 + C.Jitter(25) + + user.audible_message("BZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZT") playsound(get_turf(src), 'sound/machines/warning-buzzer.ogg', 130, 3) cooldown = world.time + 600 log_game("[user.ckey]([user]) used an emagged Cyborg Harm Alarm in ([user.x],[user.y],[user.z])") diff --git a/code/game/objects/items/robot/robot_parts.dm b/code/game/objects/items/robot/robot_parts.dm index d133a66b6124..21aab1670c9e 100644 --- a/code/game/objects/items/robot/robot_parts.dm +++ b/code/game/objects/items/robot/robot_parts.dm @@ -1,68 +1,19 @@ -/obj/item/robot_parts - name = "robot parts" - icon = 'icons/obj/robot_parts.dmi' - force = 4 - throwforce = 4 - item_state = "buildpipe" - icon_state = "blank" - flags = CONDUCT - slot_flags = SLOT_BELT - var/body_zone -/obj/item/robot_parts/l_arm - name = "cyborg left arm" - desc = "A skeletal limb wrapped in pseudomuscles, with a low-conductivity case." - attack_verb = list("slapped", "punched") - icon_state = "l_arm" - body_zone = "l_arm" -/obj/item/robot_parts/r_arm - name = "cyborg right arm" - desc = "A skeletal limb wrapped in pseudomuscles, with a low-conductivity case." - attack_verb = list("slapped", "punched") - icon_state = "r_arm" - body_zone = "r_arm" +//The robot bodyparts have been moved to code/module/surgery/bodyparts/robot_bodyparts.dm -/obj/item/robot_parts/l_leg - name = "cyborg left leg" - desc = "A skeletal limb wrapped in pseudomuscles, with a low-conductivity case." - attack_verb = list("kicked", "stomped") - icon_state = "l_leg" - body_zone = "l_leg" -/obj/item/robot_parts/r_leg - name = "cyborg right leg" - desc = "A skeletal limb wrapped in pseudomuscles, with a low-conductivity case." - attack_verb = list("kicked", "stomped") - icon_state = "r_leg" - body_zone = "r_leg" - -/obj/item/robot_parts/chest - name = "cyborg torso" - desc = "A heavily reinforced case containing cyborg logic boards, with space for a standard power cell." - icon_state = "chest" - body_zone = "chest" - var/wired = 0 - var/obj/item/weapon/stock_parts/cell/cell = null - -/obj/item/robot_parts/head - name = "cyborg head" - desc = "A standard reinforced braincase, with spine-plugged neural socket and sensor gimbals." - icon_state = "head" - body_zone = "head" - var/obj/item/device/assembly/flash/handheld/flash1 = null - var/obj/item/device/assembly/flash/handheld/flash2 = null - -/obj/item/robot_parts/robot_suit +/obj/item/robot_suit name = "cyborg endoskeleton" desc = "A complex metal backbone with standard limb sockets and pseudomuscle anchors." + icon = 'icons/obj/robot_parts.dmi' icon_state = "robo_suit" - var/obj/item/robot_parts/l_arm/l_arm = null - var/obj/item/robot_parts/r_arm/r_arm = null - var/obj/item/robot_parts/l_leg/l_leg = null - var/obj/item/robot_parts/r_leg/r_leg = null - var/obj/item/robot_parts/chest/chest = null - var/obj/item/robot_parts/head/head = null + var/obj/item/bodypart/l_arm/robot/l_arm = null + var/obj/item/bodypart/r_arm/robot/r_arm = null + var/obj/item/bodypart/l_leg/robot/l_leg = null + var/obj/item/bodypart/r_leg/robot/r_leg = null + var/obj/item/bodypart/chest/robot/chest = null + var/obj/item/bodypart/head/robot/head = null var/created_name = "" var/mob/living/silicon/ai/forced_ai @@ -71,11 +22,11 @@ var/aisync = 1 var/panel_locked = 1 -/obj/item/robot_parts/robot_suit/New() +/obj/item/robot_suit/New() ..() src.updateicon() -/obj/item/robot_parts/robot_suit/proc/updateicon() +/obj/item/robot_suit/proc/updateicon() src.cut_overlays() if(src.l_arm) src.add_overlay("l_arm+o") @@ -90,7 +41,7 @@ if(src.head) src.add_overlay("head+o") -/obj/item/robot_parts/robot_suit/proc/check_completion() +/obj/item/robot_suit/proc/check_completion() if(src.l_arm && src.r_arm) if(src.l_leg && src.r_leg) if(src.chest && src.head) @@ -98,7 +49,7 @@ return 1 return 0 -/obj/item/robot_parts/robot_suit/attackby(obj/item/W, mob/user, params) +/obj/item/robot_suit/attackby(obj/item/W, mob/user, params) if(istype(W, /obj/item/stack/sheet/metal)) var/obj/item/stack/sheet/metal/M = W @@ -114,64 +65,82 @@ else user << "You need one sheet of metal to start building ED-209!" return - else if(istype(W, /obj/item/robot_parts/l_leg)) + else if(istype(W, /obj/item/bodypart/l_leg/robot)) if(src.l_leg) return if(!user.unEquip(W)) return - W.loc = src + W.forceMove(src) + W.icon_state = initial(W.icon_state) + W.cut_overlays() src.l_leg = W src.updateicon() - else if(istype(W, /obj/item/robot_parts/r_leg)) + else if(istype(W, /obj/item/bodypart/r_leg/robot)) if(src.r_leg) return if(!user.unEquip(W)) return - W.loc = src + W.forceMove(src) + W.icon_state = initial(W.icon_state) + W.cut_overlays() src.r_leg = W src.updateicon() - else if(istype(W, /obj/item/robot_parts/l_arm)) + else if(istype(W, /obj/item/bodypart/l_arm/robot)) if(src.l_arm) return if(!user.unEquip(W)) return - W.loc = src + W.forceMove(src) + W.icon_state = initial(W.icon_state) + W.cut_overlays() src.l_arm = W src.updateicon() - else if(istype(W, /obj/item/robot_parts/r_arm)) + else if(istype(W, /obj/item/bodypart/r_arm/robot)) if(src.r_arm) return if(!user.unEquip(W)) return - W.loc = src + W.forceMove(src) + W.icon_state = initial(W.icon_state)//in case it is a dismembered robotic limb + W.cut_overlays() src.r_arm = W src.updateicon() - else if(istype(W, /obj/item/robot_parts/chest)) + else if(istype(W, /obj/item/bodypart/chest/robot)) + var/obj/item/bodypart/chest/robot/CH = W if(src.chest) return - if(W:wired && W:cell) - if(!user.unEquip(W)) + if(CH.wired && CH.cell) + if(!user.unEquip(CH)) return - W.loc = src - src.chest = W + CH.forceMove(src) + CH.icon_state = initial(CH.icon_state) //in case it is a dismembered robotic limb + CH.cut_overlays() + src.chest = CH src.updateicon() - else if(!W:wired) + else if(!CH.wired) user << "You need to attach wires to it first!" else user << "You need to attach a cell to it first!" - else if(istype(W, /obj/item/robot_parts/head)) + else if(istype(W, /obj/item/bodypart/head/robot)) + var/obj/item/bodypart/head/robot/HD = W + for(var/X in HD.contents) + if(istype(X, /obj/item/organ)) + user << "There are organs inside [HD]!" + return if(src.head) return - if(W:flash2 && W:flash1) - if(!user.unEquip(W)) + if(HD.flash2 && HD.flash1) + if(!user.unEquip(HD)) return - W.loc = src - src.head = W + HD.loc = src + HD.icon_state = initial(HD.icon_state)//in case it is a dismembered robotic limb + HD.cut_overlays() + src.head = HD src.updateicon() else user << "You need to attach a flash to it first!" @@ -192,7 +161,7 @@ user << "Sticking an empty MMI into the frame would sort of defeat the purpose!" return - var/mob/living/carbon/brain/BM = M.brainmob + var/mob/living/brain/BM = M.brainmob if(!BM.key || !BM.mind) user << "The mmi indicates that their mind is completely unresponsive; there's no point!" return @@ -283,7 +252,7 @@ else return ..() -/obj/item/robot_parts/robot_suit/proc/Interact(mob/user) +/obj/item/robot_suit/proc/Interact(mob/user) var/t1 = text("Designation: [(created_name ? "[created_name]" : "Default Cyborg")]
\n",src) t1 += text("Master AI: [(forced_ai ? "[forced_ai.name]" : "Automatic")]

\n",src) @@ -295,8 +264,8 @@ popup.set_content(t1) popup.open() -/obj/item/robot_parts/robot_suit/Topic(href, href_list) - if(usr.lying || usr.stat || usr.stunned || !Adjacent(usr)) +/obj/item/robot_suit/Topic(href, href_list) + if(usr.incapacitated() || !Adjacent(usr)) return var/mob/living/living_user = usr @@ -330,50 +299,4 @@ add_fingerprint(usr) Interact(usr) - return - -/obj/item/robot_parts/chest/attackby(obj/item/W, mob/user, params) - if(istype(W, /obj/item/weapon/stock_parts/cell)) - if(src.cell) - user << "You have already inserted a cell!" - return - else - if(!user.unEquip(W)) - return - W.loc = src - src.cell = W - user << "You insert the cell." - else if(istype(W, /obj/item/stack/cable_coil)) - if(src.wired) - user << "You have already inserted wire!" - return - var/obj/item/stack/cable_coil/coil = W - if (coil.use(1)) - src.wired = 1 - user << "You insert the wire." - else - user << "You need one length of coil to wire it!" - else - return ..() - -/obj/item/robot_parts/head/attackby(obj/item/W, mob/user, params) - if(istype(W, /obj/item/device/assembly/flash/handheld)) - var/obj/item/device/assembly/flash/handheld/F = W - if(src.flash1 && src.flash2) - user << "You have already inserted the eyes!" - return - else if(F.crit_fail) - user << "You can't use a broken flash!" - return - else - if(!user.unEquip(W)) - return - F.loc = src - if(src.flash1) - src.flash2 = F - else - src.flash1 = F - user << "You insert the flash into the eye socket." - else - return ..() diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm index 66b881f09caa..8d0009c181da 100644 --- a/code/game/objects/items/stacks/medical.dm +++ b/code/game/objects/items/stacks/medical.dm @@ -30,19 +30,21 @@ return 1 var/obj/item/bodypart/affecting - if(ishuman(M)) - var/mob/living/carbon/human/H = M - affecting = H.get_bodypart(check_zone(user.zone_selected)) + if(iscarbon(M)) + var/mob/living/carbon/C = M + affecting = C.get_bodypart(check_zone(user.zone_selected)) if(!affecting) //Missing limb? - user << "[H] doesn't have \a [parse_zone(user.zone_selected)]!" + user << "[C] doesn't have \a [parse_zone(user.zone_selected)]!" return - if(stop_bleeding) - if(H.bleedsuppress) - user << "[H]'s bleeding is already bandaged!" - return - else if(!H.bleed_rate) - user << "[H] isn't bleeding!" - return + if(ishuman(C)) + var/mob/living/carbon/human/H = C + if(stop_bleeding) + if(H.bleedsuppress) + user << "[H]'s bleeding is already bandaged!" + return + else if(!H.bleed_rate) + user << "[H] isn't bleeding!" + return if(isliving(M)) @@ -75,25 +77,24 @@ user.visible_message("[user] applies [src] on [t_himself].", "You apply [src] on yourself.") - if(ishuman(M)) - var/mob/living/carbon/human/H = M - affecting = H.get_bodypart(check_zone(user.zone_selected)) + if(iscarbon(M)) + var/mob/living/carbon/C = M + affecting = C.get_bodypart(check_zone(user.zone_selected)) if(!affecting) //Missing limb? - user << "[H] doesn't have \a [parse_zone(user.zone_selected)]!" + user << "[C] doesn't have \a [parse_zone(user.zone_selected)]!" return - if(stop_bleeding) - if(!H.bleedsuppress) //so you can't stack bleed suppression - H.suppress_bloodloss(stop_bleeding) - if(affecting.status == ORGAN_ORGANIC) //Limb must be organic to be healed - RR - if(affecting.heal_damage(src.heal_brute, src.heal_burn, 0)) - H.update_damage_overlays(0) - - M.updatehealth() + if(ishuman(C)) + var/mob/living/carbon/human/H = C + if(stop_bleeding) + if(!H.bleedsuppress) //so you can't stack bleed suppression + H.suppress_bloodloss(stop_bleeding) + if(affecting.status == BODYPART_ORGANIC) //Limb must be organic to be healed - RR + if(affecting.heal_damage(heal_brute, heal_burn)) + C.update_damage_overlays() else user << "Medicine won't work on a robotic limb!" else - M.heal_organ_damage((src.heal_brute/2), (src.heal_burn/2)) - + M.heal_bodypart_damage((src.heal_brute/2), (src.heal_burn/2)) use(1) diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm index 1fd3e766c627..a7f84608ffee 100644 --- a/code/game/objects/items/stacks/sheets/glass.dm +++ b/code/game/objects/items/stacks/sheets/glass.dm @@ -311,19 +311,16 @@ return if(istype(A, /obj/item/weapon/storage)) return - + var/hit_hand = ((user.active_hand_index % 2 == 0) ? "r_" : "l_") + "arm" if(ishuman(user)) var/mob/living/carbon/human/H = user if(!H.gloves && !(PIERCEIMMUNE in H.dna.species.specflags)) // golems, etc H << "[src] cuts into your hand!" - var/organ = ((H.active_hand_index % 2 == 0) ? "r_" : "l_") + "arm" - var/obj/item/bodypart/affecting = H.get_bodypart(organ) - if(affecting && affecting.take_damage(force / 2)) - H.update_damage_overlays(0) + H.apply_damage(force*0.5, BRUTE, hit_hand) else if(ismonkey(user)) var/mob/living/carbon/monkey/M = user M << "[src] cuts into your hand!" - M.adjustBruteLoss(force / 2) + M.apply_damage(force*0.5, BRUTE, hit_hand) /obj/item/weapon/shard/attackby(obj/item/I, mob/user, params) diff --git a/code/game/objects/items/weapons/grenades/flashbang.dm b/code/game/objects/items/weapons/grenades/flashbang.dm index 3763799c961e..5fdc8e8c197d 100644 --- a/code/game/objects/items/weapons/grenades/flashbang.dm +++ b/code/game/objects/items/weapons/grenades/flashbang.dm @@ -22,8 +22,6 @@ M.show_message("BANG", 2) playsound(loc, 'sound/weapons/flashbang.ogg', 100, 1) -//Checking for protection - var/ear_safety = M.check_ear_prot() var/distance = max(1,get_dist(src,T)) //Flash @@ -34,24 +32,12 @@ M.Stun(15) M.adjust_eye_damage(8) - if(M.flash_eyes(affect_silicon = 1)) + if(M.flash_act(affect_silicon = 1)) M.Stun(max(10/distance, 3)) M.Weaken(max(10/distance, 3)) //Bang if((loc == M) || loc == M.loc)//Holding on person or being exactly where lies is significantly more dangerous and voids protection - M.Stun(10) - M.Weaken(10) - if(!ear_safety) - M << sound('sound/weapons/flash_ring.ogg',0,1,0,100) - M.Stun(max(10/distance, 3)) - M.Weaken(max(10/distance, 3)) - M.setEarDamage(M.ear_damage + rand(0, 5), max(M.ear_deaf,15)) - if (M.ear_damage >= 15) - M << "Your ears start to ring badly!" - if(prob(M.ear_damage - 10 + 5)) - M << "You can't hear anything!" - M.disabilities |= DEAF - else - if (M.ear_damage >= 5) - M << "Your ears start to ring!" + M.soundbang_act(1, 10, rand(5, 10)) + else + M.soundbang_act(1, max(10/distance, 3), rand(0, 5)) diff --git a/code/game/objects/items/weapons/grenades/plastic.dm b/code/game/objects/items/weapons/grenades/plastic.dm index 4ec3541ce2f6..5d11b5bdac85 100644 --- a/code/game/objects/items/weapons/grenades/plastic.dm +++ b/code/game/objects/items/weapons/grenades/plastic.dm @@ -108,7 +108,7 @@ target = user sleep(10) prime() - user.gib(no_brain = 1) + user.gib(1, 1, 1) /obj/item/weapon/grenade/plastic/update_icon() if(nadeassembly) diff --git a/code/game/objects/items/weapons/grenades/spawnergrenade.dm b/code/game/objects/items/weapons/grenades/spawnergrenade.dm index 604767533657..76536e7b21d5 100644 --- a/code/game/objects/items/weapons/grenades/spawnergrenade.dm +++ b/code/game/objects/items/weapons/grenades/spawnergrenade.dm @@ -15,7 +15,7 @@ var/turf/T = get_turf(src) playsound(T, 'sound/effects/phasein.ogg', 100, 1) for(var/mob/living/carbon/C in viewers(T, null)) - C.flash_eyes() + C.flash_act() for(var/i=1, i<=deliveryamt, i++) var/atom/movable/x = new spawner_type diff --git a/code/game/objects/items/weapons/handcuffs.dm b/code/game/objects/items/weapons/handcuffs.dm index 8d76fcc492a4..810048f57821 100644 --- a/code/game/objects/items/weapons/handcuffs.dm +++ b/code/game/objects/items/weapons/handcuffs.dm @@ -30,12 +30,12 @@ return if(!C.handcuffed) - if(C.get_num_arms() >= 2) + if(C.get_num_arms() >= 2 || C.get_arm_ignore()) C.visible_message("[user] is trying to put [src.name] on [C]!", \ "[user] is trying to put [src.name] on [C]!") playsound(loc, cuffsound, 30, 1, -2) - if(do_mob(user, C, 30) && C.get_num_arms() >= 2) + if(do_mob(user, C, 30) && (C.get_num_arms() >= 2 || C.get_arm_ignore())) apply_cuffs(C,user) user << "You handcuff [C]." if(istype(src, /obj/item/weapon/restraints/handcuffs/cable)) diff --git a/code/game/objects/items/weapons/melee/energy.dm b/code/game/objects/items/weapons/melee/energy.dm index 106d91fdd732..9f93c93eca32 100644 --- a/code/game/objects/items/weapons/melee/energy.dm +++ b/code/game/objects/items/weapons/melee/energy.dm @@ -81,7 +81,7 @@ /obj/item/weapon/melee/energy/attack_self(mob/living/carbon/user) if(user.disabilities & CLUMSY && prob(50)) user << "You accidentally cut yourself with [src], like a doofus!" - user.take_organ_damage(5,5) + user.take_bodypart_damage(5,5) active = !active if (active) force = force_on diff --git a/code/game/objects/items/weapons/melee/misc.dm b/code/game/objects/items/weapons/melee/misc.dm index e9ca6ece91cb..3f35613f4420 100644 --- a/code/game/objects/items/weapons/melee/misc.dm +++ b/code/game/objects/items/weapons/melee/misc.dm @@ -67,7 +67,7 @@ var/mob/living/carbon/human/H = user H.apply_damage(2*force, BRUTE, "head") else - user.take_organ_damage(2*force) + user.take_bodypart_damage(2*force) return if(isrobot(target)) ..() @@ -124,7 +124,7 @@ if (B && !qdeleted(B)) H.internal_organs -= B qdel(B) - gibs(H.loc, H.viruses, H.dna) + new /obj/effect/gibspawner/generic(H.loc, H.viruses, H.dna) return (BRUTELOSS) /obj/item/weapon/melee/classic_baton/telescopic/attack_self(mob/user) diff --git a/code/game/objects/items/weapons/shields.dm b/code/game/objects/items/weapons/shields.dm index 24708a7829d9..26513f300b5c 100644 --- a/code/game/objects/items/weapons/shields.dm +++ b/code/game/objects/items/weapons/shields.dm @@ -74,7 +74,7 @@ /obj/item/weapon/shield/energy/attack_self(mob/living/carbon/human/user) if(user.disabilities & CLUMSY && prob(50)) user << "You beat yourself in the head with [src]." - user.take_organ_damage(5) + user.take_bodypart_damage(5) active = !active icon_state = "eshield[active]" diff --git a/code/game/objects/items/weapons/singularityhammer.dm b/code/game/objects/items/weapons/singularityhammer.dm index 07802d94a9a4..e8ef7dc94028 100644 --- a/code/game/objects/items/weapons/singularityhammer.dm +++ b/code/game/objects/items/weapons/singularityhammer.dm @@ -57,7 +57,7 @@ charged = 0 if(istype(A, /mob/living/)) var/mob/living/Z = A - Z.take_organ_damage(20,0) + Z.take_bodypart_damage(20,0) playsound(user, 'sound/weapons/marauder.ogg', 50, 1) var/turf/target = get_turf(A) vortex(target,user) diff --git a/code/game/objects/items/weapons/storage/book.dm b/code/game/objects/items/weapons/storage/book.dm index f6ffe2afb1a0..ab3d92007eae 100644 --- a/code/game/objects/items/weapons/storage/book.dm +++ b/code/game/objects/items/weapons/storage/book.dm @@ -114,15 +114,27 @@ var/global/list/bibleitemstates = list("bible", "koran", "scrapbook", "bible", " usr << browse(null, "window=editicon") // Close window -/obj/item/weapon/storage/book/bible/proc/bless(mob/living/carbon/M) - if(ishuman(M)) - var/mob/living/carbon/human/H = M - var/heal_amt = 10 - for(var/obj/item/bodypart/affecting in H.bodyparts) - if(affecting.status == ORGAN_ORGANIC) //No Bible can heal a robotic arm! - if(affecting.heal_damage(heal_amt, heal_amt, 0)) - H.update_damage_overlays(0) - return +/obj/item/weapon/storage/book/bible/proc/bless(mob/living/carbon/human/H, mob/living/user) + for(var/X in H.bodyparts) + var/obj/item/bodypart/BP = X + if(BP.status == BODYPART_ROBOTIC) + user << "[src.deity_name] refuses to heal this metallic taint!" + return 0 + + var/heal_amt = 10 + var/list/hurt_limbs = H.get_damaged_bodyparts(1, 1) + + if(hurt_limbs.len) + for(var/X in hurt_limbs) + var/obj/item/bodypart/affecting = X + if(affecting.heal_damage(heal_amt, heal_amt)) + H.update_damage_overlays() + H.visible_message("[user] heals [H] with the power of [deity_name]!") + H << "May the power of [deity_name] compel you to be healed!" + playsound(src.loc, "punch", 25, 1, -1) + return 1 + + /obj/item/weapon/storage/book/bible/attack(mob/living/M, mob/living/carbon/human/user) @@ -137,51 +149,40 @@ var/global/list/bibleitemstates = list("bible", "koran", "scrapbook", "bible", " return if(!chaplain) user << "The book sizzles in your hands." - user.take_organ_damage(0,10) + user.take_bodypart_damage(0,10) return if (user.disabilities & CLUMSY && prob(50)) user << "The [src] slips out of your hand and hits your head." - user.take_organ_damage(10) + user.take_bodypart_damage(10) user.Paralyse(20) return - if (M.stat !=2) - if(M.mind && (M.mind.assigned_role == "Chaplain")) + var/smack = 1 + + if (M.stat != DEAD) + if(chaplain && user == M) user << "You can't heal yourself!" return - if ((istype(M, /mob/living/carbon/human) && prob(60))) - bless(M) - if(ishuman(M)) - var/mob/living/carbon/human/H = M - var/message_halt = 0 - for(var/obj/item/bodypart/affecting in H.bodyparts) - if(affecting.status == ORGAN_ORGANIC) - if(message_halt == 0) - M.visible_message("[user] heals [M] with the power of [src.deity_name]!") - M << "May the power of [src.deity_name] compel you to be healed!" - playsound(src.loc, "punch", 25, 1, -1) - message_halt = 1 - else - user << "[src.deity_name] refuses to heal this metallic taint!" - return + if(ishuman(M) && prob(60) && bless(M, user)) + smack = 0 + else if(iscarbon(M)) + var/mob/living/carbon/C = M + if(!istype(C.head, /obj/item/clothing/head/helmet)) + C.adjustBrainLoss(10) + C << "You feel dumber." - - - else - if(ishuman(M) && !istype(M:head, /obj/item/clothing/head/helmet)) - M.adjustBrainLoss(10) - M << "You feel dumber." + if(smack) M.visible_message("[user] beats [M] over the head with [src]!", \ "[user] beats [M] over the head with [src]!") playsound(src.loc, "punch", 25, 1, -1) add_logs(user, M, "attacked", src) - else if(M.stat == 2) + else M.visible_message("[user] smacks [M]'s lifeless corpse with [src].") playsound(src.loc, "punch", 25, 1, -1) - return + /obj/item/weapon/storage/book/bible/afterattack(atom/A, mob/user, proximity) if(!proximity) diff --git a/code/game/objects/items/weapons/tanks/tanks.dm b/code/game/objects/items/weapons/tanks/tanks.dm index 9e5801e16670..537c4d37c781 100644 --- a/code/game/objects/items/weapons/tanks/tanks.dm +++ b/code/game/objects/items/weapons/tanks/tanks.dm @@ -114,7 +114,7 @@ H.hair_style = "Bald" H.update_hair() H.bleed_rate = 5 - gibs(H.loc, H.viruses, H.dna) + new /obj/effect/gibspawner/generic(H.loc, H.viruses, H.dna) H.adjustBruteLoss(1000) //to make the body super-bloody return (BRUTELOSS) diff --git a/code/game/objects/items/weapons/tools.dm b/code/game/objects/items/weapons/tools.dm index 906af763df6e..a48395a2cab8 100644 --- a/code/game/objects/items/weapons/tools.dm +++ b/code/game/objects/items/weapons/tools.dm @@ -298,7 +298,7 @@ var/obj/item/bodypart/affecting = H.get_bodypart(check_zone(user.zone_selected)) - if(affecting && affecting.status == ORGAN_ROBOTIC && user.a_intent != "harm") + if(affecting && affecting.status == BODYPART_ROBOTIC && user.a_intent != "harm") if(src.remove_fuel(1)) playsound(loc, 'sound/items/Welder.ogg', 50, 1) user.visible_message("[user] starts to fix some of the dents on [H]'s [affecting.name].", "You start fixing some of the dents on [H]'s [affecting.name].") @@ -347,7 +347,7 @@ reagents.remove_reagent("welding_fuel", amount) check_fuel() if(M) - M.flash_eyes(light_intensity) + M.flash_act(light_intensity) return TRUE else if(M) diff --git a/code/game/objects/items/weapons/twohanded.dm b/code/game/objects/items/weapons/twohanded.dm index 67792738d2b0..e597a00abca8 100644 --- a/code/game/objects/items/weapons/twohanded.dm +++ b/code/game/objects/items/weapons/twohanded.dm @@ -256,7 +256,7 @@ /obj/item/weapon/twohanded/dualsaber/proc/impale(mob/living/user) user << "You twirl around a bit before losing your balance and impaling yourself on \the [src]." if (force_wielded) - user.take_organ_damage(20,25) + user.take_bodypart_damage(20,25) else user.adjustStaminaLoss(25) diff --git a/code/modules/admin/verbs/manipulate_organs.dm b/code/modules/admin/verbs/manipulate_organs.dm index 82703edaa3e0..289d1b6cd7d6 100644 --- a/code/modules/admin/verbs/manipulate_organs.dm +++ b/code/modules/admin/verbs/manipulate_organs.dm @@ -26,7 +26,8 @@ organ.implant(C) if("drop organ/implant", "remove organ/implant") - for(var/obj/item/organ/I in C.internal_organs) + for(var/X in C.internal_organs) + var/obj/item/organ/I = X organs["[I.name] ([I.type])"] = I for(var/obj/item/weapon/implant/I in C) diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index 1008453f85bb..a229b10f337c 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -441,7 +441,7 @@ Traitors and the like can also be revived with the previous role mostly intact. var/datum/round_event/ion_storm/ion = new(0, announce_ion_laws, input) ion.start() - + feedback_add_details("admin_verb","IONC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/cmd_admin_rejuvenate(mob/living/M in mob_list) @@ -595,7 +595,7 @@ Traitors and the like can also be revived with the previous role mostly intact. message_admins("[key_name_admin(usr)] has gibbed [key_name_admin(M)]") if(istype(M, /mob/dead/observer)) - gibs(M.loc, M.viruses) + new /obj/effect/gibspawner/generic(M.loc, M.viruses) return if(confirm == "Yes") M.gib() @@ -612,7 +612,7 @@ Traitors and the like can also be revived with the previous role mostly intact. log_admin("[key_name(usr)] used gibself.") message_admins("[key_name_admin(usr)] used gibself.") feedback_add_details("admin_verb","GIBS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - mob.gib(1, 1) + mob.gib(1, 1, 1) /client/proc/cmd_admin_check_contents(mob/living/M in mob_list) set category = "Special Verbs" @@ -1152,4 +1152,4 @@ var/list/datum/outfit/custom_outfits = list() //Admin created outfits for(var/datum/station_goal/S in ticker.mode.station_goals) dat += "[S.name] - Announce | Remove
" dat += "
Add New Goal" - usr << browse(dat, "window=goals;size=400x400") \ No newline at end of file + usr << browse(dat, "window=goals;size=400x400") diff --git a/code/modules/assembly/flash.dm b/code/modules/assembly/flash.dm index 2ca234340538..aece047550c8 100644 --- a/code/modules/assembly/flash.dm +++ b/code/modules/assembly/flash.dm @@ -85,7 +85,7 @@ if(user && targeted) if(M.weakeyes) M.Weaken(3) //quick weaken bypasses eye protection but has no eye flash - if(M.flash_eyes(1, 1)) + if(M.flash_act(1, 1)) M.confused += power terrible_conversion_proc(M, user) M.Stun(1) @@ -100,7 +100,7 @@ user << "You fail to blind [M] with the flash!" M << "[user] fails to blind you with the flash!" else - if(M.flash_eyes()) + if(M.flash_act()) M.confused += power /obj/item/device/assembly/flash/attack(mob/living/M, mob/user) @@ -117,7 +117,7 @@ update_icon(1) M.Weaken(6) R.confused += 5 - R.flash_eyes(affect_silicon = 1) + R.flash_act(affect_silicon = 1) user.visible_message("[user] overloads [R]'s sensors with the flash!", "You overload [R]'s sensors with the flash!") return 1 diff --git a/code/modules/assembly/mousetrap.dm b/code/modules/assembly/mousetrap.dm index 30adb230404c..31ecea937bd4 100644 --- a/code/modules/assembly/mousetrap.dm +++ b/code/modules/assembly/mousetrap.dm @@ -60,8 +60,7 @@ H.Stun(3) if(affecting) if(affecting.take_damage(1, 0)) - H.update_damage_overlays(0) - H.updatehealth() + H.update_damage_overlays() else if(ismouse(target)) var/mob/living/simple_animal/mouse/M = target visible_message("SPLAT!") diff --git a/code/modules/client/verbs/suicide.dm b/code/modules/client/verbs/suicide.dm index cb6120efe3dd..659fe3f3c8dd 100644 --- a/code/modules/client/verbs/suicide.dm +++ b/code/modules/client/verbs/suicide.dm @@ -53,7 +53,7 @@ adjustOxyLoss(max(200 - getToxLoss() - getFireLoss() - getBruteLoss() - getOxyLoss(), 0)) death(0) -/mob/living/carbon/brain/verb/suicide() +/mob/living/brain/verb/suicide() set hidden = 1 if(!canSuicide()) return diff --git a/code/modules/clothing/glasses/glasses.dm b/code/modules/clothing/glasses/glasses.dm index 1c5375434f21..19bf143a1cdd 100644 --- a/code/modules/clothing/glasses/glasses.dm +++ b/code/modules/clothing/glasses/glasses.dm @@ -9,7 +9,7 @@ if(!(H.disabilities & BLIND)) if(H.glasses == src) H << "The [src] overloads and blinds you!" - H.flash_eyes(visual = 1) + H.flash_act(visual = 1) H.blind_eyes(3) H.blur_eyes(5) H.adjust_eye_damage(5) diff --git a/code/modules/crafting/recipes.dm b/code/modules/crafting/recipes.dm index 0bd4fff922ff..5dcbeb7c63b6 100644 --- a/code/modules/crafting/recipes.dm +++ b/code/modules/crafting/recipes.dm @@ -94,17 +94,17 @@ /datum/crafting_recipe/ed209 name = "ED209" result = /mob/living/simple_animal/bot/ed209 - reqs = list(/obj/item/robot_parts/robot_suit = 1, + reqs = list(/obj/item/robot_suit = 1, /obj/item/clothing/head/helmet = 1, /obj/item/clothing/suit/armor/vest = 1, - /obj/item/robot_parts/l_leg = 1, - /obj/item/robot_parts/r_leg = 1, + /obj/item/bodypart/l_leg/robot = 1, + /obj/item/bodypart/r_leg/robot = 1, /obj/item/stack/sheet/metal = 5, /obj/item/stack/cable_coil = 5, /obj/item/weapon/gun/energy/gun/advtaser = 1, /obj/item/weapon/stock_parts/cell = 1, /obj/item/device/assembly/prox_sensor = 1, - /obj/item/robot_parts/r_arm = 1) + /obj/item/bodypart/r_arm/robot = 1) tools = list(/obj/item/weapon/weldingtool, /obj/item/weapon/screwdriver) time = 60 category = CAT_ROBOT @@ -116,7 +116,7 @@ /obj/item/clothing/head/helmet/sec = 1, /obj/item/weapon/melee/baton = 1, /obj/item/device/assembly/prox_sensor = 1, - /obj/item/robot_parts/r_arm = 1) + /obj/item/bodypart/r_arm/robot = 1) tools = list(/obj/item/weapon/weldingtool) time = 60 category = CAT_ROBOT @@ -126,7 +126,7 @@ result = /mob/living/simple_animal/bot/cleanbot reqs = list(/obj/item/weapon/reagent_containers/glass/bucket = 1, /obj/item/device/assembly/prox_sensor = 1, - /obj/item/robot_parts/r_arm = 1) + /obj/item/bodypart/r_arm/robot = 1) time = 40 category = CAT_ROBOT @@ -136,7 +136,7 @@ reqs = list(/obj/item/weapon/storage/toolbox/mechanical = 1, /obj/item/stack/tile/plasteel = 1, /obj/item/device/assembly/prox_sensor = 1, - /obj/item/robot_parts/r_arm = 1) + /obj/item/bodypart/r_arm/robot = 1) time = 40 category = CAT_ROBOT @@ -146,7 +146,7 @@ reqs = list(/obj/item/device/healthanalyzer = 1, /obj/item/weapon/storage/firstaid = 1, /obj/item/device/assembly/prox_sensor = 1, - /obj/item/robot_parts/r_arm = 1) + /obj/item/bodypart/r_arm/robot = 1) time = 40 category = CAT_ROBOT diff --git a/code/modules/events/anomaly_bluespace.dm b/code/modules/events/anomaly_bluespace.dm index 19b3ac4abfa5..a2b2dbf31bc2 100644 --- a/code/modules/events/anomaly_bluespace.dm +++ b/code/modules/events/anomaly_bluespace.dm @@ -44,7 +44,7 @@ var/list/flashers = list() for(var/mob/living/carbon/C in viewers(TO, null)) - if(C.flash_eyes()) + if(C.flash_act()) flashers += C var/y_distance = TO.y - FROM.y diff --git a/code/modules/hydroponics/grown/nettle.dm b/code/modules/hydroponics/grown/nettle.dm index 0dd97c68a360..be78c4ef8b25 100644 --- a/code/modules/hydroponics/grown/nettle.dm +++ b/code/modules/hydroponics/grown/nettle.dm @@ -51,16 +51,13 @@ if(!iscarbon(user)) return 0 var/mob/living/carbon/C = user - if(ishuman(user)) - var/mob/living/carbon/human/H = C - if(H.gloves) - return 0 - var/organ = (H.held_index_to_dir(H.active_hand_index) == "l" ? "l_":"r_") + "arm" - var/obj/item/bodypart/affecting = H.get_bodypart(organ) - if(affecting && affecting.take_damage(0, force)) - H.update_damage_overlays(0) - else - C.take_organ_damage(0,force) + if(C.gloves) + return 0 + var/hit_zone = (C.held_index_to_dir(C.active_hand_index) == "l" ? "l_":"r_") + "arm" + var/obj/item/bodypart/affecting = C.get_bodypart(hit_zone) + if(affecting) + if(affecting.take_damage(0, force)) + C.update_damage_overlays() C << "The nettle burns your bare hand!" return 1 diff --git a/code/modules/mining/equipment.dm b/code/modules/mining/equipment.dm index 1b8e9a566125..adcd2b4762c4 100644 --- a/code/modules/mining/equipment.dm +++ b/code/modules/mining/equipment.dm @@ -507,7 +507,7 @@ range = 6 var/obj/item/weapon/twohanded/required/mining_hammer/hammer_synced = null -/obj/item/projectile/destabilizer/on_hit(atom/target, blocked = 0, hit_zone) +/obj/item/projectile/destabilizer/on_hit(atom/target, blocked = 0) if(hammer_synced) if(hammer_synced.mark == target) return ..() diff --git a/code/modules/mob/interactive.dm b/code/modules/mob/interactive.dm index ab0aa56e1c02..7be2862b0fc4 100644 --- a/code/modules/mob/interactive.dm +++ b/code/modules/mob/interactive.dm @@ -137,13 +137,14 @@ retal = 1 retal_target = user -/mob/living/carbon/human/interactive/bullet_act(var/obj/item/projectile/P) +/mob/living/carbon/human/interactive/bullet_act(obj/item/projectile/P, def_zone) var/potentialAssault = locate(/mob/living) in view(2,P.starting) if(potentialAssault) retal = 1 retal_target = potentialAssault ..() + /client/proc/resetSNPC(var/mob/A in SSnpc.botPool_l) set name = "Reset SNPC" set desc = "Reset the SNPC" @@ -296,9 +297,9 @@ for(var/X in bodyparts) var/obj/item/bodypart/BP = X if(prob((FUZZY_CHANCE_LOW+FUZZY_CHANCE_HIGH)/4)) - BP.change_bodypart_status(ORGAN_ROBOTIC) + BP.change_bodypart_status(BODYPART_ROBOTIC) update_icons() - update_damage_overlays(0) + update_damage_overlays() functions = list("nearbyscan","combat","shitcurity","chatter") // stop customize adding multiple copies of a function //job specific favours switch(myjob.title) @@ -422,10 +423,6 @@ if(C) retalTarget(C) -/mob/living/carbon/human/interactive/bullet_act(obj/item/projectile/P, def_zone) - ..(P,def_zone) - retalTarget(P.firer) - /mob/living/carbon/human/interactive/attack_hand(mob/living/carbon/human/M) ..(M) retalTarget(M) diff --git a/code/modules/mob/living/carbon/brain/MMI.dm b/code/modules/mob/living/brain/MMI.dm similarity index 92% rename from code/modules/mob/living/carbon/brain/MMI.dm rename to code/modules/mob/living/brain/MMI.dm index 0e6e1ee5b031..4979cbd6c7d5 100644 --- a/code/modules/mob/living/carbon/brain/MMI.dm +++ b/code/modules/mob/living/brain/MMI.dm @@ -1,198 +1,197 @@ -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 - -/obj/item/device/mmi - name = "Man-Machine Interface" - desc = "The Warrior's bland acronym, MMI, obscures the true horror of this monstrosity, that nevertheless has become standard-issue on Nanotrasen stations." - icon = 'icons/obj/assemblies.dmi' - icon_state = "mmi_empty" - w_class = 3 - origin_tech = "biotech=2;programming=3;engineering=2" - var/braintype = "Cyborg" - var/obj/item/device/radio/radio = null //Let's give it a radio. - var/hacked = 0 //Whether or not this is a Syndicate MMI - var/mob/living/carbon/brain/brainmob = null //The current occupant. - var/mob/living/silicon/robot = null //Appears unused. - var/obj/mecha = null //This does not appear to be used outside of reference in mecha.dm. - var/obj/item/organ/brain/brain = null //The actual brain - var/clockwork = FALSE //If this is a soul vessel - -/obj/item/device/mmi/update_icon() - if(brain) - if(istype(brain,/obj/item/organ/brain/alien)) - if(brainmob && brainmob.stat == DEAD) - icon_state = "mmi_alien_dead" - else - icon_state = "mmi_alien" - braintype = "Xenoborg" //HISS....Beep. - else - if(brainmob && brainmob.stat == DEAD) - icon_state = "mmi_dead" - else - icon_state = "mmi_full" - braintype = "Cyborg" - else - icon_state = "mmi_empty" - -/obj/item/device/mmi/New() - ..() - radio = new(src) //Spawns a radio inside the MMI. - radio.broadcasting = 0 //researching radio mmis turned the robofabs into radios because this didnt start as 0. - - - -/obj/item/device/mmi/attackby(obj/item/O, mob/user, params) - user.changeNext_move(CLICK_CD_MELEE) - if(istype(O,/obj/item/organ/brain)) //Time to stick a brain in it --NEO - var/obj/item/organ/brain/newbrain = O - if(brain) - user << "There's already a brain in the MMI!" - return - if(!newbrain.brainmob) - user << "You aren't sure where this brain came from, but you're pretty sure it's a useless brain!" - return - - if(!user.unEquip(O)) - return - var/mob/living/carbon/brain/B = newbrain.brainmob - if(!B.key) - B.notify_ghost_cloning("Someone has put your brain in a MMI!", source = src) - visible_message("[user] sticks \a [newbrain] into \the [src].") - - brainmob = newbrain.brainmob - newbrain.brainmob = null - brainmob.loc = src - brainmob.container = src - if(!newbrain.damaged_brain) // the brain organ hasn't been beaten to death. - brainmob.stat = CONSCIOUS //we manually revive the brain mob - dead_mob_list -= brainmob - living_mob_list += brainmob - - brainmob.reset_perspective() - if(clockwork) - add_servant_of_ratvar(brainmob, TRUE) - newbrain.loc = src //P-put your brain in it - brain = newbrain - - name = "Man-Machine Interface: [brainmob.real_name]" - update_icon() - - feedback_inc("cyborg_mmis_filled",1) - - return - - else if(brainmob) - O.attack(brainmob, user) //Oh noooeeeee - return - ..() - -/obj/item/device/mmi/attack_self(mob/user) - if(!brain) - radio.on = !radio.on - user << "You toggle the MMI's radio system [radio.on==1 ? "on" : "off"]." - else - user << "You unlock and upend the MMI, spilling the brain onto the floor." - - brainmob.container = null //Reset brainmob mmi var. - brainmob.loc = brain //Throw mob into brain. - brainmob.stat = DEAD - brainmob.emp_damage = 0 - brainmob.reset_perspective() //so the brainmob follows the brain organ instead of the mmi. And to update our vision - living_mob_list -= brainmob //Get outta here - dead_mob_list += brainmob - brain.brainmob = brainmob //Set the brain to use the brainmob - brainmob = null //Set mmi brainmob var to null - - user.put_in_hands(brain) //puts brain in the user's hand or otherwise drops it on the user's turf - brain = null //No more brain in here - - update_icon() - name = "Man-Machine Interface" - -/obj/item/device/mmi/proc/transfer_identity(mob/living/L) //Same deal as the regular brain proc. Used for human-->robot people. - if(!brainmob) - brainmob = new(src) - brainmob.name = L.real_name - brainmob.real_name = L.real_name - if(L.has_dna()) - var/mob/living/carbon/C = L - if(!brainmob.dna) - brainmob.dna = new /datum/dna(brainmob) - C.dna.copy_dna(brainmob.dna) - brainmob.container = src - - if(ishuman(L)) - var/mob/living/carbon/human/H = L - var/obj/item/organ/brain/newbrain = H.getorgan(/obj/item/organ/brain) - newbrain.loc = src - brain = newbrain - else if(!brain) - brain = new(src) - brain.name = "[L.real_name]'s brain" - - name = "Man-Machine Interface: [brainmob.real_name]" - update_icon() - return - - -/obj/item/device/mmi/verb/Toggle_Listening() - set name = "Toggle Listening" - set desc = "Toggle listening channel on or off." - set category = "MMI" - set src = usr.loc - set popup_menu = 0 - - if(brainmob.stat) - brainmob << "Can't do that while incapacitated or dead!" - if(!radio.on) - brainmob << "Your radio is disabled!" - return - - radio.listening = radio.listening==1 ? 0 : 1 - brainmob << "Radio is [radio.listening==1 ? "now" : "no longer"] receiving broadcast." - -/obj/item/device/mmi/emp_act(severity) - if(!brainmob) - return - else - switch(severity) - if(1) - brainmob.emp_damage = min(brainmob.emp_damage + rand(20,30), 30) - if(2) - brainmob.emp_damage = min(brainmob.emp_damage + rand(10,20), 30) - if(3) - brainmob.emp_damage = min(brainmob.emp_damage + rand(0,10), 30) - brainmob.emote("alarm") - ..() - -/obj/item/device/mmi/Destroy() - if(isrobot(loc)) - var/mob/living/silicon/robot/borg = loc - borg.mmi = null - if(brainmob) - qdel(brainmob) - brainmob = null - return ..() - -/obj/item/device/mmi/examine(mob/user) - ..() - if(brainmob) - var/mob/living/carbon/brain/B = brainmob - if(!B.key || !B.mind || B.stat == DEAD) - user << "The MMI indicates the brain is completely unresponsive." - - else if(!B.client) - user << "The MMI indicates the brain is currently inactive; it might change." - - else - user << "The MMI indicates the brain is active." - - -/obj/item/device/mmi/syndie - name = "Syndicate Man-Machine Interface" - desc = "Syndicate's own brand of MMI. It enforces laws designed to help Syndicate agents achieve their goals upon cyborgs created with it, but doesn't fit in Nanotrasen AI cores." - origin_tech = "biotech=4;programming=4;syndicate=2" - hacked = 1 - -/obj/item/device/mmi/syndie/New() - ..() - radio.on = 0 +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 + +/obj/item/device/mmi + name = "Man-Machine Interface" + desc = "The Warrior's bland acronym, MMI, obscures the true horror of this monstrosity, that nevertheless has become standard-issue on Nanotrasen stations." + icon = 'icons/obj/assemblies.dmi' + icon_state = "mmi_empty" + w_class = 3 + origin_tech = "biotech=2;programming=3;engineering=2" + var/braintype = "Cyborg" + var/obj/item/device/radio/radio = null //Let's give it a radio. + var/hacked = 0 //Whether or not this is a Syndicate MMI + var/mob/living/brain/brainmob = null //The current occupant. + var/mob/living/silicon/robot = null //Appears unused. + var/obj/mecha = null //This does not appear to be used outside of reference in mecha.dm. + var/obj/item/organ/brain/brain = null //The actual brain + var/clockwork = FALSE //If this is a soul vessel + +/obj/item/device/mmi/update_icon() + if(brain) + if(istype(brain,/obj/item/organ/brain/alien)) + if(brainmob && brainmob.stat == DEAD) + icon_state = "mmi_alien_dead" + else + icon_state = "mmi_alien" + braintype = "Xenoborg" //HISS....Beep. + else + if(brainmob && brainmob.stat == DEAD) + icon_state = "mmi_dead" + else + icon_state = "mmi_full" + braintype = "Cyborg" + else + icon_state = "mmi_empty" + +/obj/item/device/mmi/New() + ..() + radio = new(src) //Spawns a radio inside the MMI. + radio.broadcasting = 0 //researching radio mmis turned the robofabs into radios because this didnt start as 0. + + + +/obj/item/device/mmi/attackby(obj/item/O, mob/user, params) + user.changeNext_move(CLICK_CD_MELEE) + if(istype(O,/obj/item/organ/brain)) //Time to stick a brain in it --NEO + var/obj/item/organ/brain/newbrain = O + if(brain) + user << "There's already a brain in the MMI!" + return + if(!newbrain.brainmob) + user << "You aren't sure where this brain came from, but you're pretty sure it's a useless brain!" + return + + if(!user.unEquip(O)) + return + var/mob/living/brain/B = newbrain.brainmob + if(!B.key) + B.notify_ghost_cloning("Someone has put your brain in a MMI!", source = src) + visible_message("[user] sticks \a [newbrain] into \the [src].") + + brainmob = newbrain.brainmob + newbrain.brainmob = null + brainmob.loc = src + brainmob.container = src + if(!newbrain.damaged_brain) // the brain organ hasn't been beaten to death. + brainmob.stat = CONSCIOUS //we manually revive the brain mob + dead_mob_list -= brainmob + living_mob_list += brainmob + + brainmob.reset_perspective() + if(clockwork) + add_servant_of_ratvar(brainmob, TRUE) + newbrain.loc = src //P-put your brain in it + brain = newbrain + + name = "Man-Machine Interface: [brainmob.real_name]" + update_icon() + + feedback_inc("cyborg_mmis_filled",1) + + else if(brainmob) + O.attack(brainmob, user) //Oh noooeeeee + else + return ..() + + +/obj/item/device/mmi/attack_self(mob/user) + if(!brain) + radio.on = !radio.on + user << "You toggle the MMI's radio system [radio.on==1 ? "on" : "off"]." + else + user << "You unlock and upend the MMI, spilling the brain onto the floor." + + brainmob.container = null //Reset brainmob mmi var. + brainmob.loc = brain //Throw mob into brain. + brainmob.stat = DEAD + brainmob.emp_damage = 0 + brainmob.reset_perspective() //so the brainmob follows the brain organ instead of the mmi. And to update our vision + living_mob_list -= brainmob //Get outta here + dead_mob_list += brainmob + brain.brainmob = brainmob //Set the brain to use the brainmob + brainmob = null //Set mmi brainmob var to null + + user.put_in_hands(brain) //puts brain in the user's hand or otherwise drops it on the user's turf + brain = null //No more brain in here + + update_icon() + name = "Man-Machine Interface" + +/obj/item/device/mmi/proc/transfer_identity(mob/living/L) //Same deal as the regular brain proc. Used for human-->robot people. + if(!brainmob) + brainmob = new(src) + brainmob.name = L.real_name + brainmob.real_name = L.real_name + if(L.has_dna()) + var/mob/living/carbon/C = L + if(!brainmob.stored_dna) + brainmob.stored_dna = new /datum/dna/stored(brainmob) + C.dna.copy_dna(brainmob.stored_dna) + brainmob.container = src + + if(ishuman(L)) + var/mob/living/carbon/human/H = L + var/obj/item/organ/brain/newbrain = H.getorgan(/obj/item/organ/brain) + newbrain.loc = src + brain = newbrain + else if(!brain) + brain = new(src) + brain.name = "[L.real_name]'s brain" + + name = "Man-Machine Interface: [brainmob.real_name]" + update_icon() + return + + +/obj/item/device/mmi/verb/Toggle_Listening() + set name = "Toggle Listening" + set desc = "Toggle listening channel on or off." + set category = "MMI" + set src = usr.loc + set popup_menu = 0 + + if(brainmob.stat) + brainmob << "Can't do that while incapacitated or dead!" + if(!radio.on) + brainmob << "Your radio is disabled!" + return + + radio.listening = radio.listening==1 ? 0 : 1 + brainmob << "Radio is [radio.listening==1 ? "now" : "no longer"] receiving broadcast." + +/obj/item/device/mmi/emp_act(severity) + if(!brainmob) + return + else + switch(severity) + if(1) + brainmob.emp_damage = min(brainmob.emp_damage + rand(20,30), 30) + if(2) + brainmob.emp_damage = min(brainmob.emp_damage + rand(10,20), 30) + if(3) + brainmob.emp_damage = min(brainmob.emp_damage + rand(0,10), 30) + brainmob.emote("alarm") + ..() + +/obj/item/device/mmi/Destroy() + if(isrobot(loc)) + var/mob/living/silicon/robot/borg = loc + borg.mmi = null + if(brainmob) + qdel(brainmob) + brainmob = null + return ..() + +/obj/item/device/mmi/examine(mob/user) + ..() + if(brainmob) + var/mob/living/brain/B = brainmob + if(!B.key || !B.mind || B.stat == DEAD) + user << "The MMI indicates the brain is completely unresponsive." + + else if(!B.client) + user << "The MMI indicates the brain is currently inactive; it might change." + + else + user << "The MMI indicates the brain is active." + + +/obj/item/device/mmi/syndie + name = "Syndicate Man-Machine Interface" + desc = "Syndicate's own brand of MMI. It enforces laws designed to help Syndicate agents achieve their goals upon cyborgs created with it, but doesn't fit in Nanotrasen AI cores." + origin_tech = "biotech=4;programming=4;syndicate=2" + hacked = 1 + +/obj/item/device/mmi/syndie/New() + ..() + radio.on = 0 diff --git a/code/modules/mob/living/carbon/brain/brain.dm b/code/modules/mob/living/brain/brain.dm similarity index 50% rename from code/modules/mob/living/carbon/brain/brain.dm rename to code/modules/mob/living/brain/brain.dm index a089a58bd776..dfdf30fb3c53 100644 --- a/code/modules/mob/living/carbon/brain/brain.dm +++ b/code/modules/mob/living/brain/brain.dm @@ -1,63 +1,67 @@ -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 - -/mob/living/carbon/brain - languages_spoken = HUMAN - languages_understood = HUMAN - var/obj/item/device/mmi/container = null - var/timeofhostdeath = 0 - var/emp_damage = 0//Handles a type of MMI damage - has_limbs = 0 - stat = DEAD //we start dead by default - see_invisible = SEE_INVISIBLE_MINIMUM - -/mob/living/carbon/brain/New(loc) - ..() - if(isturf(loc)) //not spawned in an MMI or brain organ (most likely adminspawned) - var/obj/item/organ/brain/OB = new(loc) //we create a new brain organ for it. - src.loc = OB - OB.brainmob = src - - -/mob/living/carbon/brain/Destroy() - if(key) //If there is a mob connected to this thing. Have to check key twice to avoid false death reporting. - if(stat!=DEAD) //If not dead. - death(1) //Brains can die again. AND THEY SHOULD AHA HA HA HA HA HA - ghostize() //Ghostize checks for key so nothing else is necessary. - container = null - return ..() - -/mob/living/carbon/brain/update_canmove() - if(in_contents_of(/obj/mecha)) - canmove = 1 - else - canmove = 0 - return canmove - -/mob/living/carbon/brain/toggle_throw_mode() - return - -/mob/living/carbon/brain/ex_act() //you cant blow up brainmobs because it makes transfer_to() freak out when borgs blow up. - return - -/mob/living/carbon/brain/blob_act(obj/effect/blob/B) - return - -/mob/living/carbon/brain/UnarmedAttack(atom/A)//Stops runtimes due to attack_animal being the default - return - -/mob/living/carbon/brain/check_ear_prot() - return 1 - -/mob/living/carbon/brain/flash_eyes(intensity = 1, override_blindness_check = 0, affect_silicon = 0) - return // no eyes, no flashing - -/mob/living/carbon/brain/update_damage_hud() - return //no red circles for brain - -/mob/living/carbon/brain/can_be_revived() - . = 1 - if(!container || health <= HEALTH_THRESHOLD_DEAD) - return 0 - -/mob/living/carbon/brain/update_sight() - return +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 + +/mob/living/brain + languages_spoken = HUMAN + languages_understood = HUMAN + var/obj/item/device/mmi/container = null + var/timeofhostdeath = 0 + var/emp_damage = 0//Handles a type of MMI damage + var/datum/dna/stored/stored_dna // dna var for brain. Used to store dna, brain dna is not considered like actual dna, brain.has_dna() returns FALSE. + stat = DEAD //we start dead by default + see_invisible = SEE_INVISIBLE_MINIMUM + +/mob/living/brain/New(loc) + ..() + create_dna(src) + stored_dna.initialize_dna(random_blood_type()) + if(isturf(loc)) //not spawned in an MMI or brain organ (most likely adminspawned) + var/obj/item/organ/brain/OB = new(loc) //we create a new brain organ for it. + src.loc = OB + OB.brainmob = src + + +/mob/living/brain/proc/create_dna() + stored_dna = new /datum/dna/stored(src) + if(!stored_dna.species) + var/rando_race = pick(config.roundstart_races) + stored_dna.species = new rando_race() + +/mob/living/brain/Destroy() + if(key) //If there is a mob connected to this thing. Have to check key twice to avoid false death reporting. + if(stat!=DEAD) //If not dead. + death(1) //Brains can die again. AND THEY SHOULD AHA HA HA HA HA HA + ghostize() //Ghostize checks for key so nothing else is necessary. + container = null + return ..() + +/mob/living/brain/update_canmove() + if(in_contents_of(/obj/mecha)) + canmove = 1 + else + canmove = 0 + return canmove + +/mob/living/brain/ex_act() //you cant blow up brainmobs because it makes transfer_to() freak out when borgs blow up. + return + +/mob/living/brain/blob_act(obj/effect/blob/B) + return + +/mob/living/brain/get_eye_protection()//no eyes + return 2 + +/mob/living/brain/get_ear_protection()//no ears + return 2 + +/mob/living/brain/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0) + return // no eyes, no flashing + +/mob/living/brain/can_be_revived() + . = 1 + if(!container || health <= HEALTH_THRESHOLD_DEAD) + return 0 + +/mob/living/brain/fully_replace_character_name(oldname,newname) + ..() + if(stored_dna) + stored_dna.real_name = real_name \ No newline at end of file diff --git a/code/modules/mob/living/carbon/brain/brain_item.dm b/code/modules/mob/living/brain/brain_item.dm similarity index 65% rename from code/modules/mob/living/carbon/brain/brain_item.dm rename to code/modules/mob/living/brain/brain_item.dm index e5e7d511fc0e..4bccb03c2d80 100644 --- a/code/modules/mob/living/carbon/brain/brain_item.dm +++ b/code/modules/mob/living/brain/brain_item.dm @@ -1,127 +1,122 @@ -/obj/item/organ/brain - name = "brain" - desc = "A piece of juicy meat found in a person's head." - icon_state = "brain" - throw_speed = 3 - throw_range = 5 - layer = ABOVE_MOB_LAYER - zone = "head" - slot = "brain" - vital = 1 - origin_tech = "biotech=5" - attack_verb = list("attacked", "slapped", "whacked") - var/mob/living/carbon/brain/brainmob = null - var/damaged_brain = 0 //whether the brain organ is damaged. - -/obj/item/organ/brain/Insert(mob/living/carbon/M, special = 0) - ..() - name = "brain" - if(brainmob) - if(M.key) - M.ghostize() - - if(brainmob.mind) - brainmob.mind.transfer_to(M) - else - M.key = brainmob.key - - qdel(brainmob) - - //Update the body's icon so it doesnt appear debrained anymore - if(ishuman(M)) - var/mob/living/carbon/human/H = M - H.update_hair(0) - -/obj/item/organ/brain/Remove(mob/living/carbon/M, special = 0) - ..() - if(!special) - transfer_identity(M) - if(ishuman(M)) - var/mob/living/carbon/human/H = M - H.update_hair(0) - -/obj/item/organ/brain/prepare_eat() - return // Too important to eat. - -/obj/item/organ/brain/proc/transfer_identity(mob/living/L) - name = "[L.name]'s brain" - brainmob = new(src) - brainmob.name = L.real_name - brainmob.real_name = L.real_name - brainmob.timeofhostdeath = L.timeofdeath - if(L.has_dna()) - var/mob/living/carbon/C = L - if(!brainmob.dna) - brainmob.dna = new /datum/dna(brainmob) - C.dna.copy_dna(brainmob.dna) - if(L.mind && L.mind.current && (L.mind.current.stat == DEAD)) - L.mind.transfer_to(brainmob) - brainmob << "You feel slightly disoriented. That's normal when you're just a brain." - -/obj/item/organ/brain/attackby(obj/item/O, mob/user, params) - user.changeNext_move(CLICK_CD_MELEE) - if(brainmob) - O.attack(brainmob, user) //Oh noooeeeee - -/obj/item/organ/brain/examine(mob/user) - ..() - - if(brainmob) - if(brainmob.client) - if(brainmob.health <= HEALTH_THRESHOLD_DEAD) - user << "It's lifeless and severely damaged." - else - user << "You can feel the small spark of life still left in this one." - else - user << "This one seems particularly lifeless. Perhaps it will regain some of its luster later." - else - user << "This one is completely devoid of life." - -/obj/item/organ/brain/attack(mob/living/carbon/M, mob/user) - if(!istype(M)) - return ..() - - add_fingerprint(user) - - if(user.zone_selected != "head") - return ..() - - var/mob/living/carbon/human/H = M - if(istype(H) && ((H.head && H.head.flags_cover & HEADCOVERSEYES) || (H.wear_mask && H.wear_mask.flags_cover & MASKCOVERSEYES) || (H.glasses && H.glasses.flags & GLASSESCOVERSEYES))) - user << "You're going to need to remove their head cover first!" - return - -//since these people will be dead M != usr - - if(!M.getorgan(/obj/item/organ/brain)) - if(istype(H) && !H.get_bodypart("head")) - return - user.drop_item() - var/msg = "[M] has [src] inserted into \his head by [user]." - if(M == user) - msg = "[user] inserts [src] into \his head!" - - M.visible_message("[msg]", - "[msg]") - - if(M != user) - M << "[user] inserts [src] into your head." - user << "You insert [src] into [M]'s head." - else - user << "You insert [src] into your head." //LOL - - Insert(M) - else - ..() - -/obj/item/organ/brain/Destroy() //copypasted from MMIs. - if(brainmob) - qdel(brainmob) - brainmob = null - return ..() - -/obj/item/organ/brain/alien - name = "alien brain" - desc = "We barely understand the brains of terrestial animals. Who knows what we may find in the brain of such an advanced species?" - icon_state = "brain-x" - origin_tech = "biotech=6" +/obj/item/organ/brain + name = "brain" + desc = "A piece of juicy meat found in a person's head." + icon_state = "brain" + throw_speed = 3 + throw_range = 5 + layer = ABOVE_MOB_LAYER + zone = "head" + slot = "brain" + vital = 1 + origin_tech = "biotech=5" + attack_verb = list("attacked", "slapped", "whacked") + var/mob/living/brain/brainmob = null + var/damaged_brain = 0 //whether the brain organ is damaged. + +/obj/item/organ/brain/Insert(mob/living/carbon/C, special = 0) + ..() + name = "brain" + if(brainmob) + if(C.key) + C.ghostize() + + if(brainmob.mind) + brainmob.mind.transfer_to(C) + else + C.key = brainmob.key + + qdel(brainmob) + + //Update the body's icon so it doesnt appear debrained anymore + C.update_hair() + +/obj/item/organ/brain/Remove(mob/living/carbon/C, special = 0) + ..() + if(!special) + transfer_identity(C) + C.update_hair() + +/obj/item/organ/brain/prepare_eat() + return // Too important to eat. + +/obj/item/organ/brain/proc/transfer_identity(mob/living/L) + name = "[L.name]'s brain" + brainmob = new(src) + brainmob.name = L.real_name + brainmob.real_name = L.real_name + brainmob.timeofhostdeath = L.timeofdeath + if(L.has_dna()) + var/mob/living/carbon/C = L + if(!brainmob.stored_dna) + brainmob.stored_dna = new /datum/dna/stored(brainmob) + C.dna.copy_dna(brainmob.stored_dna) + if(L.mind && L.mind.current && (L.mind.current.stat == DEAD)) + L.mind.transfer_to(brainmob) + brainmob << "You feel slightly disoriented. That's normal when you're just a brain." + +/obj/item/organ/brain/attackby(obj/item/O, mob/user, params) + user.changeNext_move(CLICK_CD_MELEE) + if(brainmob) + O.attack(brainmob, user) //Oh noooeeeee + +/obj/item/organ/brain/examine(mob/user) + ..() + + if(brainmob) + if(brainmob.client) + if(brainmob.health <= HEALTH_THRESHOLD_DEAD) + user << "It's lifeless and severely damaged." + else + user << "You can feel the small spark of life still left in this one." + else + user << "This one seems particularly lifeless. Perhaps it will regain some of its luster later." + else + user << "This one is completely devoid of life." + +/obj/item/organ/brain/attack(mob/living/carbon/C, mob/user) + if(!istype(C)) + return ..() + + add_fingerprint(user) + + if(user.zone_selected != "head") + return ..() + + if((C.head && (C.head.flags_cover & HEADCOVERSEYES)) || (C.wear_mask && (C.wear_mask.flags_cover & MASKCOVERSEYES)) || (C.glasses && (C.glasses.flags & GLASSESCOVERSEYES))) + user << "You're going to need to remove their head cover first!" + return + +//since these people will be dead M != usr + + if(!C.getorgan(/obj/item/organ/brain)) + if(!C.get_bodypart("head")) + return + user.drop_item() + var/msg = "[C] has [src] inserted into \his head by [user]." + if(C == user) + msg = "[user] inserts [src] into \his head!" + + C.visible_message("[msg]", + "[msg]") + + if(C != user) + C << "[user] inserts [src] into your head." + user << "You insert [src] into [C]'s head." + else + user << "You insert [src] into your head." //LOL + + Insert(C) + else + ..() + +/obj/item/organ/brain/Destroy() //copypasted from MMIs. + if(brainmob) + qdel(brainmob) + brainmob = null + return ..() + +/obj/item/organ/brain/alien + name = "alien brain" + desc = "We barely understand the brains of terrestial animals. Who knows what we may find in the brain of such an advanced species?" + icon_state = "brain-x" + origin_tech = "biotech=6" diff --git a/code/modules/mob/living/carbon/brain/death.dm b/code/modules/mob/living/brain/death.dm similarity index 83% rename from code/modules/mob/living/carbon/brain/death.dm rename to code/modules/mob/living/brain/death.dm index 67b700b2b08e..e98859b90ff2 100644 --- a/code/modules/mob/living/carbon/brain/death.dm +++ b/code/modules/mob/living/brain/death.dm @@ -1,20 +1,20 @@ -/mob/living/carbon/brain/death(gibbed) - if(stat == DEAD) - return - stat = DEAD - - if(!gibbed && container)//If not gibbed but in a container. - var/obj/item/device/mmi = container - mmi.visible_message("[src]'s MMI flatlines!", \ - "You hear something flatline.") - mmi.update_icon() - - return ..() - -/mob/living/carbon/brain/gib() - if(container) - qdel(container)//Gets rid of the MMI if there is one - if(loc) - if(istype(loc,/obj/item/organ/brain)) - qdel(loc)//Gets rid of the brain item +/mob/living/brain/death(gibbed) + if(stat == DEAD) + return + stat = DEAD + + if(!gibbed && container)//If not gibbed but in a container. + var/obj/item/device/mmi = container + mmi.visible_message("[src]'s MMI flatlines!", \ + "You hear something flatline.") + mmi.update_icon() + + return ..() + +/mob/living/brain/gib() + if(container) + qdel(container)//Gets rid of the MMI if there is one + if(loc) + if(istype(loc,/obj/item/organ/brain)) + qdel(loc)//Gets rid of the brain item ..() \ No newline at end of file diff --git a/code/modules/mob/living/carbon/brain/emote.dm b/code/modules/mob/living/brain/emote.dm similarity index 91% rename from code/modules/mob/living/carbon/brain/emote.dm rename to code/modules/mob/living/brain/emote.dm index bd4be7c66f9b..8ab505f7a9ef 100644 --- a/code/modules/mob/living/carbon/brain/emote.dm +++ b/code/modules/mob/living/brain/emote.dm @@ -1,71 +1,71 @@ -/mob/living/carbon/brain/emote(act,m_type=1,message = null) - if(!(container && istype(container, /obj/item/device/mmi)))//No MMI, no emotes - return - - if (findtext(act, "-", 1, null)) - var/t1 = findtext(act, "-", 1, null) - act = copytext(act, 1, t1) - - - if(src.stat == DEAD) - return - switch(act) - if ("alarm") - src << "You sound an alarm." - message = "[src] sounds an alarm." - m_type = 2 - - if ("alert") - src << "You let out a distressed noise." - message = "[src] lets out a distressed noise." - m_type = 2 - - if ("beep","beeps") - src << "You beep." - message = "[src] beeps." - m_type = 2 - - if ("blink","blinks") - message = "[src] blinks." - m_type = 1 - - if ("boop","boops") - src << "You boop." - message = "[src] boops." - m_type = 2 - - if ("flash") - message = "The lights on [src] flash quickly." - m_type = 1 - - if ("notice") - src << "You play a loud tone." - message = "[src] plays a loud tone." - m_type = 2 - - if ("whistle","whistles") - src << "You whistle." - message = "[src] whistles." - m_type = 2 - - if ("help") - src << "Help for MMI emotes. You can use these emotes with say \"*emote\":\nalarm, alert, beep, blink, boop, flash, notice, whistle" - - else - src << "Unusable emote '[act]'. Say *help for a list." - return - - if (message) - log_emote("[name]/[key] : [message]") - - for(var/mob/M in dead_mob_list) - if (!M.client || istype(M, /mob/new_player)) - continue //skip monkeys, leavers, and new_players - if(M.stat == DEAD && (M.client && (M.client.prefs.chat_toggles & CHAT_GHOSTSIGHT)) && !(M in viewers(src,null))) - M.show_message(message) - - - if (m_type & 1) - visible_message(message) - else if (m_type & 2) +/mob/living/brain/emote(act,m_type=1,message = null) + if(!(container && istype(container, /obj/item/device/mmi)))//No MMI, no emotes + return + + if (findtext(act, "-", 1, null)) + var/t1 = findtext(act, "-", 1, null) + act = copytext(act, 1, t1) + + + if(src.stat == DEAD) + return + switch(act) + if ("alarm") + src << "You sound an alarm." + message = "[src] sounds an alarm." + m_type = 2 + + if ("alert") + src << "You let out a distressed noise." + message = "[src] lets out a distressed noise." + m_type = 2 + + if ("beep","beeps") + src << "You beep." + message = "[src] beeps." + m_type = 2 + + if ("blink","blinks") + message = "[src] blinks." + m_type = 1 + + if ("boop","boops") + src << "You boop." + message = "[src] boops." + m_type = 2 + + if ("flash") + message = "The lights on [src] flash quickly." + m_type = 1 + + if ("notice") + src << "You play a loud tone." + message = "[src] plays a loud tone." + m_type = 2 + + if ("whistle","whistles") + src << "You whistle." + message = "[src] whistles." + m_type = 2 + + if ("help") + src << "Help for MMI emotes. You can use these emotes with say \"*emote\":\nalarm, alert, beep, blink, boop, flash, notice, whistle" + + else + src << "Unusable emote '[act]'. Say *help for a list." + return + + if (message) + log_emote("[name]/[key] : [message]") + + for(var/mob/M in dead_mob_list) + if (!M.client || istype(M, /mob/new_player)) + continue //skip monkeys, leavers, and new_players + if(M.stat == DEAD && (M.client && (M.client.prefs.chat_toggles & CHAT_GHOSTSIGHT)) && !(M in viewers(src,null))) + M.show_message(message) + + + if (m_type & 1) + visible_message(message) + else if (m_type & 2) audible_message(message) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/brain/life.dm b/code/modules/mob/living/brain/life.dm similarity index 57% rename from code/modules/mob/living/carbon/brain/life.dm rename to code/modules/mob/living/brain/life.dm index 75f731b6e69a..9d87f412e8d9 100644 --- a/code/modules/mob/living/carbon/brain/life.dm +++ b/code/modules/mob/living/brain/life.dm @@ -1,60 +1,49 @@ - -/mob/living/carbon/brain/Life() - set invisibility = 0 - set background = BACKGROUND_ENABLED - - if (notransform) - return - if(!loc) - return - . = ..() - handle_emp_damage() - -/mob/living/carbon/brain/handle_breathing() - return - -/mob/living/carbon/brain/handle_mutations_and_radiation() - return - -/mob/living/carbon/brain/handle_environment(datum/gas_mixture/environment) - return - -/mob/living/carbon/brain/update_stat() - if(status_flags & GODMODE) - return - if(health <= HEALTH_THRESHOLD_DEAD) - if(stat != DEAD) - death() - var/obj/item/organ/brain/BR - if(container && container.brain) - BR = container.brain - else if(istype(loc, /obj/item/organ/brain)) - BR = loc - if(BR) - BR.damaged_brain = 1 //beaten to a pulp - -/* //currently unused feature, since brain outside a mmi is always dead. -/mob/living/carbon/brain/proc/handle_brain_revival_life() - if(stat != DEAD) - if(config.revival_brain_life != -1) - if( !container && (world.time - timeofhostdeath) > config.revival_brain_life) - death() -*/ - -/mob/living/carbon/brain/proc/handle_emp_damage() - if(emp_damage) - if(stat == DEAD) - emp_damage = 0 - else - emp_damage = max(emp_damage-1, 0) - -/mob/living/carbon/brain/handle_status_effects() - return - -/mob/living/carbon/brain/handle_disabilities() - return - -/mob/living/carbon/brain/handle_changeling() - return - - + +/mob/living/brain/Life() + set invisibility = 0 + set background = BACKGROUND_ENABLED + + if (notransform) + return + if(!loc) + return + . = ..() + handle_emp_damage() + +/mob/living/brain/update_stat() + if(status_flags & GODMODE) + return + if(health <= HEALTH_THRESHOLD_DEAD) + if(stat != DEAD) + death() + var/obj/item/organ/brain/BR + if(container && container.brain) + BR = container.brain + else if(istype(loc, /obj/item/organ/brain)) + BR = loc + if(BR) + BR.damaged_brain = 1 //beaten to a pulp + +/* //currently unused feature, since brain outside a mmi is always dead. +/mob/living/brain/proc/handle_brain_revival_life() + if(stat != DEAD) + if(config.revival_brain_life != -1) + if( !container && (world.time - timeofhostdeath) > config.revival_brain_life) + death() +*/ + +/mob/living/brain/proc/handle_emp_damage() + if(emp_damage) + if(stat == DEAD) + emp_damage = 0 + else + emp_damage = max(emp_damage-1, 0) + +/mob/living/brain/handle_status_effects() + return + +/mob/living/brain/handle_disabilities() + return + + + diff --git a/code/modules/mob/living/carbon/brain/posibrain.dm b/code/modules/mob/living/brain/posibrain.dm similarity index 98% rename from code/modules/mob/living/carbon/brain/posibrain.dm rename to code/modules/mob/living/brain/posibrain.dm index 229f2b52fced..f7ad95798a5a 100644 --- a/code/modules/mob/living/carbon/brain/posibrain.dm +++ b/code/modules/mob/living/brain/posibrain.dm @@ -80,11 +80,10 @@ var/global/posibrain_notif_cooldown = 0 name = "[initial(name)] ([C])" brainmob.name = C.real_name brainmob.real_name = C.real_name - brainmob.dna = C.dna if(C.has_dna()) - if(!brainmob.dna) - brainmob.dna = new /datum/dna(brainmob) - C.dna.copy_dna(brainmob.dna) + if(!brainmob.stored_dna) + brainmob.stored_dna = new /datum/dna/stored(brainmob) + C.dna.copy_dna(brainmob.stored_dna) brainmob.timeofhostdeath = C.timeofdeath brainmob.stat = CONSCIOUS if(brainmob.mind) diff --git a/code/modules/mob/living/carbon/brain/say.dm b/code/modules/mob/living/brain/say.dm similarity index 70% rename from code/modules/mob/living/carbon/brain/say.dm rename to code/modules/mob/living/brain/say.dm index 77f72d484a7d..0aeb312ee0fd 100644 --- a/code/modules/mob/living/carbon/brain/say.dm +++ b/code/modules/mob/living/brain/say.dm @@ -1,23 +1,23 @@ -/mob/living/carbon/brain/say(message) - if(!(container && istype(container, /obj/item/device/mmi))) - return //No MMI, can't speak, bucko./N - else - if(prob(emp_damage*4)) - if(prob(10))//10% chane to drop the message entirely - return - else - message = Gibberish(message, (emp_damage*6))//scrambles the message, gets worse when emp_damage is higher - ..() - -/mob/living/carbon/brain/radio(message, message_mode, list/spans) - if(message_mode && istype(container, /obj/item/device/mmi)) - var/obj/item/device/mmi/R = container - if(R.radio) - R.radio.talk_into(src, message, , spans) - return ITALICS | REDUCE_RANGE - -/mob/living/carbon/brain/lingcheck() - return 0 - -/mob/living/carbon/brain/treat_message(message) +/mob/living/brain/say(message) + if(!(container && istype(container, /obj/item/device/mmi))) + return //No MMI, can't speak, bucko./N + else + if(prob(emp_damage*4)) + if(prob(10))//10% chane to drop the message entirely + return + else + message = Gibberish(message, (emp_damage*6))//scrambles the message, gets worse when emp_damage is higher + ..() + +/mob/living/brain/radio(message, message_mode, list/spans) + if(message_mode && istype(container, /obj/item/device/mmi)) + var/obj/item/device/mmi/R = container + if(R.radio) + R.radio.talk_into(src, message, , spans) + return ITALICS | REDUCE_RANGE + +/mob/living/brain/lingcheck() + return 0 + +/mob/living/brain/treat_message(message) return message \ No newline at end of file diff --git a/code/modules/mob/living/carbon/brain/status_procs.dm b/code/modules/mob/living/brain/status_procs.dm similarity index 52% rename from code/modules/mob/living/carbon/brain/status_procs.dm rename to code/modules/mob/living/brain/status_procs.dm index dc8ff6ffc1e1..caf2bfe22c4c 100644 --- a/code/modules/mob/living/carbon/brain/status_procs.dm +++ b/code/modules/mob/living/brain/status_procs.dm @@ -4,35 +4,30 @@ /////////////////////////////////// EAR DAMAGE //////////////////////////////////// -/mob/living/carbon/brain/adjustEarDamage() +/mob/living/brain/adjustEarDamage() return -/mob/living/carbon/brain/setEarDamage() // no ears to damage or heal +/mob/living/brain/setEarDamage() // no ears to damage or heal return /////////////////////////////////// EYE_BLIND //////////////////////////////////// -/mob/living/carbon/brain/blind_eyes() // no eyes to damage or heal +/mob/living/brain/blind_eyes() // no eyes to damage or heal return -/mob/living/carbon/brain/adjust_blindness() +/mob/living/brain/adjust_blindness() return -/mob/living/carbon/brain/set_blindness() +/mob/living/brain/set_blindness() return /////////////////////////////////// EYE_BLURRY //////////////////////////////////// -/mob/living/carbon/brain/blur_eyes() +/mob/living/brain/blur_eyes() return -/mob/living/carbon/brain/adjust_blurriness() +/mob/living/brain/adjust_blurriness() return -/mob/living/carbon/brain/set_blurriness() +/mob/living/brain/set_blurriness() return - -/////////////////////////////////// BLIND DISABILITY //////////////////////////////////// - -/mob/living/carbon/brain/become_blind() - return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/alien.dm b/code/modules/mob/living/carbon/alien/alien.dm index c8f7ce99a227..42572b1c03ca 100644 --- a/code/modules/mob/living/carbon/alien/alien.dm +++ b/code/modules/mob/living/carbon/alien/alien.dm @@ -37,35 +37,22 @@ verbs += /mob/living/proc/mob_sleep verbs += /mob/living/proc/lay_down - internal_organs += new /obj/item/organ/brain/alien - internal_organs += new /obj/item/organ/alien/hivenode - internal_organs += new /obj/item/organ/tongue/alien + create_bodyparts() //initialize bodyparts - for(var/obj/item/organ/I in internal_organs) - I.Insert(src) + create_internal_organs() AddAbility(new/obj/effect/proc_holder/alien/nightvisiontoggle(null)) ..() +/mob/living/carbon/alien/create_internal_organs() + internal_organs += new /obj/item/organ/brain/alien + internal_organs += new /obj/item/organ/alien/hivenode + internal_organs += new /obj/item/organ/tongue/alien + ..() + /mob/living/carbon/alien/assess_threat() // beepsky won't hunt aliums return -10 -/mob/living/carbon/alien/adjustToxLoss(amount) - return 0 - -/mob/living/carbon/alien/adjustFireLoss(amount) // Weak to Fire - if(amount > 0) - ..(amount * 2) - else - ..(amount) - return - -/mob/living/carbon/alien/check_eye_prot() - return ..() + 2 - -/mob/living/carbon/alien/getToxLoss() - return 0 - /mob/living/carbon/alien/handle_environment(datum/gas_mixture/environment) if(!environment) return @@ -100,35 +87,6 @@ else clear_alert("alien_fire") - -/mob/living/carbon/alien/ex_act(severity, target) - ..() - - switch (severity) - if (1) - gib() - return - - if (2) - adjustBruteLoss(60) - adjustFireLoss(60) - adjustEarDamage(30,120) - - if(3) - adjustBruteLoss(30) - if (prob(50)) - Paralyse(1) - adjustEarDamage(15,60) - - updatehealth() - - -/mob/living/carbon/alien/handle_fire()//Aliens on fire code - if(..()) - return - bodytemperature += BODYTEMP_HEATING_MAX //If you're on fire, you heat up! - return - /mob/living/carbon/alien/reagent_check(datum/reagent/R) //can metabolize all reagents return 0 diff --git a/code/modules/mob/living/carbon/alien/alien_defense.dm b/code/modules/mob/living/carbon/alien/alien_defense.dm index d9f5ef6fa98e..0d934446366d 100644 --- a/code/modules/mob/living/carbon/alien/alien_defense.dm +++ b/code/modules/mob/living/carbon/alien/alien_defense.dm @@ -1,3 +1,10 @@ + +/mob/living/carbon/alien/get_eye_protection() + return ..() + 2 //potential cyber implants + natural eye protection + +/mob/living/carbon/alien/get_ear_protection() + return 2 //no ears + /mob/living/carbon/alien/hitby(atom/movable/AM, skipcatch, hitpush) ..(AM, skipcatch = 1, hitpush = 0) @@ -40,7 +47,6 @@ In all, this is a lot like the monkey code. /N updatehealth() else M << "[name] is too injured for that." - return /mob/living/carbon/alien/attack_larva(mob/living/carbon/alien/larva/L) @@ -65,9 +71,10 @@ In all, this is a lot like the monkey code. /N /mob/living/carbon/alien/attack_paw(mob/living/carbon/monkey/M) if(..()) if (stat != DEAD) - adjustBruteLoss(rand(1, 3)) - updatehealth() - return + var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected)) + apply_damage(rand(1, 3), BRUTE, affecting) + + /mob/living/carbon/alien/attack_animal(mob/living/simple_animal/M) @@ -96,3 +103,22 @@ In all, this is a lot like the monkey code. /N adjustBruteLoss(damage) add_logs(M, src, "attacked") updatehealth() + +/mob/living/carbon/alien/ex_act(severity, target) + ..() + switch (severity) + if (1) + gib() + + if (2) + take_overall_damage(60, 60) + adjustEarDamage(30,120) + + if(3) + take_overall_damage(30,0) + if(prob(50)) + Paralyse(1) + adjustEarDamage(15,60) + +/mob/living/carbon/alien/soundbang_act(intensity = 1, stun_pwr = 1, damage_pwr = 5, deafen_pwr = 15) + return 0 \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/damage_procs.dm b/code/modules/mob/living/carbon/alien/damage_procs.dm new file mode 100644 index 000000000000..7857c0b565e6 --- /dev/null +++ b/code/modules/mob/living/carbon/alien/damage_procs.dm @@ -0,0 +1,22 @@ + + +/mob/living/carbon/alien/getToxLoss() + return 0 + +/mob/living/carbon/alien/adjustToxLoss(amount) //alien immune to tox damage + return 0 + +/mob/living/carbon/alien/adjustFireLoss(amount) // Weak to Fire + if(amount > 0) + ..(amount * 2) + else + ..(amount) + + + +//aliens are immune to stamina damage. +/mob/living/carbon/alien/adjustStaminaLoss(amount, updating_stamina = 1) + return + +/mob/living/carbon/alien/setStaminaLoss(amount, updating_stamina = 1) + return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/death.dm b/code/modules/mob/living/carbon/alien/death.dm index 7583d0afaa7a..6211dc834936 100644 --- a/code/modules/mob/living/carbon/alien/death.dm +++ b/code/modules/mob/living/carbon/alien/death.dm @@ -1,5 +1,8 @@ -/mob/living/carbon/alien/spawn_gibs() - xgibs(loc, viruses) +/mob/living/carbon/alien/spawn_gibs(with_bodyparts) + if(with_bodyparts) + new /obj/effect/gibspawner/xeno(loc,viruses) + else + new /obj/effect/gibspawner/xenobodypartless(loc,viruses) /mob/living/carbon/alien/gib_animation() PoolOrNew(/obj/effect/overlay/temp/gib_animation, list(loc, "gibbed-a")) diff --git a/code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm b/code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm index 8e078e4ed7c2..5f0dbd5635ed 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm @@ -7,11 +7,14 @@ /mob/living/carbon/alien/humanoid/drone/New() + AddAbility(new/obj/effect/proc_holder/alien/evolve(null)) + ..() + + +/mob/living/carbon/alien/humanoid/drone/create_internal_organs() internal_organs += new /obj/item/organ/alien/plasmavessel/large internal_organs += new /obj/item/organ/alien/resinspinner internal_organs += new /obj/item/organ/alien/acid - - AddAbility(new/obj/effect/proc_holder/alien/evolve(null)) ..() /mob/living/carbon/alien/humanoid/drone/movement_delay() diff --git a/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm b/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm index 379500f5002e..3a9e938df390 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm @@ -6,7 +6,7 @@ icon_state = "alienh_s" var/obj/screen/leap_icon = null -/mob/living/carbon/alien/humanoid/hunter/New() +/mob/living/carbon/alien/humanoid/hunter/create_internal_organs() internal_organs += new /obj/item/organ/alien/plasmavessel/small ..() diff --git a/code/modules/mob/living/carbon/alien/humanoid/caste/praetorian.dm b/code/modules/mob/living/carbon/alien/humanoid/caste/praetorian.dm index 8da5304ff77b..d16c06bea538 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/caste/praetorian.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/caste/praetorian.dm @@ -11,14 +11,18 @@ real_name = name + AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/repulse/xeno(src)) + AddAbility(new /obj/effect/proc_holder/alien/royal/praetorian/evolve()) + ..() + +/mob/living/carbon/alien/humanoid/royal/praetorian/create_internal_organs() internal_organs += new /obj/item/organ/alien/plasmavessel/large internal_organs += new /obj/item/organ/alien/resinspinner internal_organs += new /obj/item/organ/alien/acid internal_organs += new /obj/item/organ/alien/neurotoxin - AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/repulse/xeno(src)) - AddAbility(new /obj/effect/proc_holder/alien/royal/praetorian/evolve()) ..() + /mob/living/carbon/alien/humanoid/royal/praetorian/movement_delay() . = ..() . += 1 diff --git a/code/modules/mob/living/carbon/alien/humanoid/caste/sentinel.dm b/code/modules/mob/living/carbon/alien/humanoid/caste/sentinel.dm index a22ab106dd4e..dacd4ff7d4a7 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/caste/sentinel.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/caste/sentinel.dm @@ -7,11 +7,15 @@ /mob/living/carbon/alien/humanoid/sentinel/New() - internal_organs += new /obj/item/organ/alien/plasmavessel - internal_organs += new /obj/item/organ/alien/acid - internal_organs += new /obj/item/organ/alien/neurotoxin AddAbility(new /obj/effect/proc_holder/alien/sneak) ..() +/mob/living/carbon/alien/humanoid/sentinel/create_internal_organs() + internal_organs += new /obj/item/organ/alien/plasmavessel + internal_organs += new /obj/item/organ/alien/acid + internal_organs += new /obj/item/organ/alien/neurotoxin + ..() + + /mob/living/carbon/alien/humanoid/sentinel/movement_delay() . = ..() diff --git a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm index 89acb9ab91c2..98c1df7b382a 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm @@ -15,75 +15,19 @@ var/custom_pixel_y_offset = 0 var/sneaking = 0 //For sneaky-sneaky mode and appropriate slowdown var/drooling = 0 //For Neruotoxic spit overlays + bodyparts = list(/obj/item/bodypart/chest/alien, /obj/item/bodypart/head/alien, /obj/item/bodypart/l_arm/alien, + /obj/item/bodypart/r_arm/alien, /obj/item/bodypart/r_leg/alien, /obj/item/bodypart/l_leg/alien) + //This is fine right now, if we're adding organ specific damage this needs to be updated /mob/living/carbon/alien/humanoid/New() AddAbility(new/obj/effect/proc_holder/alien/regurgitate(null)) ..() - /mob/living/carbon/alien/humanoid/movement_delay() . = ..() . += move_delay_add + config.alien_delay + sneaking //move_delay_add is used to slow aliens with stuns -/mob/living/carbon/alien/humanoid/emp_act(severity) - if(r_store) r_store.emp_act(severity) - if(l_store) l_store.emp_act(severity) - ..() - -/mob/living/carbon/alien/humanoid/attack_hulk(mob/living/carbon/human/user) - if(user.a_intent == "harm") - ..(user, 1) - adjustBruteLoss(15) - var/hitverb = "punched" - if(mob_size < MOB_SIZE_LARGE) - step_away(src,user,15) - sleep(1) - step_away(src,user,15) - hitverb = "slammed" - playsound(loc, "punch", 25, 1, -1) - visible_message("[user] has [hitverb] [src]!", \ - "[user] has [hitverb] [src]!") - return 1 - -/mob/living/carbon/alien/humanoid/attack_hand(mob/living/carbon/human/M) - if(..()) - switch(M.a_intent) - if ("harm") - var/damage = rand(1, 9) - if (prob(90)) - playsound(loc, "punch", 25, 1, -1) - visible_message("[M] has punched [src]!", \ - "[M] has punched [src]!") - if ((stat != DEAD) && (damage > 9 || prob(5)))//Regular humans have a very small chance of weakening an alien. - Paralyse(2) - visible_message("[M] has weakened [src]!", \ - "[M] has weakened [src]!") - adjustBruteLoss(damage) - add_logs(M, src, "attacked") - updatehealth() - else - playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) - visible_message("[M] has attempted to punch [src]!") - - if ("disarm") - if (!lying) - if (prob(5)) - Paralyse(2) - playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - add_logs(M, src, "pushed") - visible_message("[M] has pushed down [src]!", \ - "[M] has pushed down [src]!") - else - if (prob(50)) - drop_item() - playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - visible_message("[M] has disarmed [src]!", \ - "[M] has disarmed [src]!") - else - playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) - visible_message("[M] has attempted to disarm [src]!") - /mob/living/carbon/alien/humanoid/restrained(ignore_grab) . = handcuffed @@ -150,9 +94,6 @@ else return initial(pixel_x) -/mob/living/carbon/alien/humanoid/check_ear_prot() - return 1 - /mob/living/carbon/alien/humanoid/get_permeability_protection() return 0.8 @@ -179,9 +120,3 @@ proc/get_alien_type(var/alienpath) if(breath && breath.total_moles() > 0 && !sneaking) playsound(get_turf(src), pick('sound/voice/lowHiss2.ogg', 'sound/voice/lowHiss3.ogg', 'sound/voice/lowHiss4.ogg'), 50, 0, -5) ..() - -/mob/living/carbon/alien/humanoid/grabbedby(mob/living/carbon/user, supress_message = 0) - if(user == src && pulling && grab_state >= GRAB_AGGRESSIVE && !pulling.anchored && iscarbon(pulling)) - devour_mob(pulling, devour_time = 60) - else - ..() \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/humanoid/humanoid_defense.dm b/code/modules/mob/living/carbon/alien/humanoid/humanoid_defense.dm new file mode 100644 index 000000000000..4f08997c40fa --- /dev/null +++ b/code/modules/mob/living/carbon/alien/humanoid/humanoid_defense.dm @@ -0,0 +1,59 @@ + +/mob/living/carbon/alien/humanoid/grabbedby(mob/living/carbon/user, supress_message = 0) + if(user == src && pulling && grab_state >= GRAB_AGGRESSIVE && !pulling.anchored && iscarbon(pulling)) + devour_mob(pulling, devour_time = 60) + else + ..() + +/mob/living/carbon/alien/humanoid/attack_hulk(mob/living/carbon/human/user) + if(user.a_intent == "harm") + ..(user, 1) + adjustBruteLoss(15) + var/hitverb = "punched" + if(mob_size < MOB_SIZE_LARGE) + step_away(src,user,15) + sleep(1) + step_away(src,user,15) + hitverb = "slammed" + playsound(loc, "punch", 25, 1, -1) + visible_message("[user] has [hitverb] [src]!", \ + "[user] has [hitverb] [src]!") + return 1 + +/mob/living/carbon/alien/humanoid/attack_hand(mob/living/carbon/human/M) + if(..()) + switch(M.a_intent) + if ("harm") + var/damage = rand(1, 9) + if (prob(90)) + playsound(loc, "punch", 25, 1, -1) + visible_message("[M] has punched [src]!", \ + "[M] has punched [src]!") + if ((stat != DEAD) && (damage > 9 || prob(5)))//Regular humans have a very small chance of weakening an alien. + Paralyse(2) + visible_message("[M] has weakened [src]!", \ + "[M] has weakened [src]!") + var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected)) + apply_damage(damage, BRUTE, affecting) + add_logs(M, src, "attacked") + else + playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) + visible_message("[M] has attempted to punch [src]!") + + if ("disarm") + if (!lying) + if (prob(5)) + Paralyse(2) + playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + add_logs(M, src, "pushed") + visible_message("[M] has pushed down [src]!", \ + "[M] has pushed down [src]!") + else + if (prob(50)) + drop_item() + playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + visible_message("[M] has disarmed [src]!", \ + "[M] has disarmed [src]!") + else + playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) + visible_message("[M] has attempted to disarm [src]!") diff --git a/code/modules/mob/living/carbon/alien/humanoid/queen.dm b/code/modules/mob/living/carbon/alien/humanoid/queen.dm index 5f48d88c55d2..5559ebffe016 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/queen.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/queen.dm @@ -57,14 +57,17 @@ real_name = src.name + AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/repulse/xeno(src)) + AddAbility(new/obj/effect/proc_holder/alien/royal/queen/promote()) + smallsprite.Grant(src) + ..() + +/mob/living/carbon/alien/humanoid/royal/queen/create_internal_organs() internal_organs += new /obj/item/organ/alien/plasmavessel/large/queen internal_organs += new /obj/item/organ/alien/resinspinner internal_organs += new /obj/item/organ/alien/acid internal_organs += new /obj/item/organ/alien/neurotoxin internal_organs += new /obj/item/organ/alien/eggsac - AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/repulse/xeno(src)) - AddAbility(new/obj/effect/proc_holder/alien/royal/queen/promote()) - smallsprite.Grant(src) ..() /mob/living/carbon/alien/humanoid/royal/queen/movement_delay() diff --git a/code/modules/mob/living/carbon/alien/larva/death.dm b/code/modules/mob/living/carbon/alien/larva/death.dm index 136572fb5c51..43a2f196255e 100644 --- a/code/modules/mob/living/carbon/alien/larva/death.dm +++ b/code/modules/mob/living/carbon/alien/larva/death.dm @@ -8,3 +8,18 @@ visible_message("[src] lets out a waning high-pitched cry.") return ..(gibbed) + +/mob/living/carbon/alien/larva/spawn_gibs(with_bodyparts) + if(with_bodyparts) + new /obj/effect/gibspawner/larva(loc,viruses) + else + new /obj/effect/gibspawner/larvabodypartless(loc,viruses) + +/mob/living/carbon/alien/larva/gib_animation() + PoolOrNew(/obj/effect/overlay/temp/gib_animation, list(loc, "gibbed-l")) + +/mob/living/carbon/alien/larva/spawn_dust() + new /obj/effect/decal/remains/xeno(loc) + +/mob/living/carbon/alien/larva/dust_animation() + PoolOrNew(/obj/effect/overlay/temp/dust_animation, list(loc, "dust-l")) diff --git a/code/modules/mob/living/carbon/alien/larva/larva.dm b/code/modules/mob/living/carbon/alien/larva/larva.dm index 887cf139996e..f6ceff4774a2 100644 --- a/code/modules/mob/living/carbon/alien/larva/larva.dm +++ b/code/modules/mob/living/carbon/alien/larva/larva.dm @@ -14,16 +14,20 @@ var/time_of_birth rotate_on_lying = 0 + bodyparts = list(/obj/item/bodypart/chest/larva, /obj/item/bodypart/head/larva) + //This is fine right now, if we're adding organ specific damage this needs to be updated /mob/living/carbon/alien/larva/New() - regenerate_icons() - internal_organs += new /obj/item/organ/alien/plasmavessel/small/tiny AddAbility(new/obj/effect/proc_holder/alien/hide(null)) AddAbility(new/obj/effect/proc_holder/alien/larva_evolve(null)) ..() +/mob/living/carbon/alien/larva/create_internal_organs() + internal_organs += new /obj/item/organ/alien/plasmavessel/small/tiny + ..() + //This needs to be fixed /mob/living/carbon/alien/larva/Stat() ..() @@ -39,36 +43,6 @@ /mob/living/carbon/alien/larva/attack_ui(slot_id) return -/mob/living/carbon/alien/larva/attack_hulk(mob/living/carbon/human/user) - if(user.a_intent == "harm") - ..(user, 1) - adjustBruteLoss(5 + rand(1,9)) - spawn() - step_away(src,user,15) - sleep(1) - step_away(src,user,15) - return 1 - -/mob/living/carbon/alien/larva/attack_hand(mob/living/carbon/human/M) - if(..()) - var/damage = rand(1, 9) - if (prob(90)) - playsound(loc, "punch", 25, 1, -1) - add_logs(M, src, "attacked") - visible_message("[M] has kicked [src]!", \ - "[M] has kicked [src]!") - if ((stat != DEAD) && (damage > 4.9)) - Paralyse(rand(5,10)) - - adjustBruteLoss(damage) - updatehealth() - else - playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) - visible_message("[M] has attempted to kick [src]!", \ - "[M] has attempted to kick [src]!") - - return - /mob/living/carbon/alien/larva/restrained(ignore_grab) . = 0 diff --git a/code/modules/mob/living/carbon/alien/larva/larva_defense.dm b/code/modules/mob/living/carbon/alien/larva/larva_defense.dm new file mode 100644 index 000000000000..77bab6cdf040 --- /dev/null +++ b/code/modules/mob/living/carbon/alien/larva/larva_defense.dm @@ -0,0 +1,29 @@ + + +/mob/living/carbon/alien/larva/attack_hand(mob/living/carbon/human/M) + if(..()) + var/damage = rand(1, 9) + if (prob(90)) + playsound(loc, "punch", 25, 1, -1) + add_logs(M, src, "attacked") + visible_message("[M] has kicked [src]!", \ + "[M] has kicked [src]!") + if ((stat != DEAD) && (damage > 4.9)) + Paralyse(rand(5,10)) + + var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected)) + apply_damage(damage, BRUTE, affecting) + else + playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) + visible_message("[M] has attempted to kick [src]!", \ + "[M] has attempted to kick [src]!") + +/mob/living/carbon/alien/larva/attack_hulk(mob/living/carbon/human/user) + if(user.a_intent == "harm") + ..(user, 1) + adjustBruteLoss(5 + rand(1,9)) + spawn() + step_away(src,user,15) + sleep(1) + step_away(src,user,15) + return 1 \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/life.dm b/code/modules/mob/living/carbon/alien/life.dm index 91bddef2cde8..f0192cf2a96b 100644 --- a/code/modules/mob/living/carbon/alien/life.dm +++ b/code/modules/mob/living/carbon/alien/life.dm @@ -45,4 +45,10 @@ move_delay_add = max(0, move_delay_add - rand(1, 2)) /mob/living/carbon/alien/handle_changeling() + return + +/mob/living/carbon/alien/handle_fire()//Aliens on fire code + if(..()) + return + bodytemperature += BODYTEMP_HEATING_MAX //If you're on fire, you heat up! return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm index 9a531fdf956a..f2382721cff7 100644 --- a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm +++ b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm @@ -41,7 +41,7 @@ var/const/ALIEN_AFK_BRACKET = 450 // 45 seconds if(prob(4)) owner << "Your muscles ache." if(prob(20)) - owner.take_organ_damage(1) + owner.take_bodypart_damage(1) if(prob(4)) owner << "Your stomach hurts." if(prob(20)) diff --git a/code/modules/mob/living/carbon/alien/special/facehugger.dm b/code/modules/mob/living/carbon/alien/special/facehugger.dm index a1292a9c9ab5..95387d856910 100644 --- a/code/modules/mob/living/carbon/alien/special/facehugger.dm +++ b/code/modules/mob/living/carbon/alien/special/facehugger.dm @@ -68,7 +68,6 @@ var/const/MAX_ACTIVE_TIME = 400 /obj/item/clothing/mask/facehugger/bullet_act(obj/item/projectile/P) if(P.damage) Die() - return /obj/item/clothing/mask/facehugger/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) if(exposed_temperature > 300) @@ -124,7 +123,7 @@ var/const/MAX_ACTIVE_TIME = 400 return 0 if(stat != CONSCIOUS) return 0 - if(!sterile) M.take_organ_damage(strength,0) //done here so that even borgs and humans in helmets take damage + if(!sterile) M.take_bodypart_damage(strength,0) //done here so that even borgs and humans in helmets take damage M.visible_message("[src] leaps at [M]'s face!", \ "[src] leaps at [M]'s face!") if(ishuman(M)) @@ -180,7 +179,7 @@ var/const/MAX_ACTIVE_TIME = 400 icon_state = "[initial(icon_state)]_impregnated" var/obj/item/bodypart/chest/LC = target.get_bodypart("chest") - if((!LC || LC.status != ORGAN_ROBOTIC) && !target.getorgan(/obj/item/organ/body_egg/alien_embryo)) + if((!LC || LC.status != BODYPART_ROBOTIC) && !target.getorgan(/obj/item/organ/body_egg/alien_embryo)) new /obj/item/organ/body_egg/alien_embryo(target) if(iscorgi(target)) diff --git a/code/modules/mob/living/carbon/alien/update_icons.dm b/code/modules/mob/living/carbon/alien/update_icons.dm new file mode 100644 index 000000000000..ec3753e69790 --- /dev/null +++ b/code/modules/mob/living/carbon/alien/update_icons.dm @@ -0,0 +1,11 @@ + + + +/mob/living/carbon/alien/update_damage_overlays() //aliens don't have damage overlays. + return + +/mob/living/carbon/alien/update_body() // we don't use the bodyparts or body layers for aliens. + return + +/mob/living/carbon/alien/update_body_parts()//we don't use the bodyparts layer for aliens. + return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 8175cf4e862d..0198c4a1cf8f 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -3,10 +3,11 @@ /mob/living/carbon/New() create_reagents(1000) + update_body_parts() //to update the carbon's new bodyparts appearance ..() /mob/living/carbon/Destroy() - for(var/atom/movable/guts in internal_organs) + for(var/guts in internal_organs) qdel(guts) for(var/atom/movable/food in stomach_contents) qdel(food) @@ -28,16 +29,9 @@ var/obj/item/I = user.get_active_held_item() if(I && I.force) var/d = rand(round(I.force / 4), I.force) - if(istype(src, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = src - var/organ = H.get_bodypart("chest") - if (istype(organ, /obj/item/bodypart)) - var/obj/item/bodypart/temp = organ - if(temp.take_damage(d, 0)) - H.update_damage_overlays(0) - H.updatehealth() - else - src.take_organ_damage(d) + var/obj/item/bodypart/BP = get_bodypart("chest") + if(BP.take_damage(d, 0)) + update_damage_overlays() visible_message("[user] attacks [src]'s stomach wall with the [I.name]!", \ "[user] attacks your stomach wall with the [I.name]!") playsound(user.loc, 'sound/effects/attackblob.ogg', 50, 1) @@ -49,36 +43,6 @@ src.gib() -/mob/living/carbon/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, override = 0, tesla_shock = 0) - shock_damage *= siemens_coeff - if(dna && dna.species) - shock_damage *= dna.species.siemens_coeff - if(shock_damage<1 && !override) - return 0 - if(reagents.has_reagent("teslium")) - shock_damage *= 1.5 //If the mob has teslium in their body, shocks are 50% more damaging! - take_overall_damage(0,shock_damage) - visible_message( - "[src] was shocked by \the [source]!", \ - "You feel a powerful shock coursing through your body!", \ - "You hear a heavy electrical crack." \ - ) - jitteriness += 1000 //High numbers for violent convulsions - do_jitter_animation(jitteriness) - stuttering += 2 - if(!tesla_shock || (tesla_shock && siemens_coeff > 0.5)) - Stun(2) - spawn(20) - jitteriness = max(jitteriness - 990, 10) //Still jittery, but vastly less - if(!tesla_shock || (tesla_shock && siemens_coeff > 0.5)) - Stun(3) - Weaken(3) - if(override) - return override - else - return shock_damage - - /mob/living/carbon/swap_hand(held_index) if(!held_index) held_index = (active_hand_index % held_items.len)+1 @@ -117,73 +81,27 @@ else mode() // Activate held item -/mob/living/carbon/proc/help_shake_act(mob/living/carbon/M) - if(on_fire) - M << "You can't put them out with just your bare hands!" - return +/mob/living/carbon/attackby(obj/item/I, mob/user, params) + if(lying && surgeries.len) + if(user != src && user.a_intent == "help") + for(var/datum/surgery/S in surgeries) + if(S.next_step(user)) + return 1 + return ..() - if(health >= 0 && !(status_flags & FAKEDEATH)) - - if(lying) - M.visible_message("[M] shakes [src] trying to get them up!", \ - "You shake [src] trying to get them up!") - else - M.visible_message("[M] hugs [src] to make them feel better!", \ - "You hug [src] to make them feel better!") - AdjustSleeping(-5) - AdjustParalysis(-3) - AdjustStunned(-3) - AdjustWeakened(-3) - if(resting) - resting = 0 - update_canmove() - - playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - -/mob/living/carbon/flash_eyes(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0) +/mob/living/carbon/throw_impact(atom/hit_atom) . = ..() - - var/damage = intensity - check_eye_prot() - if(.) // we've been flashed - if(visual) - return - if(weakeyes) - Stun(2) - - if (damage == 1) - src << "Your eyes sting a little." - if(prob(40)) - adjust_eye_damage(1) - - else if (damage == 2) - src << "Your eyes burn." - adjust_eye_damage(rand(2, 4)) - - else if( damage > 3) - src << "Your eyes itch and burn severely!" - adjust_eye_damage(rand(12, 16)) - - if(eye_damage > 10) - blind_eyes(damage) - blur_eyes(damage * rand(3, 6)) - - if(eye_damage > 20) - if(prob(eye_damage - 20)) - if(become_nearsighted()) - src << "Your eyes start to burn badly!" - else if(prob(eye_damage - 25)) - if(become_blind()) - src << "You can't see anything!" - else - src << "Your eyes are really starting to hurt. This can't be good for you!" - if(has_bane(BANE_LIGHT)) - mind.disrupt_spells(-500) - return 1 - else if(damage == 0) // just enough protection - if(prob(20)) - src << "Something bright flashes in the corner of your vision!" - if(has_bane(BANE_LIGHT)) - mind.disrupt_spells(0) + if(hit_atom.density && isturf(hit_atom)) + Weaken(1) + take_bodypart_damage(10) + if(iscarbon(hit_atom)) + var/mob/living/carbon/victim = hit_atom + victim.Weaken(1) + Weaken(1) + victim.take_bodypart_damage(10) + take_bodypart_damage(10) + visible_message("[src] crashes into [victim], knocking them both over!", "You violently crash into [victim]!") + playsound(src,'sound/weapons/punch1.ogg',50,1) //Throwing stuff @@ -308,13 +226,6 @@ /mob/living/carbon/is_muzzled() return(istype(src.wear_mask, /obj/item/clothing/mask/muzzle)) -/mob/living/carbon/blob_act(obj/effect/blob/B) - if (stat == DEAD) - return - else - show_message("The blob attacks!") - adjustBruteLoss(10) - /mob/living/carbon/proc/spin(spintime, speed) set waitfor = 0 var/D = dir @@ -467,10 +378,6 @@ else return initial(pixel_y) -/mob/living/carbon/check_ear_prot() - if(head && (head.flags & HEADBANGPROTECT)) - return 1 - /mob/living/carbon/proc/accident(obj/item/I) if(!I || (I.flags & (NODROP|ABSTRACT))) return @@ -499,17 +406,6 @@ var/turf/target = get_turf(loc) I.throw_at(target,I.throw_range,I.throw_speed,src) -/mob/living/carbon/emp_act(severity) - for(var/obj/item/organ/O in internal_organs) - O.emp_act(severity) - ..() - -/mob/living/carbon/check_eye_prot() - var/number = ..() - for(var/obj/item/organ/cyberimp/eyes/EFP in internal_organs) - number += EFP.flash_protect - return number - /mob/living/carbon/proc/AddAbility(obj/effect/proc_holder/alien/A) abilities.Add(A) A.on_gain(src) @@ -538,6 +434,11 @@ add_abilities_to_panel() +/mob/living/carbon/attack_ui(slot) + if(!has_hand_for_held_index(active_hand_index)) + return 0 + return ..() + /mob/living/carbon/proc/vomit(var/lost_nutrition = 10, var/blood = 0, var/stun = 1, var/distance = 0, var/message = 1, var/toxic = 0) if(nutrition < 100 && !blood) if(message) @@ -578,12 +479,29 @@ return 1 - /mob/living/carbon/fully_replace_character_name(oldname,newname) ..() if(dna) dna.real_name = real_name +//Updates the mob's health from bodyparts and mob damage variables +/mob/living/carbon/updatehealth() + if(status_flags & GODMODE) + return + var/total_burn = 0 + var/total_brute = 0 + for(var/X in bodyparts) //hardcoded to streamline things a bit + var/obj/item/bodypart/BP = X + total_brute += BP.brute_dam + total_burn += BP.burn_dam + health = maxHealth - getOxyLoss() - getToxLoss() - getCloneLoss() - total_burn - total_brute + update_stat() + if(((maxHealth - total_burn) < HEALTH_THRESHOLD_DEAD) && stat == DEAD ) + become_husk() + if(on_fire) + shred_clothing() + med_hud_set_health() + /mob/living/carbon/update_sight() if(!client) return @@ -756,6 +674,7 @@ for(var/datum/disease/D in viruses) D.cure(0) if(admin_revive) + regenerate_limbs() handcuffed = initial(handcuffed) for(var/obj/item/weapon/restraints/R in contents) //actually remove cuffs from inventory qdel(R) @@ -773,7 +692,8 @@ if(qdeleted(src)) return var/organs_amt = 0 - for(var/obj/item/organ/O in internal_organs) + for(var/X in internal_organs) + var/obj/item/organ/O = X if(prob(50)) organs_amt++ O.Remove(src) @@ -783,15 +703,6 @@ ..() -/mob/living/carbon/adjustToxLoss(amount, updating_health=1) - if(has_dna() && TOXINLOVER in dna.species.specflags) //damage becomes healing and healing becomes damage - amount = -amount - if(amount > 0) - blood_volume -= 5*amount - else - blood_volume -= amount - return ..() - /mob/living/carbon/fakefire(var/fire_icon = "Generic_mob_burning") overlays_standing[FIRE_LAYER] = image("icon"='icons/mob/OnFire.dmi', "icon_state"= fire_icon, "layer"=-FIRE_LAYER) apply_overlay(FIRE_LAYER) @@ -799,3 +710,34 @@ /mob/living/carbon/fakefireextinguish() remove_overlay(FIRE_LAYER) + +/mob/living/carbon/proc/devour_mob(mob/living/carbon/C, devour_time = 130) + C.visible_message("[src] is attempting to devour [C]!", \ + "[src] is attempting to devour you!") + if(!do_mob(src, C, devour_time)) + return + if(pulling && pulling == C && grab_state >= GRAB_AGGRESSIVE && a_intent == "grab") + C.visible_message("[src] devours [C]!", \ + "[src] devours you!") + C.forceMove(src) + stomach_contents.Add(C) + add_logs(src, C, "devoured") + +/mob/living/carbon/proc/create_bodyparts() + for(var/X in bodyparts) + var/obj/item/bodypart/O = new X() + O.owner = src + bodyparts.Remove(X) + bodyparts.Add(O) + if(O.body_part == ARM_LEFT) + O.held_index = 1 + hand_bodyparts += O + else if(O.body_part == ARM_RIGHT) + O.held_index = 2 + hand_bodyparts += O + + +/mob/living/carbon/proc/create_internal_organs() + for(var/X in internal_organs) + var/obj/item/organ/I = X + I.Insert(src) diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index 6a82174e41ec..4de7733bd266 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -1,3 +1,19 @@ + +/mob/living/carbon/get_eye_protection() + var/number = ..() + for(var/obj/item/organ/cyberimp/eyes/EFP in internal_organs) + number += EFP.flash_protect + return number + +/mob/living/carbon/get_ear_protection() + if(head && (head.flags & HEADBANGPROTECT)) + return 1 + +/mob/living/carbon/check_projectile_dismemberment(obj/item/projectile/P, def_zone) + var/obj/item/bodypart/affecting = get_bodypart(def_zone) + if(affecting && affecting.dismemberable && affecting.get_damage() >= (affecting.max_damage - P.dismemberment)) + affecting.dismember(P.damtype) + /mob/living/carbon/hitby(atom/movable/AM, skipcatch, hitpush = 1, blocked = 0) if(!skipcatch) //ugly, but easy if(in_throw_mode && !get_active_held_item()) //empty active hand and we're in throw mode @@ -11,32 +27,42 @@ return 1 ..() -/mob/living/carbon/throw_impact(atom/hit_atom) - . = ..() - if(hit_atom.density && isturf(hit_atom)) - Weaken(1) - take_organ_damage(10) - if(iscarbon(hit_atom)) - var/mob/living/carbon/victim = hit_atom - victim.Weaken(1) - Weaken(1) - victim.take_organ_damage(10) - take_organ_damage(10) - visible_message("[src] crashes into [victim], knocking them both over!", "You violently crash into [victim]!") - playsound(src,'sound/weapons/punch1.ogg',50,1) -/mob/living/carbon/attackby(obj/item/I, mob/user, params) - if(lying && surgeries.len) - if(user != src && user.a_intent == "help") - for(var/datum/surgery/S in surgeries) - if(S.next_step(user)) - return 1 - return ..() +/mob/living/carbon/attacked_by(obj/item/I, mob/living/user) + var/obj/item/bodypart/affecting = get_bodypart(ran_zone(user.zone_selected)) + if(!affecting) //missing limb? we select the first bodypart (you can never have zero, because of chest) + affecting = bodyparts[1] + send_item_attack_message(I, user, affecting.name) + if(I.force) + apply_damage(I.force, I.damtype, affecting) + if(I.damtype == BRUTE && affecting.status == BODYPART_ORGANIC) + if(prob(33)) + I.add_mob_blood(src) + var/turf/location = get_turf(src) + add_splatter_floor(location) + if(get_dist(user, src) <= 1) //people with TK won't get smeared with blood + user.add_mob_blood(src) + if(affecting.body_zone == "head") + if(wear_mask) + wear_mask.add_mob_blood(src) + update_inv_wear_mask() + if(head) + head.add_mob_blood(src) + update_inv_head() + + //dismemberment + var/probability = I.get_dismemberment_chance(affecting) + if(prob(probability)) + if(affecting.dismember(I.damtype)) + I.add_mob_blood(src) + playsound(get_turf(src), I.get_dismember_sound(), 80, 1) + return TRUE //successful attack + +/mob/living/carbon/attack_drone(mob/living/simple_animal/drone/user) + return //so we don't call the carbon's attack_hand(). /mob/living/carbon/attack_hand(mob/living/carbon/human/user) - if(!iscarbon(user)) - return for(var/datum/disease/D in viruses) if(D.IsSpreadByTouch()) @@ -55,9 +81,6 @@ /mob/living/carbon/attack_paw(mob/living/carbon/monkey/M) - if(!istype(M, /mob/living/carbon)) - return 0 - for(var/datum/disease/D in viruses) if(D.IsSpreadByTouch()) M.ContractDisease(D) @@ -101,20 +124,8 @@ updatehealth() return 1 -/mob/living/carbon/proc/devour_mob(mob/living/carbon/C, devour_time = 130) - C.visible_message("[src] is attempting to devour [C]!", \ - "[src] is attempting to devour you!") - if(!do_mob(src, C, devour_time)) - return - if(pulling && pulling == C && grab_state >= GRAB_AGGRESSIVE && a_intent == "grab") - C.visible_message("[src] devours [C]!", \ - "[src] devours you!") - C.forceMove(src) - stomach_contents.Add(C) - add_logs(src, C, "devoured") - /mob/living/carbon/proc/dismembering_strike(mob/living/attacker, dam_zone) - if(!attacker.limb_destroyer || !has_limbs) + if(!attacker.limb_destroyer) return dam_zone var/obj/item/bodypart/affecting if(dam_zone && attacker.client) @@ -134,3 +145,136 @@ return null return affecting.body_zone return dam_zone + + +/mob/living/carbon/blob_act(obj/effect/blob/B) + if (stat == DEAD) + return + else + show_message("The blob attacks!") + adjustBruteLoss(10) + +/mob/living/carbon/emp_act(severity) + for(var/X in internal_organs) + var/obj/item/organ/O = X + O.emp_act(severity) + ..() + +/mob/living/carbon/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, override = 0, tesla_shock = 0) + shock_damage *= siemens_coeff + if(dna && dna.species) + shock_damage *= dna.species.siemens_coeff + if(shock_damage<1 && !override) + return 0 + if(reagents.has_reagent("teslium")) + shock_damage *= 1.5 //If the mob has teslium in their body, shocks are 50% more damaging! + take_overall_damage(0,shock_damage) + visible_message( + "[src] was shocked by \the [source]!", \ + "You feel a powerful shock coursing through your body!", \ + "You hear a heavy electrical crack." \ + ) + jitteriness += 1000 //High numbers for violent convulsions + do_jitter_animation(jitteriness) + stuttering += 2 + if(!tesla_shock || (tesla_shock && siemens_coeff > 0.5)) + Stun(2) + spawn(20) + jitteriness = max(jitteriness - 990, 10) //Still jittery, but vastly less + if(!tesla_shock || (tesla_shock && siemens_coeff > 0.5)) + Stun(3) + Weaken(3) + if(override) + return override + else + return shock_damage + +/mob/living/carbon/proc/help_shake_act(mob/living/carbon/M) + if(on_fire) + M << "You can't put them out with just your bare hands!" + return + + if(health >= 0 && !(status_flags & FAKEDEATH)) + + if(lying) + M.visible_message("[M] shakes [src] trying to get them up!", \ + "You shake [src] trying to get them up!") + else + M.visible_message("[M] hugs [src] to make them feel better!", \ + "You hug [src] to make them feel better!") + AdjustSleeping(-5) + AdjustParalysis(-3) + AdjustStunned(-3) + AdjustWeakened(-3) + if(resting) + resting = 0 + update_canmove() + + playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + + +/mob/living/carbon/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0) + . = ..() + + var/damage = intensity - get_eye_protection() + if(.) // we've been flashed + if(visual) + return + if(weakeyes) + Stun(2) + + if (damage == 1) + src << "Your eyes sting a little." + if(prob(40)) + adjust_eye_damage(1) + + else if (damage == 2) + src << "Your eyes burn." + adjust_eye_damage(rand(2, 4)) + + else if( damage > 3) + src << "Your eyes itch and burn severely!" + adjust_eye_damage(rand(12, 16)) + + if(eye_damage > 10) + blind_eyes(damage) + blur_eyes(damage * rand(3, 6)) + + if(eye_damage > 20) + if(prob(eye_damage - 20)) + if(become_nearsighted()) + src << "Your eyes start to burn badly!" + else if(prob(eye_damage - 25)) + if(become_blind()) + src << "You can't see anything!" + else + src << "Your eyes are really starting to hurt. This can't be good for you!" + if(has_bane(BANE_LIGHT)) + mind.disrupt_spells(-500) + return 1 + else if(damage == 0) // just enough protection + if(prob(20)) + src << "Something bright flashes in the corner of your vision!" + if(has_bane(BANE_LIGHT)) + mind.disrupt_spells(0) + + +/mob/living/carbon/soundbang_act(intensity = 1, stun_pwr = 1, damage_pwr = 5, deafen_pwr = 15) + var/ear_safety = get_ear_protection() + if(ear_safety < 2) //has ears + var/effect_amount = intensity - ear_safety + if(effect_amount > 0) + if(stun_pwr) + Stun(stun_pwr*effect_amount) + Weaken(stun_pwr*effect_amount) + if(deafen_pwr || damage_pwr) + setEarDamage(ear_damage + damage_pwr*effect_amount, max(ear_deaf, deafen_pwr*effect_amount)) + if (ear_damage >= 15) + src << "Your ears start to ring badly!" + if(prob(ear_damage - 5)) + src << "You can't hear anything!" + disabilities |= DEAF + else if(ear_damage >= 5) + src << "Your ears start to ring!" + src << sound('sound/weapons/flash_ring.ogg',0,1,0,250) + return effect_amount //how soundbanged we are diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm index 103fcbe50d70..f73ad1053c12 100644 --- a/code/modules/mob/living/carbon/carbon_defines.dm +++ b/code/modules/mob/living/carbon/carbon_defines.dm @@ -16,6 +16,11 @@ var/obj/item/weapon/tank/internal = null var/obj/item/head = null + var/obj/item/gloves = null //only used by humans + var/obj/item/shoes = null //only used by humans. + var/obj/item/clothing/glasses/glasses = null //only used by humans. + var/obj/item/ears = null //only used by humans. + var/datum/dna/dna = null//Carbon var/failed_last_breath = 0 //This is used to determine if the mob failed a breath. If they did fail a brath, they will attempt to breathe each tick, otherwise just once per 4 ticks. @@ -32,4 +37,8 @@ var/tinttotal = 0 // Total level of visualy impairing items - var/list/bodyparts = list() //Gets filled up in the constructor (New() proc in human.dm and monkey.dm) + var/list/bodyparts = list(/obj/item/bodypart/chest, /obj/item/bodypart/head, /obj/item/bodypart/l_arm, + /obj/item/bodypart/r_arm, /obj/item/bodypart/r_leg, /obj/item/bodypart/l_leg) + //Gets filled up in create_bodyparts() + + var/list/hand_bodyparts = list() //a collection of arms (or actually whatever the fug /bodyparts you monsters use to wreck my systems) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/carbon_movement.dm b/code/modules/mob/living/carbon/carbon_movement.dm index 479e9459c5c1..6b2e19c19592 100644 --- a/code/modules/mob/living/carbon/carbon_movement.dm +++ b/code/modules/mob/living/carbon/carbon_movement.dm @@ -1,6 +1,13 @@ /mob/living/carbon/movement_delay() . = ..() - . += grab_state * 3 + . += grab_state * 3 //can't go fast while grabbing something. + + if(!get_leg_ignore()) //ignore the fact we lack legs + var/leg_amount = get_num_legs() + . += 6 - 3*leg_amount //the fewer the legs, the slower the mob + if(!leg_amount) + . += 6 - 3*get_num_arms() //crawling is harder with fewer arms + if(legcuffed) . += legcuffed.slowdown diff --git a/code/modules/mob/living/carbon/damage_procs.dm b/code/modules/mob/living/carbon/damage_procs.dm new file mode 100644 index 000000000000..6da20373f62c --- /dev/null +++ b/code/modules/mob/living/carbon/damage_procs.dm @@ -0,0 +1,191 @@ + + +/mob/living/carbon/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked = 0) + var/hit_percent = (100-blocked)/100 + if(!damage || hit_percent <= 0) + return 0 + + var/obj/item/bodypart/BP = null + if(islimb(def_zone)) //we specified a bodypart object + BP = def_zone + else + if(!def_zone) + def_zone = ran_zone(def_zone) + BP = get_bodypart(check_zone(def_zone)) + if(!BP) + BP = bodyparts[1] + + switch(damagetype) + if(BRUTE) + if(BP) + if(BP.take_damage(damage * hit_percent, 0)) + update_damage_overlays() + else //no bodypart, we deal damage with a more general method. + adjustBruteLoss(damage * hit_percent) + if(BURN) + if(BP) + if(BP.take_damage(0, damage * hit_percent)) + update_damage_overlays() + else + adjustFireLoss(damage * hit_percent) + if(TOX) + adjustToxLoss(damage * hit_percent) + if(OXY) + adjustOxyLoss(damage * hit_percent) + if(CLONE) + adjustCloneLoss(damage * hit_percent) + if(STAMINA) + adjustStaminaLoss(damage * hit_percent) + return 1 + + +//These procs fetch a cumulative total damage from all bodyparts +/mob/living/carbon/getBruteLoss() + var/amount = 0 + for(var/X in bodyparts) + var/obj/item/bodypart/BP = X + amount += BP.brute_dam + return amount + +/mob/living/carbon/getFireLoss() + var/amount = 0 + for(var/X in bodyparts) + var/obj/item/bodypart/BP = X + amount += BP.burn_dam + return amount + + +/mob/living/carbon/adjustBruteLoss(amount, updating_health = 1) + if(status_flags & GODMODE) + return 0 + if(amount > 0) + take_overall_damage(amount, 0) + else + heal_overall_damage(-amount, 0, 0, 1, updating_health) + +/mob/living/carbon/adjustFireLoss(amount) + if(status_flags & GODMODE) + return 0 + if(amount > 0) + take_overall_damage(0, amount) + else + heal_overall_damage(0, -amount) + + +/mob/living/carbon/adjustToxLoss(amount, updating_health=1) + if(has_dna() && TOXINLOVER in dna.species.specflags) //damage becomes healing and healing becomes damage + amount = -amount + if(amount > 0) + blood_volume -= 5*amount + else + blood_volume -= amount + return ..() + +//////////////////////////////////////////// + +//Returns a list of damaged bodyparts +/mob/living/carbon/proc/get_damaged_bodyparts(brute, burn) + var/list/obj/item/bodypart/parts = list() + for(var/X in bodyparts) + var/obj/item/bodypart/BP = X + if((brute && BP.brute_dam) || (burn && BP.burn_dam)) + parts += BP + return parts + +//Returns a list of damageable bodyparts +/mob/living/carbon/proc/get_damageable_bodyparts() + var/list/obj/item/bodypart/parts = list() + for(var/X in bodyparts) + var/obj/item/bodypart/BP = X + if(BP.brute_dam + BP.burn_dam < BP.max_damage) + parts += BP + return parts + +//Heals ONE bodypart randomly selected from damaged ones. +//It automatically updates damage overlays if necessary +//It automatically updates health status +/mob/living/carbon/heal_bodypart_damage(brute, burn, only_robotic = 0, only_organic = 1) + var/list/obj/item/bodypart/parts = get_damaged_bodyparts(brute,burn) + if(!parts.len) + return + var/obj/item/bodypart/picked = pick(parts) + if(picked.heal_damage(brute, burn, only_robotic, only_organic)) + update_damage_overlays() + +//Damages ONE bodypart randomly selected from damagable ones. +//It automatically updates damage overlays if necessary +//It automatically updates health status +/mob/living/carbon/take_bodypart_damage(brute, burn) + var/list/obj/item/bodypart/parts = get_damageable_bodyparts() + if(!parts.len) + return + var/obj/item/bodypart/picked = pick(parts) + if(picked.take_damage(brute,burn)) + update_damage_overlays() + + +//Heal MANY bodyparts, in random order +/mob/living/carbon/heal_overall_damage(brute, burn, only_robotic = 0, only_organic = 1, updating_health = 1) + var/list/obj/item/bodypart/parts = get_damaged_bodyparts(brute,burn) + + var/update = 0 + while(parts.len && (brute>0 || burn>0) ) + var/obj/item/bodypart/picked = pick(parts) + + var/brute_was = picked.brute_dam + var/burn_was = picked.burn_dam + + update |= picked.heal_damage(brute,burn, only_robotic, only_organic, 0) + + brute -= (brute_was-picked.brute_dam) + burn -= (burn_was-picked.burn_dam) + + parts -= picked + if(updating_health) + updatehealth() + if(update) + update_damage_overlays() + +// damage MANY bodyparts, in random order +/mob/living/carbon/take_overall_damage(brute, burn, updating_health = 1) + if(status_flags & GODMODE) + return //godmode + + var/list/obj/item/bodypart/parts = get_damageable_bodyparts() + var/update = 0 + while(parts.len && (brute>0 || burn>0) ) + var/obj/item/bodypart/picked = pick(parts) + var/brute_per_part = round(brute/parts.len, 0.01) + var/burn_per_part = round(burn/parts.len, 0.01) + + var/brute_was = picked.brute_dam + var/burn_was = picked.burn_dam + + + update |= picked.take_damage(brute_per_part,burn_per_part, 0) + + brute -= (picked.brute_dam - brute_was) + burn -= (picked.burn_dam - burn_was) + + parts -= picked + if(updating_health) + updatehealth() + if(update) + update_damage_overlays() + + + +/mob/living/carbon/adjustStaminaLoss(amount, updating_stamina = 1) + if(status_flags & GODMODE) + return 0 + staminaloss = Clamp(staminaloss + amount, 0, maxHealth*2) + if(updating_stamina) + update_stamina() + + +/mob/living/carbon/setStaminaLoss(amount, updating_stamina = 1) + if(status_flags & GODMODE) + return 0 + staminaloss = amount + if(updating_stamina) + update_stamina() diff --git a/code/modules/mob/living/carbon/death.dm b/code/modules/mob/living/carbon/death.dm index 3db1d738a964..f1a2a526a7aa 100644 --- a/code/modules/mob/living/carbon/death.dm +++ b/code/modules/mob/living/carbon/death.dm @@ -3,19 +3,43 @@ losebreath = 0 ..() -/mob/living/carbon/gib(no_brain, no_organs) +/mob/living/carbon/gib(no_brain, no_organs, no_bodyparts) for(var/mob/M in src) if(M in stomach_contents) stomach_contents.Remove(M) - M.loc = loc + M.forceMove(loc) visible_message("[M] bursts out of [src]!") ..() -/mob/living/carbon/spill_organs(no_brain) - for(var/obj/item/organ/I in internal_organs) - if(no_brain && istype(I, /obj/item/organ/brain)) - continue - if(I) +/mob/living/carbon/spill_organs(no_brain, no_organs, no_bodyparts) + if(!no_bodyparts) + if(no_organs)//so the organs don't get transfered inside the bodyparts we'll drop. + for(var/X in internal_organs) + qdel(X) + else //we're going to drop all bodyparts except chest, so the only organs that needs spilling are those inside it. + for(var/X in internal_organs) + var/obj/item/organ/O = X + if(no_brain && istype(O, /obj/item/organ/brain)) + qdel(O) //so the brain isn't transfered to the head when the head drops. + continue + var/org_zone = check_zone(O.zone) //both groin and chest organs. + if(org_zone == "chest") + O.Remove(src) + O.forceMove(get_turf(src)) + O.throw_at_fast(get_edge_target_turf(src,pick(alldirs)),rand(1,3),5) + else + for(var/X in internal_organs) + var/obj/item/organ/I = X + if(no_brain && istype(I, /obj/item/organ/brain)) + qdel(I) + continue I.Remove(src) - I.loc = get_turf(src) + I.forceMove(get_turf(src)) I.throw_at_fast(get_edge_target_turf(src,pick(alldirs)),rand(1,3),5) + + +/mob/living/carbon/spread_bodyparts() + for(var/X in bodyparts) + var/obj/item/bodypart/BP = X + BP.drop_limb() + BP.throw_at_fast(get_edge_target_turf(src,pick(alldirs)),rand(1,3),5) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/examine.dm b/code/modules/mob/living/carbon/examine.dm index 1be55c38a125..61d30f7b8e9c 100644 --- a/code/modules/mob/living/carbon/examine.dm +++ b/code/modules/mob/living/carbon/examine.dm @@ -2,7 +2,7 @@ var/msg = "*---------*\nThis is \icon[src] \a [src]!\n" if (handcuffed) - msg += "It is \icon[src.handcuffed] handcuffed!\n" + msg += "It is \icon[src.handcuffed] handcuffed!\n" if (head) msg += "It has \icon[src.head] \a [src.head] on its head. \n" if (wear_mask) @@ -17,52 +17,65 @@ if (back) msg += "It has \icon[src.back] \a [src.back] on its back.\n" + var/appears_dead = 0 if (stat == DEAD) - msg += "It is limp and unresponsive, with no signs of life.\n" - else - msg += "" - var/temp = getBruteLoss() - if(temp) - if (temp < 30) - msg += "It has minor bruising.\n" - else - msg += "It has severe bruising!\n" + appears_dead = 1 + if(getorgan(/obj/item/organ/brain)) + msg += "It is limp and unresponsive, with no signs of life.\n" + else if(get_bodypart("head")) + msg += "It appears that it's brain is missing...\n" - temp = getFireLoss() - if(temp) - if (temp < 30) - msg += "It has minor burns.\n" - else - msg += "It has severe burns!\n" + var/list/missing = get_missing_limbs() + for(var/t in missing) + if(t=="head") + msg += "Its [parse_zone(t)] is missing!\n" + continue + msg += "<Its [parse_zone(t)] is missing!\n" - temp = getCloneLoss() - if(temp) - if(getCloneLoss() < 30) - msg += "It is slightly deformed.\n" - else - msg += "It is severely deformed.\n" + msg += "" + var/temp = getBruteLoss() + if(temp) + if (temp < 30) + msg += "It has minor bruising.\n" + else + msg += "It has severe bruising!\n" - if(getBrainLoss() > 60) - msg += "It seems to be clumsy and unable to think.\n" + temp = getFireLoss() + if(temp) + if (temp < 30) + msg += "It has minor burns.\n" + else + msg += "It has severe burns!\n" - if(fire_stacks > 0) - msg += "It's covered in something flammable.\n" - if(fire_stacks < 0) - msg += "It's soaked in water.\n" + temp = getCloneLoss() + if(temp) + if(getCloneLoss() < 30) + msg += "It is slightly deformed.\n" + else + msg += "It is severely deformed.\n" - if(pulledby && pulledby.grab_state) - msg += "It's restrained by [pulledby]'s grip.\n" + if(getBrainLoss() > 60) + msg += "It seems to be clumsy and unable to think.\n" + if(fire_stacks > 0) + msg += "It's covered in something flammable.\n" + if(fire_stacks < 0) + msg += "It's soaked in water.\n" + + if(pulledby && pulledby.grab_state) + msg += "It's restrained by [pulledby]'s grip.\n" + + msg += "" + + if(!appears_dead) if(stat == UNCONSCIOUS) msg += "It isn't responding to anything around it; it seems to be asleep.\n" - msg += "" - if(digitalcamo) - msg += "It is moving its body in an unnatural and blatantly unsimian manner.\n" + if(digitalcamo) + msg += "It is moving its body in an unnatural and blatantly unsimian manner.\n" + - if(!getorgan(/obj/item/organ/brain)) - msg += "It appears that it's brain is missing...\n" msg += "*---------*" - user << msg \ No newline at end of file + user << msg diff --git a/code/modules/mob/living/carbon/human/damage_procs.dm b/code/modules/mob/living/carbon/human/damage_procs.dm new file mode 100644 index 000000000000..aa49718753f2 --- /dev/null +++ b/code/modules/mob/living/carbon/human/damage_procs.dm @@ -0,0 +1,5 @@ + + +/mob/living/carbon/human/apply_damage(damage = 0,damagetype = BRUTE, def_zone = null, blocked = 0) + // depending on the species, it will run the corresponding apply_damage code there + return dna.species.apply_damage(damage, damagetype, def_zone, blocked, src) diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm index d1b085ca3b94..83bf44f8e14a 100644 --- a/code/modules/mob/living/carbon/human/death.dm +++ b/code/modules/mob/living/carbon/human/death.dm @@ -4,8 +4,11 @@ /mob/living/carbon/human/dust_animation() PoolOrNew(/obj/effect/overlay/temp/dust_animation, list(loc, "dust-h")) -/mob/living/carbon/human/spawn_gibs() - hgibs(loc, viruses, dna) +/mob/living/carbon/human/spawn_gibs(with_bodyparts) + if(with_bodyparts) + new /obj/effect/gibspawner/human(loc, viruses, dna) + else + new /obj/effect/gibspawner/humanbodypartless(loc, viruses, dna) /mob/living/carbon/human/spawn_dust() new /obj/effect/decal/remains/human(loc) @@ -40,21 +43,9 @@ set_species(/datum/species/skeleton) return 1 -/mob/living/carbon/proc/ChangeToHusk() - if(disabilities & HUSK) - return - disabilities |= HUSK - status_flags |= DISFIGURED //makes them unknown without fucking up other stuff like admintools - return 1 - -/mob/living/carbon/human/ChangeToHusk() - . = ..() - if(.) - update_hair() - update_body() /mob/living/carbon/proc/Drain() - ChangeToHusk() + become_husk() disabilities |= NOCLONE blood_volume = 0 return 1 diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 48f191b4e747..1c7a02138df7 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -3,7 +3,7 @@ real_name = "Unknown" voice_name = "Unknown" icon = 'icons/mob/human.dmi' - icon_state = "caucasian1_m_s" + icon_state = "caucasian_m_s" @@ -18,18 +18,7 @@ verbs += /mob/living/proc/lay_down //initialize limbs first - bodyparts = newlist(/obj/item/bodypart/chest, /obj/item/bodypart/head, /obj/item/bodypart/r_leg, /obj/item/bodypart/l_leg) - var/obj/item/bodypart/l_arm/l_arm = new() - var/obj/item/bodypart/r_arm/r_arm = new() - bodyparts += l_arm - bodyparts += r_arm - l_arm.held_index = 1 - r_arm.held_index = 2 - hand_bodyparts += l_arm - hand_bodyparts += r_arm - for(var/X in bodyparts) - var/obj/item/bodypart/O = X - O.owner = src + create_bodyparts() //initialize dna. for spawned humans; overwritten by other code create_dna(src) @@ -40,21 +29,7 @@ set_species(dna.species.type) //initialise organs - if(!(NOHUNGER in dna.species.specflags)) - internal_organs += new /obj/item/organ/appendix - - if(!(NOBREATH in dna.species.specflags)) - internal_organs += new /obj/item/organ/lungs - - if(!(NOBLOOD in dna.species.specflags)) - internal_organs += new /obj/item/organ/heart - - internal_organs += new /obj/item/organ/brain - - //Note: Additional organs are generated/replaced on the dna.species level - - for(var/obj/item/organ/I in internal_organs) - I.Insert(src) + create_internal_organs() martial_art = default_martial_art @@ -62,6 +37,16 @@ ..() +/mob/living/carbon/human/create_internal_organs() + if(!(NOHUNGER in dna.species.specflags)) + internal_organs += new /obj/item/organ/appendix + if(!(NOBREATH in dna.species.specflags)) + internal_organs += new /obj/item/organ/lungs + if(!(NOBLOOD in dna.species.specflags)) + internal_organs += new /obj/item/organ/heart + internal_organs += new /obj/item/organ/brain + ..() + /mob/living/carbon/human/OpenCraftingMenu() handcrafting.ui_interact(src) @@ -123,87 +108,6 @@ stat("*", "[D.name], Type: [D.spread_text], Stage: [D.stage]/[D.max_stages], Possible Cure: [D.cure_text]") -/mob/living/carbon/human/ex_act(severity, ex_target) - var/b_loss = null - var/f_loss = null - var/bomb_armor = getarmor(null, "bomb") - if(istype(ex_target, /datum/spacevine_mutation) && isvineimmune(src)) - return - - switch (severity) - if (1) - b_loss += 500 - if (prob(bomb_armor)) - shred_clothing(1,150) - var/atom/target = get_edge_target_turf(src, get_dir(src, get_step_away(src, src))) - throw_at(target, 200, 4) - else - gib() - return - - if (2) - b_loss += 60 - - f_loss += 60 - if (prob(bomb_armor)) - b_loss = b_loss/1.5 - f_loss = f_loss/1.5 - shred_clothing(1,25) - else - shred_clothing(1,50) - - if (!istype(ears, /obj/item/clothing/ears/earmuffs)) - adjustEarDamage(30, 120) - if (prob(70)) - Paralyse(10) - - if(3) - b_loss += 30 - if (prob(bomb_armor)) - b_loss = b_loss/2 - if (!istype(ears, /obj/item/clothing/ears/earmuffs)) - adjustEarDamage(15,60) - if (prob(50)) - Paralyse(10) - - take_overall_damage(b_loss,f_loss) - //attempt to dismember bodyparts - if(severity <= 2 || !bomb_armor) - var/max_limb_loss = round(4/severity) //so you don't lose four limbs at severity 3. - for(var/X in bodyparts) - var/obj/item/bodypart/BP = X - if(prob(50/severity) && !prob(getarmor(BP, "bomb")) && BP.body_zone != "head" && BP.body_zone != "chest") - BP.brute_dam = BP.max_damage - BP.dismember() - max_limb_loss-- - if(!max_limb_loss) - break - ..() - -/mob/living/carbon/human/blob_act(obj/effect/blob/B) - if(stat == DEAD) - return - show_message("The blob attacks you!") - var/dam_zone = pick("chest", "l_hand", "r_hand", "l_leg", "r_leg") - var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone)) - apply_damage(5, BRUTE, affecting, run_armor_check(affecting, "melee")) - return - -/mob/living/carbon/human/bullet_act() - if(martial_art && martial_art.deflection_chance) //Some martial arts users can deflect projectiles! - if(!prob(martial_art.deflection_chance)) - return ..() - if(!src.lying && dna && !dna.check_mutation(HULK)) //But only if they're not lying down, and hulks can't do it - src.visible_message("[src] deflects the projectile; they can't be hit with ranged weapons!", "You deflect the projectile!") - playsound(src, pick("sound/weapons/bulletflyby.ogg","sound/weapons/bulletflyby2.ogg","sound/weapons/bulletflyby3.ogg"), 75, 1) - return 0 - ..() - -/mob/living/carbon/human/attack_ui(slot) - if(!has_hand_for_held_index(active_hand_index)) - return 0 - return ..() - /mob/living/carbon/human/show_inv(mob/user) user.set_machine(src) var/has_breathable_mask = istype(wear_mask, /obj/item/clothing/mask) @@ -300,35 +204,6 @@ spreadFire(AM) -//Added a safety check in case you want to shock a human mob directly through electrocute_act. -/mob/living/carbon/human/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, override = 0, tesla_shock = 0) - if(tesla_shock) - var/total_coeff = 1 - if(gloves) - var/obj/item/clothing/gloves/G = gloves - if(G.siemens_coefficient <= 0) - total_coeff -= 0.5 - if(wear_suit) - var/obj/item/clothing/suit/S = wear_suit - if(S.siemens_coefficient <= 0) - total_coeff -= 0.95 - siemens_coeff = total_coeff - else if(!safety) - var/gloves_siemens_coeff = 1 - if(gloves) - var/obj/item/clothing/gloves/G = gloves - gloves_siemens_coeff = G.siemens_coefficient - siemens_coeff = gloves_siemens_coeff - if(heart_attack) - if(shock_damage * siemens_coeff >= 1 && prob(25)) - heart_attack = 0 - if(stat == CONSCIOUS) - src << "You feel your heart beating again!" - . = ..(shock_damage,source,siemens_coeff,safety,override,tesla_shock) - if(.) - electrocution_animation(40) - - /mob/living/carbon/human/Topic(href, href_list) if(usr.canUseTopic(src, BE_CLOSE, NO_DEXTERY)) @@ -734,17 +609,6 @@ update_body() update_hair() -/mob/living/carbon/human/singularity_act() - var/gain = 20 - if(mind) - if((mind.assigned_role == "Station Engineer") || (mind.assigned_role == "Chief Engineer") ) - gain = 100 - if(mind.assigned_role == "Clown") - gain = rand(-300, 300) - investigate_log("([key_name(src)]) has been consumed by the singularity.","singulo") //Oh that's where the clown ended up! - gib() - return(gain) - /mob/living/carbon/human/singularity_pull(S, current_size) if(current_size >= STAGE_THREE) for(var/obj/item/hand in held_items) @@ -756,71 +620,6 @@ return ..() - -/mob/living/carbon/human/help_shake_act(mob/living/carbon/M) - if(!istype(M)) - return - - if(health >= 0) - if(src == M) - visible_message( \ - "[src] examines \himself.", \ - "You check yourself for injuries.") - - var/list/missing = list("head", "chest", "l_arm", "r_arm", "l_leg", "r_leg") - for(var/X in bodyparts) - var/obj/item/bodypart/LB = X - missing -= LB.body_zone - var/status = "" - var/brutedamage = LB.brute_dam - var/burndamage = LB.burn_dam - if(hallucination) - if(prob(30)) - brutedamage += rand(30,40) - if(prob(30)) - burndamage += rand(30,40) - - if(brutedamage > 0) - status = "bruised" - if(brutedamage > 20) - status = "battered" - if(brutedamage > 40) - status = "mangled" - if(brutedamage > 0 && burndamage > 0) - status += " and " - if(burndamage > 40) - status += "peeling away" - - else if(burndamage > 10) - status += "blistered" - else if(burndamage > 0) - status += "numb" - if(status == "") - status = "OK" - src << "\t [status == "OK" ? "\blue" : "\red"] Your [LB.name] is [status]." - - for(var/obj/item/I in LB.embedded_objects) - src << "\t \red There is \a [I] embedded in your [LB.name]!" - - for(var/t in missing) - src << "Your [parse_zone(t)] is missing!" - - if(bleed_rate) - src << "You are bleeding!" - if(staminaloss) - if(staminaloss > 30) - src << "You're completely exhausted." - else - src << "You feel fatigued." - else - if(wear_suit) - wear_suit.add_fingerprint(M) - else if(w_uniform) - w_uniform.add_fingerprint(M) - - ..() - - /mob/living/carbon/human/proc/do_cpr(mob/living/carbon/C) CHECK_DNA_AND_SPECIES(C) @@ -1010,7 +809,6 @@ hud_used.healthdoll.icon_state = "healthdoll_DEAD" /mob/living/carbon/human/fully_heal(admin_revive = 0) - CHECK_DNA_AND_SPECIES(src) if(admin_revive) regenerate_limbs() diff --git a/code/modules/mob/living/carbon/human/human_attackalien.dm b/code/modules/mob/living/carbon/human/human_attackalien.dm deleted file mode 100644 index b407a2881a93..000000000000 --- a/code/modules/mob/living/carbon/human/human_attackalien.dm +++ /dev/null @@ -1,39 +0,0 @@ -/mob/living/carbon/human/attack_alien(mob/living/carbon/alien/humanoid/M) - if(check_shields(0, M.name)) - visible_message("[M] attempted to touch [src]!") - return 0 - - if(..()) - if(M.a_intent == "harm") - if (w_uniform) - w_uniform.add_fingerprint(M) - var/damage = prob(90) ? 20 : 0 - if(!damage) - playsound(loc, 'sound/weapons/slashmiss.ogg', 50, 1, -1) - visible_message("[M] has lunged at [src]!", \ - "[M] has lunged at [src]!") - return 0 - var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected)) - var/armor_block = run_armor_check(affecting, "melee","","",10) - - playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1) - visible_message("[M] has slashed at [src]!", \ - "[M] has slashed at [src]!") - if(!dismembering_strike(M, M.zone_selected)) //Dismemberment successful - return 1 - apply_damage(damage, BRUTE, affecting, armor_block) - add_logs(M, src, "attacked") - updatehealth() - - if(M.a_intent == "disarm") //Always drop item in hand, if no item, get stunned instead. - if(get_active_held_item() && drop_item()) - playsound(loc, 'sound/weapons/slash.ogg', 25, 1, -1) - visible_message("[M] disarmed [src]!", \ - "[M] disarmed [src]!") - else - playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1) - Weaken(5) - add_logs(M, src, "tackled") - visible_message("[M] has tackled down [src]!", \ - "[M] has tackled down [src]!") - return diff --git a/code/modules/mob/living/carbon/human/human_attackhand.dm b/code/modules/mob/living/carbon/human/human_attackhand.dm deleted file mode 100644 index 43e4dfaae761..000000000000 --- a/code/modules/mob/living/carbon/human/human_attackhand.dm +++ /dev/null @@ -1,14 +0,0 @@ -/mob/living/carbon/human/attack_hulk(mob/living/carbon/human/user) - if(user.a_intent == "harm") - ..(user, 1) - playsound(loc, user.dna.species.attack_sound, 25, 1, -1) - var/hulk_verb = pick("smash","pummel") - visible_message("[user] has [hulk_verb]ed [src]!", \ - "[user] has [hulk_verb]ed [src]!") - adjustBruteLoss(15) - return 1 - -/mob/living/carbon/human/attack_hand(mob/living/carbon/human/M) - if(..()) //to allow surgery to return properly. - return - dna.species.spec_attack_hand(M, src) diff --git a/code/modules/mob/living/carbon/human/human_attackpaw.dm b/code/modules/mob/living/carbon/human/human_attackpaw.dm deleted file mode 100644 index 4c666a86799a..000000000000 --- a/code/modules/mob/living/carbon/human/human_attackpaw.dm +++ /dev/null @@ -1,18 +0,0 @@ -/mob/living/carbon/human/attack_paw(mob/living/carbon/monkey/M) - var/dam_zone = pick("chest", "l_hand", "r_hand", "l_leg", "r_leg") - var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone)) - - if(M.a_intent == "help") - ..() //shaking - return 0 - - if(M.limb_destroyer) - dismembering_strike(M, affecting.body_zone) - - if(can_inject(M, 1, affecting))//Thick suits can stop monkey bites. - if(..()) //successful monkey bite, this handles disease contraction. - var/damage = rand(1, 3) - if(stat != DEAD) - apply_damage(damage, BRUTE, affecting, run_armor_check(affecting, "melee")) - updatehealth() - return 1 \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm deleted file mode 100644 index c218fbb84450..000000000000 --- a/code/modules/mob/living/carbon/human/human_damage.dm +++ /dev/null @@ -1,161 +0,0 @@ -//Updates the mob's health from bodyparts and mob damage variables -/mob/living/carbon/human/updatehealth() - if(status_flags & GODMODE) - return - var/total_burn = 0 - var/total_brute = 0 - for(var/X in bodyparts) //hardcoded to streamline things a bit - var/obj/item/bodypart/BP = X - total_brute += BP.brute_dam - total_burn += BP.burn_dam - health = maxHealth - getOxyLoss() - getToxLoss() - getCloneLoss() - total_burn - total_brute - update_stat() - if(((maxHealth - total_burn) < HEALTH_THRESHOLD_DEAD) && stat == DEAD ) - ChangeToHusk() - if(on_fire) - shred_clothing() - med_hud_set_health() - med_hud_set_status() - - -//These procs fetch a cumulative total damage from all bodyparts -/mob/living/carbon/human/getBruteLoss() - var/amount = 0 - for(var/X in bodyparts) - var/obj/item/bodypart/BP = X - amount += BP.brute_dam - return amount - -/mob/living/carbon/human/getFireLoss() - var/amount = 0 - for(var/X in bodyparts) - var/obj/item/bodypart/BP = X - amount += BP.burn_dam - return amount - - -/mob/living/carbon/human/adjustBruteLoss(amount) - if(status_flags & GODMODE) - return 0 - if(amount > 0) - take_overall_damage(amount, 0) - else - heal_overall_damage(-amount, 0) - -/mob/living/carbon/human/adjustFireLoss(amount) - if(status_flags & GODMODE) - return 0 - if(amount > 0) - take_overall_damage(0, amount) - else - heal_overall_damage(0, -amount) - -/mob/living/carbon/human/proc/hat_fall_prob() - var/multiplier = 1 - var/obj/item/clothing/head/H = head - var/loose = 40 - if(stat || (status_flags & FAKEDEATH)) - multiplier = 2 - if(H.flags_cover & (HEADCOVERSEYES | HEADCOVERSMOUTH) || H.flags_inv & (HIDEEYES | HIDEFACE)) - loose = 0 - return loose * multiplier - -//////////////////////////////////////////// - -//Returns a list of damaged bodyparts -/mob/living/carbon/human/proc/get_damaged_bodyparts(brute, burn) - var/list/obj/item/bodypart/parts = list() - for(var/X in bodyparts) - var/obj/item/bodypart/BP = X - if((brute && BP.brute_dam) || (burn && BP.burn_dam)) - parts += BP - return parts - -//Returns a list of damageable bodyparts -/mob/living/carbon/human/proc/get_damageable_bodyparts() - var/list/obj/item/bodypart/parts = list() - for(var/X in bodyparts) - var/obj/item/bodypart/BP = X - if(BP.brute_dam + BP.burn_dam < BP.max_damage) - parts += BP - return parts - -//Heals ONE external organ, organ gets randomly selected from damaged ones. -//It automatically updates damage overlays if necesary -//It automatically updates health status -/mob/living/carbon/human/heal_organ_damage(brute, burn) - var/list/obj/item/bodypart/parts = get_damaged_bodyparts(brute,burn) - if(!parts.len) - return - var/obj/item/bodypart/picked = pick(parts) - if(picked.heal_damage(brute,burn,0)) - update_damage_overlays(0) - updatehealth() - -//Damages ONE external organ, organ gets randomly selected from damagable ones. -//It automatically updates damage overlays if necesary -//It automatically updates health status -/mob/living/carbon/human/take_organ_damage(brute, burn) - var/list/obj/item/bodypart/parts = get_damageable_bodyparts() - if(!parts.len) - return - var/obj/item/bodypart/picked = pick(parts) - if(picked.take_damage(brute,burn)) - update_damage_overlays(0) - updatehealth() - - -//Heal MANY bodyparts, in random order -/mob/living/carbon/human/heal_overall_damage(brute, burn, updating_health=1) - var/list/obj/item/bodypart/parts = get_damaged_bodyparts(brute,burn) - - var/update = 0 - while(parts.len && (brute>0 || burn>0) ) - var/obj/item/bodypart/picked = pick(parts) - - var/brute_was = picked.brute_dam - var/burn_was = picked.burn_dam - - update |= picked.heal_damage(brute,burn,0) - - brute -= (brute_was-picked.brute_dam) - burn -= (burn_was-picked.burn_dam) - - parts -= picked - if(updating_health) - updatehealth() - if(update) - update_damage_overlays(0) - -// damage MANY bodyparts, in random order -/mob/living/carbon/human/take_overall_damage(brute, burn) - if(status_flags & GODMODE) - return //godmode - - var/list/obj/item/bodypart/parts = get_damageable_bodyparts() - var/update = 0 - while(parts.len && (brute>0 || burn>0) ) - var/obj/item/bodypart/picked = pick(parts) - var/brute_per_part = brute/parts.len - var/burn_per_part = burn/parts.len - - var/brute_was = picked.brute_dam - var/burn_was = picked.burn_dam - - - update |= picked.take_damage(brute_per_part,burn_per_part) - - brute -= (picked.brute_dam - brute_was) - burn -= (picked.burn_dam - burn_was) - - parts -= picked - updatehealth() - if(update) - update_damage_overlays(0) - -//////////////////////////////////////////// - - -/mob/living/carbon/human/apply_damage(damage = 0,damagetype = BRUTE, def_zone = null, blocked = 0) - // depending on the species, it will run the corresponding apply_damage code there - return dna.species.apply_damage(damage, damagetype, def_zone, blocked, src) diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index f19d05675654..535f7f39ffb8 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -31,10 +31,36 @@ protection += C.armor[type] return protection +///checkeyeprot() +///Returns a number between -1 to 2 +/mob/living/carbon/human/get_eye_protection() + var/number = ..() + if(istype(src.head, /obj/item/clothing/head)) //are they wearing something on their head + var/obj/item/clothing/head/HFP = src.head //if yes gets the flash protection value from that item + number += HFP.flash_protect + if(istype(src.glasses, /obj/item/clothing/glasses)) //glasses + var/obj/item/clothing/glasses/GFP = src.glasses + number += GFP.flash_protect + if(istype(src.wear_mask, /obj/item/clothing/mask)) //mask + var/obj/item/clothing/mask/MFP = src.wear_mask + number += MFP.flash_protect + return number + +/mob/living/carbon/human/get_ear_protection() + if((ears && (ears.flags & EARBANGPROTECT)) || (head && (head.flags & HEADBANGPROTECT))) + return 1 + /mob/living/carbon/human/on_hit(proj_type) dna.species.on_hit(proj_type, src) + /mob/living/carbon/human/bullet_act(obj/item/projectile/P, def_zone) + if(martial_art && martial_art.deflection_chance) //Some martial arts users can deflect projectiles! + if(prob(martial_art.deflection_chance)) + if(!lying && dna && !dna.check_mutation(HULK)) //But only if they're not lying down, and hulks can't do it + visible_message("[src] deflects the projectile; they can't be hit with ranged weapons!", "You deflect the projectile!") + playsound(src, pick("sound/weapons/bulletflyby.ogg","sound/weapons/bulletflyby2.ogg","sound/weapons/bulletflyby3.ogg"), 75, 1) + return 0 if(!(P.original == src && P.firer == src)) //can't block or reflect when shooting yourself if(istype(P, /obj/item/projectile/energy) || istype(P, /obj/item/projectile/beam)) if(check_reflect(def_zone)) // Checks if you've passed a reflection% check @@ -63,11 +89,6 @@ return (..(P , def_zone)) -/mob/living/check_projectile_dismemberment(obj/item/projectile/P, def_zone) - var/obj/item/bodypart/affecting = get_bodypart(def_zone) - if(affecting && affecting.get_damage() >= (affecting.max_damage - P.dismemberment)) - affecting.dismember(P.damtype) - /mob/living/carbon/human/proc/check_reflect(def_zone) //Reflection checks for anything in your l_hand, r_hand, or wear_suit based on the reflection chance of the object if(wear_suit) if(wear_suit.IsReflect(def_zone) == 1) @@ -96,22 +117,309 @@ return 0 +/mob/living/carbon/human/hitby(atom/movable/AM, skipcatch = 0, hitpush = 1, blocked = 0) + var/obj/item/I + var/throwpower = 30 + if(istype(AM, /obj/item)) + I = AM + throwpower = I.throwforce + if(I.thrownby == src) //No throwing stuff at yourself to trigger hit reactions + return ..() + if(check_shields(throwpower, "\the [AM.name]", AM, THROWN_PROJECTILE_ATTACK)) + hitpush = 0 + skipcatch = 1 + blocked = 1 + else if(I) + if(I.throw_speed >= EMBED_THROWSPEED_THRESHOLD) + if(can_embed(I)) + if(prob(I.embed_chance) && !(dna && (PIERCEIMMUNE in dna.species.specflags))) + throw_alert("embeddedobject", /obj/screen/alert/embeddedobject) + var/obj/item/bodypart/L = pick(bodyparts) + L.embedded_objects |= I + I.add_mob_blood(src)//it embedded itself in you, of course it's bloody! + I.loc = src + L.take_damage(I.w_class*I.embedded_impact_pain_multiplier) + visible_message("\the [I.name] embeds itself in [src]'s [L.name]!","\the [I.name] embeds itself in your [L.name]!") + hitpush = 0 + skipcatch = 1 //can't catch the now embedded item + + return ..() + +/mob/living/carbon/human/grabbedby(mob/living/carbon/user, supress_message = 0) + if(user == src && pulling && !pulling.anchored && grab_state >= GRAB_AGGRESSIVE && (disabilities & FAT) && ismonkey(pulling)) + devour_mob(pulling) + else + ..() + +/mob/living/carbon/human/grippedby(mob/living/user) + if(w_uniform) + w_uniform.add_fingerprint(user) + ..() + + /mob/living/carbon/human/attacked_by(obj/item/I, mob/living/user) if(!I || !user) return 0 - var/obj/item/bodypart/affecting = get_bodypart(ran_zone(user.zone_selected)) - var/target_area = parse_zone(check_zone(user.zone_selected)) + var/obj/item/bodypart/affecting = get_bodypart(ran_zone(user.zone_selected)) //what we're actually ending up trying to hit. + var/target_area = parse_zone(check_zone(user.zone_selected)) //our intended target feedback_add_details("item_used_for_combat","[I.type]|[I.force]") feedback_add_details("zone_targeted","[target_area]") // the attacked_by code varies among species - return dna.species.spec_attacked_by(I, user, affecting, a_intent, target_area, src) + return dna.species.spec_attacked_by(I, user, affecting, a_intent, src) + + +/mob/living/carbon/human/attack_hulk(mob/living/carbon/human/user) + if(user.a_intent == "harm") + ..(user, 1) + playsound(loc, user.dna.species.attack_sound, 25, 1, -1) + var/hulk_verb = pick("smash","pummel") + visible_message("[user] has [hulk_verb]ed [src]!", \ + "[user] has [hulk_verb]ed [src]!") + adjustBruteLoss(15) + return 1 + +/mob/living/carbon/human/attack_hand(mob/living/carbon/human/M) + if(..()) //to allow surgery to return properly. + return + dna.species.spec_attack_hand(M, src) + + +/mob/living/carbon/human/attack_paw(mob/living/carbon/monkey/M) + var/dam_zone = pick("chest", "l_hand", "r_hand", "l_leg", "r_leg") + var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone)) + + if(M.a_intent == "help") + ..() //shaking + return 0 + + if(M.limb_destroyer) + dismembering_strike(M, affecting.body_zone) + + if(can_inject(M, 1, affecting))//Thick suits can stop monkey bites. + if(..()) //successful monkey bite, this handles disease contraction. + var/damage = rand(1, 3) + if(stat != DEAD) + apply_damage(damage, BRUTE, affecting, run_armor_check(affecting, "melee")) + return 1 + +/mob/living/carbon/human/attack_alien(mob/living/carbon/alien/humanoid/M) + if(check_shields(0, M.name)) + visible_message("[M] attempted to touch [src]!") + return 0 + + if(..()) + if(M.a_intent == "harm") + if (w_uniform) + w_uniform.add_fingerprint(M) + var/damage = prob(90) ? 20 : 0 + if(!damage) + playsound(loc, 'sound/weapons/slashmiss.ogg', 50, 1, -1) + visible_message("[M] has lunged at [src]!", \ + "[M] has lunged at [src]!") + return 0 + var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected)) + var/armor_block = run_armor_check(affecting, "melee","","",10) + + playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1) + visible_message("[M] has slashed at [src]!", \ + "[M] has slashed at [src]!") + add_logs(M, src, "attacked") + if(!dismembering_strike(M, M.zone_selected)) //Dismemberment successful + return 1 + apply_damage(damage, BRUTE, affecting, armor_block) + + if(M.a_intent == "disarm") //Always drop item in hand, if no item, get stunned instead. + if(get_active_held_item() && drop_item()) + playsound(loc, 'sound/weapons/slash.ogg', 25, 1, -1) + visible_message("[M] disarmed [src]!", \ + "[M] disarmed [src]!") + else + playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1) + Weaken(5) + add_logs(M, src, "tackled") + visible_message("[M] has tackled down [src]!", \ + "[M] has tackled down [src]!") + + +/mob/living/carbon/human/attack_larva(mob/living/carbon/alien/larva/L) + + if(..()) //successful larva bite. + var/damage = rand(1, 3) + if(check_shields(damage, "the [L.name]")) + return 0 + if(stat != DEAD) + L.amount_grown = min(L.amount_grown + damage, L.max_grown) + var/obj/item/bodypart/affecting = get_bodypart(ran_zone(L.zone_selected)) + var/armor_block = run_armor_check(affecting, "melee") + apply_damage(damage, BRUTE, affecting, armor_block) + + +/mob/living/carbon/human/attack_animal(mob/living/simple_animal/M) + if(..()) + var/damage = rand(M.melee_damage_lower, M.melee_damage_upper) + if(check_shields(damage, "the [M.name]", null, MELEE_ATTACK, M.armour_penetration)) + return 0 + var/dam_zone = dismembering_strike(M, pick("chest", "l_hand", "r_hand", "l_leg", "r_leg")) + if(!dam_zone) //Dismemberment successful + return 1 + var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone)) + var/armor = run_armor_check(affecting, "melee", armour_penetration = M.armour_penetration) + apply_damage(damage, M.melee_damage_type, affecting, armor) + + + +/mob/living/carbon/human/attack_slime(mob/living/simple_animal/slime/M) + if(..()) //successful slime attack + var/damage = rand(5, 25) + if(M.is_adult) + damage = rand(10, 35) + + if(check_shields(damage, "the [M.name]")) + return 0 + + var/dam_zone = dismembering_strike(M, pick("head", "chest", "l_arm", "r_arm", "l_leg", "r_leg")) + if(!dam_zone) //Dismemberment successful + return 1 + + var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone)) + var/armor_block = run_armor_check(affecting, "melee") + apply_damage(damage, BRUTE, affecting, armor_block) + +/mob/living/carbon/human/mech_melee_attack(obj/mecha/M) + + if(M.occupant.a_intent == "harm") + M.do_attack_animation(src) + if(M.damtype == "brute") + step_away(src,M,15) + var/obj/item/bodypart/temp = get_bodypart(pick("chest", "chest", "chest", "head")) + if(temp) + var/update = 0 + switch(M.damtype) + if("brute") + if(M.force > 20) + Paralyse(1) + update |= temp.take_damage(rand(M.force/2, M.force), 0) + playsound(src, 'sound/weapons/punch4.ogg', 50, 1) + if("fire") + update |= temp.take_damage(0, rand(M.force/2, M.force)) + playsound(src, 'sound/items/Welder.ogg', 50, 1) + if("tox") + M.mech_toxin_damage(src) + else + return + if(update) + update_damage_overlays() + updatehealth() + + visible_message("[M.name] has hit [src]!", \ + "[M.name] has hit [src]!") + add_logs(M.occupant, src, "attacked", M, "(INTENT: [uppertext(M.occupant.a_intent)]) (DAMTYPE: [uppertext(M.damtype)])") + + else + ..() + + +/mob/living/carbon/human/ex_act(severity, ex_target) + var/b_loss = null + var/f_loss = null + var/bomb_armor = getarmor(null, "bomb") + if(istype(ex_target, /datum/spacevine_mutation) && isvineimmune(src)) + return + + switch (severity) + if (1) + b_loss += 500 + if (prob(bomb_armor)) + shred_clothing(1,150) + var/atom/target = get_edge_target_turf(src, get_dir(src, get_step_away(src, src))) + throw_at(target, 200, 4) + else + gib() + return + + if (2) + b_loss += 60 + + f_loss += 60 + if (prob(bomb_armor)) + b_loss = b_loss/1.5 + f_loss = f_loss/1.5 + shred_clothing(1,25) + else + shred_clothing(1,50) + + if (!istype(ears, /obj/item/clothing/ears/earmuffs)) + adjustEarDamage(30, 120) + if (prob(70)) + Paralyse(10) + + if(3) + b_loss += 30 + if (prob(bomb_armor)) + b_loss = b_loss/2 + if (!istype(ears, /obj/item/clothing/ears/earmuffs)) + adjustEarDamage(15,60) + if (prob(50)) + Paralyse(8) + + take_overall_damage(b_loss,f_loss) + //attempt to dismember bodyparts + if(severity <= 2 || !bomb_armor) + var/max_limb_loss = round(4/severity) //so you don't lose four limbs at severity 3. + for(var/X in bodyparts) + var/obj/item/bodypart/BP = X + if(prob(50/severity) && !prob(getarmor(BP, "bomb")) && BP.body_zone != "head" && BP.body_zone != "chest") + BP.brute_dam = BP.max_damage + BP.dismember() + max_limb_loss-- + if(!max_limb_loss) + break + ..() + +/mob/living/carbon/human/blob_act(obj/effect/blob/B) + if(stat == DEAD) + return + show_message("The blob attacks you!") + var/dam_zone = pick("chest", "l_hand", "r_hand", "l_leg", "r_leg") + var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone)) + apply_damage(5, BRUTE, affecting, run_armor_check(affecting, "melee")) + + +//Added a safety check in case you want to shock a human mob directly through electrocute_act. +/mob/living/carbon/human/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, override = 0, tesla_shock = 0) + if(tesla_shock) + var/total_coeff = 1 + if(gloves) + var/obj/item/clothing/gloves/G = gloves + if(G.siemens_coefficient <= 0) + total_coeff -= 0.5 + if(wear_suit) + var/obj/item/clothing/suit/S = wear_suit + if(S.siemens_coefficient <= 0) + total_coeff -= 0.95 + siemens_coeff = total_coeff + else if(!safety) + var/gloves_siemens_coeff = 1 + if(gloves) + var/obj/item/clothing/gloves/G = gloves + gloves_siemens_coeff = G.siemens_coefficient + siemens_coeff = gloves_siemens_coeff + if(heart_attack) + if(shock_damage * siemens_coeff >= 1 && prob(25)) + heart_attack = 0 + if(stat == CONSCIOUS) + src << "You feel your heart beating again!" + . = ..(shock_damage,source,siemens_coeff,safety,override,tesla_shock) + if(.) + electrocution_animation(40) + /mob/living/carbon/human/emp_act(severity) var/informed = 0 for(var/obj/item/bodypart/L in src.bodyparts) - if(L.status == ORGAN_ROBOTIC) + if(L.status == BODYPART_ROBOTIC) if(!informed) src << "You feel a sharp pain as your robotic limbs overload." informed = 1 @@ -264,123 +572,76 @@ acid_volume_left = max(acid_volume_left - acid_decay, 0) -/mob/living/carbon/human/attack_animal(mob/living/simple_animal/M) - if(..()) - var/damage = rand(M.melee_damage_lower, M.melee_damage_upper) - if(check_shields(damage, "the [M.name]", null, MELEE_ATTACK, M.armour_penetration)) - return 0 - var/dam_zone = dismembering_strike(M, pick("chest", "l_hand", "r_hand", "l_leg", "r_leg")) - if(!dam_zone) //Dismemberment successful - return 1 - var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone)) - var/armor = run_armor_check(affecting, "melee", armour_penetration = M.armour_penetration) - apply_damage(damage, M.melee_damage_type, affecting, armor) - updatehealth() +/mob/living/carbon/human/singularity_act() + var/gain = 20 + if(mind) + if((mind.assigned_role == "Station Engineer") || (mind.assigned_role == "Chief Engineer") ) + gain = 100 + if(mind.assigned_role == "Clown") + gain = rand(-300, 300) + investigate_log("([key_name(src)]) has been consumed by the singularity.","singulo") //Oh that's where the clown ended up! + gib() + return(gain) +/mob/living/carbon/human/help_shake_act(mob/living/carbon/M) + if(!istype(M)) + return -/mob/living/carbon/human/attack_larva(mob/living/carbon/alien/larva/L) + if(health >= 0) + if(src == M) + visible_message( \ + "[src] examines \himself.", \ + "You check yourself for injuries.") - if(..()) //successful larva bite. - var/damage = rand(1, 3) - if(check_shields(damage, "the [L.name]")) - return 0 - if(stat != DEAD) - L.amount_grown = min(L.amount_grown + damage, L.max_grown) - var/obj/item/bodypart/affecting = get_bodypart(ran_zone(L.zone_selected)) - var/armor_block = run_armor_check(affecting, "melee") - apply_damage(damage, BRUTE, affecting, armor_block) - updatehealth() + var/list/missing = list("head", "chest", "l_arm", "r_arm", "l_leg", "r_leg") + for(var/X in bodyparts) + var/obj/item/bodypart/LB = X + missing -= LB.body_zone + var/status = "" + var/brutedamage = LB.brute_dam + var/burndamage = LB.burn_dam + if(hallucination) + if(prob(30)) + brutedamage += rand(30,40) + if(prob(30)) + burndamage += rand(30,40) + if(brutedamage > 0) + status = "bruised" + if(brutedamage > 20) + status = "battered" + if(brutedamage > 40) + status = "mangled" + if(brutedamage > 0 && burndamage > 0) + status += " and " + if(burndamage > 40) + status += "peeling away" -/mob/living/carbon/human/attack_slime(mob/living/simple_animal/slime/M) - if(..()) //successful slime attack - var/damage = rand(5, 25) - if(M.is_adult) - damage = rand(10, 35) + else if(burndamage > 10) + status += "blistered" + else if(burndamage > 0) + status += "numb" + if(status == "") + status = "OK" + src << "\t [status == "OK" ? "\blue" : "\red"] Your [LB.name] is [status]." - if(check_shields(damage, "the [M.name]")) - return 0 + for(var/obj/item/I in LB.embedded_objects) + src << "\t \red There is \a [I] embedded in your [LB.name]!" - var/dam_zone = dismembering_strike(M, pick("head", "chest", "l_arm", "r_arm", "l_leg", "r_leg")) - if(!dam_zone) //Dismemberment successful - return 1 + for(var/t in missing) + src << "Your [parse_zone(t)] is missing!" - var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone)) - var/armor_block = run_armor_check(affecting, "melee") - apply_damage(damage, BRUTE, affecting, armor_block) - -/mob/living/carbon/human/mech_melee_attack(obj/mecha/M) - - if(M.occupant.a_intent == "harm") - M.do_attack_animation(src) - if(M.damtype == "brute") - step_away(src,M,15) - var/obj/item/bodypart/temp = get_bodypart(pick("chest", "chest", "chest", "head")) - if(temp) - var/update = 0 - switch(M.damtype) - if("brute") - if(M.force > 20) - Paralyse(1) - update |= temp.take_damage(rand(M.force/2, M.force), 0) - playsound(src, 'sound/weapons/punch4.ogg', 50, 1) - if("fire") - update |= temp.take_damage(0, rand(M.force/2, M.force)) - playsound(src, 'sound/items/Welder.ogg', 50, 1) - if("tox") - M.mech_toxin_damage(src) + if(bleed_rate) + src << "You are bleeding!" + if(staminaloss) + if(staminaloss > 30) + src << "You're completely exhausted." else - return - if(update) - update_damage_overlays(0) - updatehealth() + src << "You feel fatigued." + else + if(wear_suit) + wear_suit.add_fingerprint(M) + else if(w_uniform) + w_uniform.add_fingerprint(M) - visible_message("[M.name] has hit [src]!", \ - "[M.name] has hit [src]!") - add_logs(M.occupant, src, "attacked", M, "(INTENT: [uppertext(M.occupant.a_intent)]) (DAMTYPE: [uppertext(M.damtype)])") - - else - ..() - -/mob/living/carbon/human/hitby(atom/movable/AM, skipcatch = 0, hitpush = 1, blocked = 0) - var/obj/item/I - var/throwpower = 30 - if(istype(AM, /obj/item)) - I = AM - throwpower = I.throwforce - if(I.thrownby == src) //No throwing stuff at yourself to trigger hit reactions - return ..() - if(check_shields(throwpower, "\the [AM.name]", AM, THROWN_PROJECTILE_ATTACK)) - hitpush = 0 - skipcatch = 1 - blocked = 1 - else if(I) - if(I.throw_speed >= EMBED_THROWSPEED_THRESHOLD) - if(can_embed(I)) - if(prob(I.embed_chance) && !(dna && (PIERCEIMMUNE in dna.species.specflags))) - throw_alert("embeddedobject", /obj/screen/alert/embeddedobject) - var/obj/item/bodypart/L = pick(bodyparts) - L.embedded_objects |= I - I.add_mob_blood(src)//it embedded itself in you, of course it's bloody! - I.loc = src - L.take_damage(I.w_class*I.embedded_impact_pain_multiplier) - visible_message("\the [I.name] embeds itself in [src]'s [L.name]!","\the [I.name] embeds itself in your [L.name]!") - hitpush = 0 - skipcatch = 1 //can't catch the now embedded item - - return ..() - -/mob/living/carbon/human/grabbedby(mob/living/carbon/user, supress_message = 0) - if(user == src && pulling && !pulling.anchored && grab_state >= GRAB_AGGRESSIVE && (disabilities & FAT) && ismonkey(pulling)) - devour_mob(pulling) - else - ..() - -/mob/living/carbon/human/grippedby(mob/living/user) - if(w_uniform) - w_uniform.add_fingerprint(user) - ..() - -/mob/living/carbon/human/Stun(amount, updating_canmove = 1) - amount = dna.species.spec_stun(src,amount) - ..() \ No newline at end of file + ..() diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index 2bccce619fa1..abf9dffc00c9 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -30,11 +30,7 @@ var/global/default_martial_art = new/datum/martial_art //Equipment slots var/obj/item/wear_suit = null var/obj/item/w_uniform = null - var/obj/item/shoes = null var/obj/item/belt = null - var/obj/item/gloves = null - var/obj/item/clothing/glasses/glasses = null - var/obj/item/ears = null var/obj/item/wear_id = null var/obj/item/r_store = null var/obj/item/l_store = null @@ -53,5 +49,3 @@ var/global/default_martial_art = new/datum/martial_art var/drunkenness = 0 //Overall drunkenness - check handle_alcohol() in life.dm for effects var/datum/personal_crafting/handcrafting - - var/list/hand_bodyparts = list() //a collection of arms (or actually whatever the fug /bodyparts you monsters use to wreck my systems) \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm index 69863d41b9b4..984260604620 100644 --- a/code/modules/mob/living/carbon/human/human_helpers.dm +++ b/code/modules/mob/living/carbon/human/human_helpers.dm @@ -81,24 +81,6 @@ if(wear_id) return wear_id.GetID() -///checkeyeprot() -///Returns a number between -1 to 2 -/mob/living/carbon/human/check_eye_prot() - var/number = ..() - if(istype(src.head, /obj/item/clothing/head)) //are they wearing something on their head - var/obj/item/clothing/head/HFP = src.head //if yes gets the flash protection value from that item - number += HFP.flash_protect - if(istype(src.glasses, /obj/item/clothing/glasses)) //glasses - var/obj/item/clothing/glasses/GFP = src.glasses - number += GFP.flash_protect - if(istype(src.wear_mask, /obj/item/clothing/mask)) //mask - var/obj/item/clothing/mask/MFP = src.wear_mask - number += MFP.flash_protect - return number - -/mob/living/carbon/human/check_ear_prot() - if((ears && (ears.flags & EARBANGPROTECT)) || (head && (head.flags & HEADBANGPROTECT))) - return 1 /mob/living/carbon/human/abiotic(full_body = 0) var/abiotic_hands = FALSE diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm index cf9504df7102..3283e04d22ee 100644 --- a/code/modules/mob/living/carbon/human/inventory.dm +++ b/code/modules/mob/living/carbon/human/inventory.dm @@ -200,7 +200,16 @@ //Cycles through all clothing slots and tests them for destruction -/mob/living/carbon/human/proc/shred_clothing(bomb,shock) +/mob/living/carbon/proc/shred_clothing(bomb,shock) + if(back) + back.shred(bomb,shock-20,src) + if(head) + head.shred(bomb,shock,src) + if(wear_mask) + wear_mask.shred(bomb,shock,src) + + +/mob/living/carbon/human/shred_clothing(bomb,shock) var/covered_parts = 0 //The body parts that are protected by exterior clothing/armor var/head_absorbed = 0 //How much of the shock the headgear absorbs when it is shredded. -1=it survives var/suit_absorbed = 0 //How much of the shock the exosuit absorbs when it is shredded. -1=it survives diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 619e9a7e139d..852a19fd1ab2 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -54,7 +54,7 @@ var/punchdamagehigh = 9 //highest possible punch damage var/punchstunthreshold = 9//damage at which punches from this race will stun //yes it should be to the attacked race but it's not useful that way even if it's logical var/siemens_coeff = 1 //base electrocution coefficient - var/exotic_damage_overlay = "" + var/damage_overlay_type = "human" //what kind of damage overlays (if any) appear on our species when wounded? var/fixed_mut_color = "" //to use MUTCOLOR with a fixed color that's independent of dna.feature["mcolor"] var/invis_sight = SEE_INVISIBLE_LIVING @@ -132,8 +132,6 @@ var/obj/item/thing = C.get_item_by_slot(slot_id) if(thing && (!thing.species_exception || !is_type_in_list(src,thing.species_exception))) C.unEquip(thing) - if(NODISMEMBER in specflags) - C.regenerate_limbs() //if we don't handle dismemberment, we grow our missing limbs back var/obj/item/organ/heart/heart = C.getorganslot("heart") var/obj/item/organ/lungs/lungs = C.getorganslot("lungs") @@ -226,7 +224,8 @@ hair_hidden = 1 if(!hair_hidden) if(!H.getorgan(/obj/item/organ/brain)) //Applies the debrained overlay if there is no brain - standing += image("icon"='icons/mob/human_face.dmi', "icon_state" = "debrained_s", "layer" = -HAIR_LAYER) + if(!(NOBLOOD in specflags)) + standing += image("icon"='icons/mob/human_face.dmi', "icon_state" = "debrained_s", "layer" = -HAIR_LAYER) else if(H.hair_style && (HAIR in specflags)) S = hair_styles_list[H.hair_style] @@ -263,17 +262,18 @@ var/obj/item/bodypart/head/HD = H.get_bodypart("head") - // lipstick - if(H.lip_style && (LIPS in specflags) && HD) - var/image/lips = image("icon"='icons/mob/human_face.dmi', "icon_state"="lips_[H.lip_style]_s", "layer" = -BODY_LAYER) - lips.color = H.lip_color - standing += lips + if(!(H.disabilities & HUSK)) + // lipstick + if(H.lip_style && (LIPS in specflags) && HD) + var/image/lips = image("icon"='icons/mob/human_face.dmi', "icon_state"="lips_[H.lip_style]_s", "layer" = -BODY_LAYER) + lips.color = H.lip_color + standing += lips - // eyes - if((EYECOLOR in specflags) && HD) - var/image/img_eyes_s = image("icon" = 'icons/mob/human_face.dmi', "icon_state" = "[eyes]_s", "layer" = -BODY_LAYER) - img_eyes_s.color = "#" + H.eye_color - standing += img_eyes_s + // eyes + if((EYECOLOR in specflags) && HD) + var/image/img_eyes_s = image("icon" = 'icons/mob/human_face.dmi', "icon_state" = "[eyes]_s", "layer" = -BODY_LAYER) + img_eyes_s.color = "#" + H.eye_color + standing += img_eyes_s //Underwear, Undershirts & Socks if(H.underwear) @@ -346,19 +346,19 @@ bodyparts_to_add -= "waggingspines" if("snout" in mutant_bodyparts) //Take a closer look at that snout! - if((H.wear_mask && (H.wear_mask.flags_inv & HIDEFACE)) || (H.head && (H.head.flags_inv & HIDEFACE)) || !HD || HD.status == ORGAN_ROBOTIC) + if((H.wear_mask && (H.wear_mask.flags_inv & HIDEFACE)) || (H.head && (H.head.flags_inv & HIDEFACE)) || !HD || HD.status == BODYPART_ROBOTIC) bodyparts_to_add -= "snout" if("frills" in mutant_bodyparts) - if(!H.dna.features["frills"] || H.dna.features["frills"] == "None" || H.head && (H.head.flags_inv & HIDEEARS) || !HD || HD.status == ORGAN_ROBOTIC) + if(!H.dna.features["frills"] || H.dna.features["frills"] == "None" || H.head && (H.head.flags_inv & HIDEEARS) || !HD || HD.status == BODYPART_ROBOTIC) bodyparts_to_add -= "frills" if("horns" in mutant_bodyparts) - if(!H.dna.features["horns"] || H.dna.features["horns"] == "None" || H.head && (H.head.flags_inv & HIDEHAIR) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEHAIR)) || !HD || HD.status == ORGAN_ROBOTIC) + if(!H.dna.features["horns"] || H.dna.features["horns"] == "None" || H.head && (H.head.flags_inv & HIDEHAIR) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEHAIR)) || !HD || HD.status == BODYPART_ROBOTIC) bodyparts_to_add -= "horns" if("ears" in mutant_bodyparts) - if(!H.dna.features["ears"] || H.dna.features["ears"] == "None" || H.head && (H.head.flags_inv & HIDEHAIR) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEHAIR)) || !HD || HD.status == ORGAN_ROBOTIC) + if(!H.dna.features["ears"] || H.dna.features["ears"] == "None" || H.head && (H.head.flags_inv & HIDEHAIR) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEHAIR)) || !HD || HD.status == BODYPART_ROBOTIC) bodyparts_to_add -= "ears" if("wings" in mutant_bodyparts) @@ -830,7 +830,7 @@ if(75 to 100) if(prob(1)) H << "You mutate!" - randmutb(H) + H.randmutb() H.emote("gasp") H.domutcheck() return 0 @@ -894,13 +894,6 @@ if(H.bodytemperature < BODYTEMP_COLD_DAMAGE_LIMIT) . += (BODYTEMP_COLD_DAMAGE_LIMIT - H.bodytemperature) / COLD_SLOWDOWN_FACTOR - if(!(FLYING in specflags)) - var/leg_amount = H.get_num_legs() - . += 6 - 3*leg_amount //the fewer the legs, the slower the mob - if(!leg_amount) - . += 6 - 3*H.get_num_arms() //crawling is harder with fewer arms - - . += speedmod ////////////////// @@ -1027,10 +1020,9 @@ "[M] attemped to disarm [H]!") return -/datum/species/proc/spec_attacked_by(obj/item/I, mob/living/user, obj/item/bodypart/affecting, intent, target_area, mob/living/carbon/human/H) +/datum/species/proc/spec_attacked_by(obj/item/I, mob/living/user, obj/item/bodypart/affecting, intent, mob/living/carbon/human/H) // Allows you to put in item-specific reactions based on species if(user != H) - user.do_attack_animation(H) if(H.check_shields(I.force, "the [I.name]", I, MELEE_ATTACK, I.armour_penetration)) return 0 @@ -1062,7 +1054,7 @@ var/bloody = 0 if(((I.damtype == BRUTE) && I.force && prob(25 + (I.force * 2)))) - if(affecting.status == ORGAN_ORGANIC) + if(affecting.status == BODYPART_ORGANIC) I.add_mob_blood(H) //Make the weapon bloody, not the person. if(prob(I.force * 2)) //blood spatter! bloody = 1 @@ -1112,39 +1104,43 @@ return TRUE /datum/species/proc/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked, mob/living/carbon/human/H) - blocked = (100-(blocked+armor))/100 - if(!damage || blocked <= 0) + var/hit_percent = (100-(blocked+armor))/100 + if(!damage || hit_percent <= 0) return 0 - var/obj/item/bodypart/organ = null + var/obj/item/bodypart/BP = null if(islimb(def_zone)) - organ = def_zone + BP = def_zone else if(!def_zone) def_zone = ran_zone(def_zone) - organ = H.get_bodypart(check_zone(def_zone)) - if(!organ) - return 0 - - damage = (damage * blocked) + BP = H.get_bodypart(check_zone(def_zone)) + if(!BP) + BP = H.bodyparts[1] switch(damagetype) if(BRUTE) H.damageoverlaytemp = 20 - if(organ.take_damage(damage*brutemod, 0)) - H.update_damage_overlays(0) + if(BP) + if(BP.take_damage(damage * hit_percent * brutemod, 0)) + H.update_damage_overlays() + else//no bodypart, we deal damage with a more general method. + H.adjustBruteLoss(damage * hit_percent * brutemod) if(BURN) H.damageoverlaytemp = 20 - if(organ.take_damage(0, damage*burnmod)) - H.update_damage_overlays(0) + if(BP) + if(BP.take_damage(0, damage * hit_percent * burnmod)) + H.update_damage_overlays() + else + H.adjustFireLoss(damage * hit_percent* burnmod) if(TOX) - H.adjustToxLoss(damage) + H.adjustToxLoss(damage * hit_percent) if(OXY) - H.adjustOxyLoss(damage) + H.adjustOxyLoss(damage * hit_percent) if(CLONE) - H.adjustCloneLoss(damage) + H.adjustCloneLoss(damage * hit_percent) if(STAMINA) - H.adjustStaminaLoss(damage) + H.adjustStaminaLoss(damage * hit_percent) return 1 /datum/species/proc/on_hit(obj/item/projectile/proj_type, mob/living/carbon/human/H) diff --git a/code/modules/mob/living/carbon/human/species_types.dm b/code/modules/mob/living/carbon/human/species_types.dm index 9677c1b0bfcd..c3e0bc205e1d 100644 --- a/code/modules/mob/living/carbon/human/species_types.dm +++ b/code/modules/mob/living/carbon/human/species_types.dm @@ -146,9 +146,9 @@ H.Weaken(5) H.visible_message("[H] writhes in pain as \his vacuoles boil.", "You writhe in pain as your vacuoles boil!", "You hear the crunching of leaves.") if(prob(80)) - randmutb(H) + H.randmutb() else - randmutg(H) + H.randmutg() H.domutcheck() else H.adjustFireLoss(rand(5,15)) @@ -642,6 +642,7 @@ meat = /obj/item/weapon/reagent_containers/food/snacks/meat/slab/human/mutant/skeleton specflags = list(NOBREATH,RESISTTEMP,NOBLOOD,RADIMMUNE,VIRUSIMMUNE,PIERCEIMMUNE,NOHUNGER,EASYDISMEMBER,EASYLIMBATTACHMENT) mutant_organs = list(/obj/item/organ/tongue/bone) + damage_overlay_type = ""//let's not show bloody wounds or burns over bones. /* ZOMBIES @@ -730,6 +731,7 @@ var/global/image/plasmaman_on_fire = image("icon"='icons/mob/OnFire.dmi', "icon_ burnmod = 2 heatmod = 2 speedmod = 1 + damage_overlay_type = ""//let's not show bloody wounds or burns over bones. /datum/species/plasmaman/spec_life(mob/living/carbon/human/H) var/datum/gas_mixture/environment = H.loc.return_air() @@ -781,7 +783,7 @@ var/global/image/plasmaman_on_fire = image("icon"='icons/mob/OnFire.dmi', "icon_ dangerous_existence = 1 blacklisted = 1 meat = null - exotic_damage_overlay = "synth" + damage_overlay_type = "synth" limbs_id = "synth" var/list/initial_specflags = list(NOTRANSSTING,NOBREATH,VIRUSIMMUNE,NODISMEMBER,NOHUNGER) //for getting these values back for assume_disguise() var/disguise_fail_health = 75 //When their health gets to this level their synthflesh partially falls off diff --git a/code/modules/mob/living/carbon/human/status_procs.dm b/code/modules/mob/living/carbon/human/status_procs.dm new file mode 100644 index 000000000000..adcf57433c41 --- /dev/null +++ b/code/modules/mob/living/carbon/human/status_procs.dm @@ -0,0 +1,15 @@ + +/mob/living/carbon/human/Stun(amount, updating = 1, ignore_canstun = 0) + amount = dna.species.spec_stun(src,amount) + ..() + + +/mob/living/carbon/human/cure_husk() + . = ..() + if(.) + update_hair() + +/mob/living/carbon/human/become_husk() + . = ..() + if(.) + update_hair() \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index cb7289a7ef5b..4bbde09513de 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -48,28 +48,6 @@ There are several things that need to be remembered: */ -//DAMAGE OVERLAYS -//constructs damage icon for each organ from mask * damage field and saves it in our overlays_ lists -/mob/living/carbon/human/update_damage_overlays() - remove_overlay(DAMAGE_LAYER) - - var/image/standing = image("icon"='icons/mob/dam_human.dmi', "icon_state"="blank", "layer"=-DAMAGE_LAYER) - overlays_standing[DAMAGE_LAYER] = standing - - var/dmgoverlaytype = "" - if(dna.species.exotic_damage_overlay) - dmgoverlaytype = dna.species.exotic_damage_overlay + "_" - - for(var/X in bodyparts) - var/obj/item/bodypart/BP = X - if(BP.brutestate) - standing.overlays += "[dmgoverlaytype][BP.body_zone]_[BP.brutestate]0" //we're adding icon_states of the base image as overlays - if(BP.burnstate) - standing.overlays += "[dmgoverlaytype][BP.body_zone]_0[BP.burnstate]" - - apply_overlay(DAMAGE_LAYER) - - //HAIR OVERLAY /mob/living/carbon/human/update_hair() dna.species.handle_hair(src) @@ -79,47 +57,14 @@ There are several things that need to be remembered: dna.species.handle_mutant_bodyparts(src) -/mob/living/carbon/human/proc/update_body() +/mob/living/carbon/human/update_body() remove_overlay(BODY_LAYER) dna.species.handle_body(src) - update_body_parts() + ..() /mob/living/carbon/human/update_fire() ..("Standing") -/mob/living/carbon/human/proc/update_body_parts() - //CHECK FOR UPDATE - var/oldkey = icon_render_key - icon_render_key = generate_icon_render_key() - if(oldkey == icon_render_key) - return - - remove_overlay(BODYPARTS_LAYER) - - //LOAD ICONS - if(limb_icon_cache[icon_render_key]) - load_limb_from_cache() - update_damage_overlays() - update_mutant_bodyparts() - update_hair() - return - - //GENERATE NEW LIMBS - var/list/new_limbs = list() - for(var/X in bodyparts) - var/obj/item/bodypart/BP = X - if(!BP.no_update) - BP.update_limb() - var/image/temp = BP.get_limb_icon() - if(temp) - new_limbs += temp - if(new_limbs.len) - overlays_standing[BODYPARTS_LAYER] = new_limbs - limb_icon_cache[icon_render_key] = new_limbs - - apply_overlay(BODYPARTS_LAYER) - update_damage_overlays() - /* --------------------------------------- */ //For legacy support. @@ -219,9 +164,16 @@ There are several things that need to be remembered: remove_overlay(GLOVES_LAYER) if(get_num_arms() <2) + if(!gloves && blood_DNA) + if(has_left_hand()) + overlays_standing[GLOVES_LAYER] = image("icon"='icons/effects/blood.dmi', "icon_state"="bloodyhands_left", "layer"=-GLOVES_LAYER) + apply_overlay(GLOVES_LAYER) + else if(has_right_hand()) + overlays_standing[GLOVES_LAYER] = image("icon"='icons/effects/blood.dmi', "icon_state"="bloodyhands_right", "layer"=-GLOVES_LAYER) + apply_overlay(GLOVES_LAYER) return - if(client && hud_used) + if(client && hud_used && hud_used.inv_slots[slot_gloves]) var/obj/screen/inventory/inv = hud_used.inv_slots[slot_gloves] inv.update_icon() @@ -246,7 +198,6 @@ There are several things that need to be remembered: apply_overlay(GLOVES_LAYER) - /mob/living/carbon/human/update_inv_glasses() remove_overlay(GLASSES_LAYER) @@ -336,19 +287,10 @@ There are several things that need to be remembered: apply_overlay(SUIT_STORE_LAYER) - /mob/living/carbon/human/update_inv_head() - remove_overlay(HEAD_LAYER) - if(!get_bodypart("head")) //Decapitated - return ..() - if(client && hud_used) - var/obj/screen/inventory/inv = hud_used.inv_slots[slot_head] - inv.update_icon() - update_mutant_bodyparts() - /mob/living/carbon/human/update_inv_belt() remove_overlay(BELT_LAYER) @@ -382,16 +324,16 @@ There are several things that need to be remembered: inv.update_icon() if(istype(wear_suit, /obj/item/clothing/suit)) - wear_suit.screen_loc = ui_oclothing //TODO //Todo what? + wear_suit.screen_loc = ui_oclothing if(client && hud_used && hud_used.hud_shown) - if(hud_used.inventory_shown) //if the inventory is open ... - client.screen += wear_suit //Either way, add the item to the HUD + if(hud_used.inventory_shown) + client.screen += wear_suit update_observer_view(wear_suit,1) var/image/standing = wear_suit.build_worn_icon(state = wear_suit.icon_state, default_layer = SUIT_LAYER, default_icon_file = 'icons/mob/suit.dmi') overlays_standing[SUIT_LAYER] = standing - if(istype(wear_suit, /obj/item/clothing/suit/straight_jacket)) + if(wear_suit.breakouttime) //suit is restraining drop_all_held_items() update_hair() @@ -423,22 +365,10 @@ There are several things that need to be remembered: update_observer_view(r_store) - /mob/living/carbon/human/update_inv_wear_mask() - remove_overlay(FACEMASK_LAYER) - if(!get_bodypart("head")) //Decapitated - return ..() - if(client && hud_used) - var/obj/screen/inventory/inv = hud_used.inv_slots[slot_wear_mask] - inv.update_icon() - update_mutant_bodyparts() + update_mutant_bodyparts() //e.g. upgate needed because mask now hides lizard snout -/mob/living/carbon/human/update_inv_handcuffed() - remove_overlay(HANDCUFF_LAYER) - if(handcuffed) - overlays_standing[HANDCUFF_LAYER] = image("icon"='icons/mob/mob.dmi', "icon_state"="handcuff1", "layer"=-HANDCUFF_LAYER) - apply_overlay(HANDCUFF_LAYER) /mob/living/carbon/human/update_inv_legcuffed() remove_overlay(LEGCUFF_LAYER) @@ -492,6 +422,8 @@ There are several things that need to be remembered: update_observer_view(I) + + /* Does everything in relation to building the /image used in the mob's overlays list covers: @@ -581,31 +513,8 @@ generate/load female uniform sprites matching all previously decided variables - - - -///////////////////// -// Limb Icon Cache // -///////////////////// -/* - Called from update_body_parts() these procs handle the limb icon cache. - the limb icon cache adds an icon_render_key to a human mob, it represents: - - skin_tone (if applicable) - - gender - - limbs (stores as the limb name and whether it is removed/fine, organic/robotic) - These procs only store limbs as to increase the number of matching icon_render_keys - This cache exists because drawing 6/7 icons for humans constantly is quite a waste - See RemieRichards on irc.rizon.net #coderbus -*/ - -var/global/list/limb_icon_cache = list() - -/mob/living/carbon/human - var/icon_render_key = "" - - //produces a key based on the human's limbs -/mob/living/carbon/human/proc/generate_icon_render_key() +/mob/living/carbon/human/generate_icon_render_key() . = "[dna.species.limbs_id]" if(dna.check_mutation(HULK)) @@ -624,7 +533,7 @@ var/global/list/limb_icon_cache = list() for(var/X in bodyparts) var/obj/item/bodypart/BP = X . += "-[BP.body_zone]" - if(BP.status == ORGAN_ORGANIC) + if(BP.status == BODYPART_ORGANIC) . += "-organic" else . += "-robotic" @@ -632,16 +541,14 @@ var/global/list/limb_icon_cache = list() if(disabilities & HUSK) . += "-husk" - -//change the human's icon to the one matching it's key -/mob/living/carbon/human/proc/load_limb_from_cache() - if(limb_icon_cache[icon_render_key]) - remove_overlay(BODYPARTS_LAYER) - overlays_standing[BODYPARTS_LAYER] = limb_icon_cache[icon_render_key] - apply_overlay(BODYPARTS_LAYER) +/mob/living/carbon/human/load_limb_from_cache() + ..() + update_mutant_bodyparts() + update_hair() -/mob/living/carbon/human/proc/update_observer_view(var/obj/item/I,var/inventory) + +/mob/living/carbon/human/proc/update_observer_view(obj/item/I, inventory) if(observers && observers.len) for(var/M in observers) var/mob/dead/observe = M diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index 2f4ca6da1191..aa701d7f1b38 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -14,7 +14,8 @@ handle_blood() - for(var/obj/item/organ/O in internal_organs) + for(var/X in internal_organs) + var/obj/item/organ/O = X O.on_life() //Updates the number of stored chemicals for powers diff --git a/code/modules/mob/living/carbon/monkey/life.dm b/code/modules/mob/living/carbon/monkey/life.dm index d3e541143b03..3e87fa5c1ab9 100644 --- a/code/modules/mob/living/carbon/monkey/life.dm +++ b/code/modules/mob/living/carbon/monkey/life.dm @@ -39,7 +39,7 @@ if(75 to 100) if(prob(1)) src << "You mutate!" - randmutb(src) + randmutb() emote("gasp") domutcheck() ..() @@ -83,29 +83,29 @@ switch(bodytemperature) if(360 to 400) throw_alert("temp", /obj/screen/alert/hot, 1) - adjustFireLoss(2) + apply_damage(HEAT_DAMAGE_LEVEL_1, BURN) if(400 to 460) throw_alert("temp", /obj/screen/alert/hot, 2) - adjustFireLoss(3) + apply_damage(HEAT_DAMAGE_LEVEL_2, BURN) if(460 to INFINITY) throw_alert("temp", /obj/screen/alert/hot, 3) if(on_fire) - adjustFireLoss(8) + apply_damage(HEAT_DAMAGE_LEVEL_3, BURN) else - adjustFireLoss(3) + apply_damage(HEAT_DAMAGE_LEVEL_2, BURN) else if(bodytemperature < BODYTEMP_COLD_DAMAGE_LIMIT) if(!istype(loc, /obj/machinery/atmospherics/components/unary/cryo_cell)) switch(bodytemperature) if(200 to 260) throw_alert("temp", /obj/screen/alert/cold, 1) - adjustFireLoss(0.5) + apply_damage(COLD_DAMAGE_LEVEL_1, BURN) if(120 to 200) throw_alert("temp", /obj/screen/alert/cold, 2) - adjustFireLoss(1.5) + apply_damage(COLD_DAMAGE_LEVEL_2, BURN) if(-INFINITY to 120) throw_alert("temp", /obj/screen/alert/cold, 3) - adjustFireLoss(3) + apply_damage(COLD_DAMAGE_LEVEL_3, BURN) else clear_alert("temp") diff --git a/code/modules/mob/living/carbon/monkey/monkey.dm b/code/modules/mob/living/carbon/monkey/monkey.dm index 6ae41f3c8592..33cbce3edb14 100644 --- a/code/modules/mob/living/carbon/monkey/monkey.dm +++ b/code/modules/mob/living/carbon/monkey/monkey.dm @@ -3,7 +3,7 @@ voice_name = "monkey" verb_say = "chimpers" icon = 'icons/mob/monkey.dmi' - icon_state = "monkey1" + icon_state = "" gender = NEUTER pass_flags = PASSTABLE languages_spoken = MONKEY @@ -13,6 +13,10 @@ type_of_meat = /obj/item/weapon/reagent_containers/food/snacks/meat/slab/monkey gib_type = /obj/effect/decal/cleanable/blood/gibs unique_name = 1 + bodyparts = list(/obj/item/bodypart/chest/monkey, /obj/item/bodypart/head/monkey, /obj/item/bodypart/l_arm/monkey, + /obj/item/bodypart/r_arm/monkey, /obj/item/bodypart/r_leg/monkey, /obj/item/bodypart/l_leg/monkey) + + /mob/living/carbon/monkey/New() verbs += /mob/living/proc/mob_sleep @@ -22,24 +26,13 @@ gender = pick(MALE, FEMALE) real_name = name - //initialize limbs, currently only used to handle cavity implant surgery, no dismemberment. - bodyparts = newlist(/obj/item/bodypart/chest, /obj/item/bodypart/head, /obj/item/bodypart/l_arm, - /obj/item/bodypart/r_arm, /obj/item/bodypart/r_leg, /obj/item/bodypart/l_leg) - for(var/X in bodyparts) - var/obj/item/bodypart/O = X - O.owner = src + //initialize limbs + create_bodyparts() if(good_mutations.len) //genetic mutations have been set up. - initialize() + initialize() //initialize monkey dna - internal_organs += new /obj/item/organ/appendix - internal_organs += new /obj/item/organ/lungs - internal_organs += new /obj/item/organ/heart - internal_organs += new /obj/item/organ/brain - internal_organs += new /obj/item/organ/tongue - - for(var/obj/item/organ/I in internal_organs) - I.Insert(src) + create_internal_organs() ..() @@ -47,6 +40,15 @@ create_dna(src) dna.initialize_dna(random_blood_type()) + +/mob/living/carbon/monkey/create_internal_organs() + internal_organs += new /obj/item/organ/appendix + internal_organs += new /obj/item/organ/lungs + internal_organs += new /obj/item/organ/heart + internal_organs += new /obj/item/organ/brain + internal_organs += new /obj/item/organ/tongue + ..() + /mob/living/carbon/monkey/movement_delay() if(reagents) if(reagents.has_reagent("morphine")) @@ -64,133 +66,6 @@ . += (283.222 - bodytemperature) / 10 * 1.75 return . + config.monkey_delay -/mob/living/carbon/monkey/attack_paw(mob/living/M) - if(..()) //successful monkey bite. - var/damage = rand(1, 5) - if (stat != DEAD) - adjustBruteLoss(damage) - updatehealth() - return - -/mob/living/carbon/monkey/attack_larva(mob/living/carbon/alien/larva/L) - if(..()) //successful larva bite. - var/damage = rand(1, 3) - if(stat != DEAD) - L.amount_grown = min(L.amount_grown + damage, L.max_grown) - adjustBruteLoss(damage) - updatehealth() - -/mob/living/carbon/monkey/attack_hand(mob/living/carbon/human/M) - if(..()) //To allow surgery to return properly. - return - - switch(M.a_intent) - if("help") - help_shake_act(M) - if("grab") - grabbedby(M) - if("harm") - M.do_attack_animation(src) - if (prob(75)) - visible_message("[M] has punched [name]!", \ - "[M] has punched [name]!") - - playsound(loc, "punch", 25, 1, -1) - var/damage = rand(5, 10) - if (prob(40)) - damage = rand(10, 15) - if ( (paralysis < 5) && (health > 0) ) - Paralyse(rand(10, 15)) - visible_message("[M] has knocked out [name]!", \ - "[M] has knocked out [name]!") - adjustBruteLoss(damage) - add_logs(M, src, "attacked") - updatehealth() - else - playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) - visible_message("[M] has attempted to punch [name]!", \ - "[M] has attempted to punch [name]!") - if("disarm") - if (!( paralysis )) - M.do_attack_animation(src) - if (prob(25)) - Paralyse(2) - playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - add_logs(M, src, "pushed") - visible_message("[M] has pushed down [src]!", \ - "[M] has pushed down [src]!") - else - if(drop_item()) - playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - visible_message("[M] has disarmed [src]!", \ - "[M] has disarmed [src]!") - -/mob/living/carbon/monkey/attack_alien(mob/living/carbon/alien/humanoid/M) - if(..()) //if harm or disarm intent. - if (M.a_intent == "harm") - if ((prob(95) && health > 0)) - playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1) - var/damage = rand(15, 30) - if (damage >= 25) - damage = rand(20, 40) - if (paralysis < 15) - Paralyse(rand(10, 15)) - visible_message("[M] has wounded [name]!", \ - "[M] has wounded [name]!") - else - visible_message("[M] has slashed [name]!", \ - "[M] has slashed [name]!") - - if (stat != DEAD) - adjustBruteLoss(damage) - updatehealth() - add_logs(M, src, "attacked") - else - playsound(loc, 'sound/weapons/slashmiss.ogg', 25, 1, -1) - visible_message("[M] has attempted to lunge at [name]!", \ - "[M] has attempted to lunge at [name]!") - - if (M.a_intent == "disarm") - playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1) - if(prob(95)) - Weaken(10) - visible_message("[M] has tackled down [name]!", \ - "[M] has tackled down [name]!") - else - if(drop_item()) - visible_message("[M] has disarmed [name]!", \ - "[M] has disarmed [name]!") - add_logs(M, src, "disarmed") - updatehealth() - return - -/mob/living/carbon/monkey/attack_animal(mob/living/simple_animal/M) - if(..()) - var/damage = rand(M.melee_damage_lower, M.melee_damage_upper) - switch(M.melee_damage_type) - if(BRUTE) - adjustBruteLoss(damage) - if(BURN) - adjustFireLoss(damage) - if(TOX) - adjustToxLoss(damage) - if(OXY) - adjustOxyLoss(damage) - if(CLONE) - adjustCloneLoss(damage) - if(STAMINA) - adjustStaminaLoss(damage) - updatehealth() - - -/mob/living/carbon/monkey/attack_slime(mob/living/simple_animal/slime/M) - if(..()) //successful slime attack - var/damage = rand(5, 35) - if(M.is_adult) - damage = rand(20, 40) - adjustBruteLoss(damage) - updatehealth() - /mob/living/carbon/monkey/Stat() ..() if(statpanel("Status")) @@ -209,24 +84,6 @@ internal = null return -/mob/living/carbon/monkey/ex_act(severity, target) - ..() - switch(severity) - if(1) - gib() - return - if(2) - adjustBruteLoss(60) - adjustFireLoss(60) - adjustEarDamage(30,120) - if(3) - adjustBruteLoss(30) - if (prob(50)) - Paralyse(10) - adjustEarDamage(15,60) - - updatehealth() - return /mob/living/carbon/monkey/IsAdvancedToolUser()//Unless its monkey mode monkeys cant use advanced tools return 0 @@ -270,24 +127,6 @@ return threatcount -/mob/living/carbon/monkey/acid_act(acidpwr, toxpwr, acid_volume) - if(wear_mask) - if(!wear_mask.unacidable) - wear_mask.acid_act(acidpwr) - update_inv_wear_mask() - else - src << "Your mask protects you from the acid." - return - - take_organ_damage(min(6*toxpwr, acid_volume * acidpwr/10)) - -/mob/living/carbon/monkey/help_shake_act(mob/living/carbon/M) - if(health < 0 && ishuman(M)) - var/mob/living/carbon/human/H = M - H.do_cpr(src) - else - ..() - /mob/living/carbon/monkey/get_permeability_protection() var/protection = 0 if(head) @@ -297,13 +136,6 @@ protection = protection/7 //the rest of the body isn't covered. return protection -/mob/living/carbon/monkey/check_eye_prot() - var/number = ..() - if(istype(src.wear_mask, /obj/item/clothing/mask)) - var/obj/item/clothing/mask/MFP = src.wear_mask - number += MFP.flash_protect - return number - /mob/living/carbon/monkey/fully_heal(admin_revive = 0) if(!getorganslot("lungs")) var/obj/item/organ/lungs/L = new() diff --git a/code/modules/mob/living/carbon/monkey/monkey_defense.dm b/code/modules/mob/living/carbon/monkey/monkey_defense.dm new file mode 100644 index 000000000000..c3a1818b242d --- /dev/null +++ b/code/modules/mob/living/carbon/monkey/monkey_defense.dm @@ -0,0 +1,188 @@ + +/mob/living/carbon/monkey/get_eye_protection() + var/number = ..() + if(istype(src.wear_mask, /obj/item/clothing/mask)) + var/obj/item/clothing/mask/MFP = src.wear_mask + number += MFP.flash_protect + return number + +/mob/living/carbon/monkey/help_shake_act(mob/living/carbon/M) + if(health < 0 && ishuman(M)) + var/mob/living/carbon/human/H = M + H.do_cpr(src) + else + ..() + +/mob/living/carbon/monkey/attack_paw(mob/living/M) + if(..()) //successful monkey bite. + var/dam_zone = pick("chest", "l_hand", "r_hand", "l_leg", "r_leg") + var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone)) + if(M.limb_destroyer) + dismembering_strike(M, affecting.body_zone) + if(stat != DEAD) + apply_damage(rand(1, 5), BRUTE, affecting) + + + +/mob/living/carbon/monkey/attack_larva(mob/living/carbon/alien/larva/L) + if(..()) //successful larva bite. + var/damage = rand(1, 3) + if(stat != DEAD) + L.amount_grown = min(L.amount_grown + damage, L.max_grown) + var/obj/item/bodypart/affecting = get_bodypart(ran_zone(L.zone_selected)) + apply_damage(damage, BRUTE, affecting) + +/mob/living/carbon/monkey/attack_hand(mob/living/carbon/human/M) + if(..()) //To allow surgery to return properly. + return + + switch(M.a_intent) + if("help") + help_shake_act(M) + if("grab") + grabbedby(M) + if("harm") + M.do_attack_animation(src) + if (prob(75)) + visible_message("[M] has punched [name]!", \ + "[M] has punched [name]!") + + playsound(loc, "punch", 25, 1, -1) + var/damage = rand(5, 10) + if (prob(40)) + damage = rand(10, 15) + if ( (paralysis < 5) && (health > 0) ) + Paralyse(rand(10, 15)) + visible_message("[M] has knocked out [name]!", \ + "[M] has knocked out [name]!") + var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected)) + apply_damage(damage, BRUTE, affecting) + add_logs(M, src, "attacked") + + else + playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) + visible_message("[M] has attempted to punch [name]!", \ + "[M] has attempted to punch [name]!") + if("disarm") + if (!( paralysis )) + M.do_attack_animation(src) + if (prob(25)) + Paralyse(2) + playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + add_logs(M, src, "pushed") + visible_message("[M] has pushed down [src]!", \ + "[M] has pushed down [src]!") + else + if(drop_item()) + playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + visible_message("[M] has disarmed [src]!", \ + "[M] has disarmed [src]!") + +/mob/living/carbon/monkey/attack_alien(mob/living/carbon/alien/humanoid/M) + if(..()) //if harm or disarm intent. + if (M.a_intent == "harm") + if ((prob(95) && health > 0)) + playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1) + var/damage = rand(15, 30) + if (damage >= 25) + damage = rand(20, 40) + if (paralysis < 15) + Paralyse(rand(10, 15)) + visible_message("[M] has wounded [name]!", \ + "[M] has wounded [name]!") + else + visible_message("[M] has slashed [name]!", \ + "[M] has slashed [name]!") + + var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected)) + add_logs(M, src, "attacked") + if(!dismembering_strike(M, M.zone_selected)) //Dismemberment successful + return 1 + apply_damage(damage, BRUTE, affecting) + + else + playsound(loc, 'sound/weapons/slashmiss.ogg', 25, 1, -1) + visible_message("[M] has attempted to lunge at [name]!", \ + "[M] has attempted to lunge at [name]!") + + if (M.a_intent == "disarm") + playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1) + if(prob(95)) + Weaken(10) + visible_message("[M] has tackled down [name]!", \ + "[M] has tackled down [name]!") + else + if(drop_item()) + visible_message("[M] has disarmed [name]!", \ + "[M] has disarmed [name]!") + add_logs(M, src, "disarmed") + updatehealth() + + +/mob/living/carbon/monkey/attack_animal(mob/living/simple_animal/M) + if(..()) + var/damage = rand(M.melee_damage_lower, M.melee_damage_upper) + var/dam_zone = dismembering_strike(M, pick("chest", "l_hand", "r_hand", "l_leg", "r_leg")) + if(!dam_zone) //Dismemberment successful + return 1 + var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone)) + apply_damage(damage, M.melee_damage_type, affecting) + + + +/mob/living/carbon/monkey/attack_slime(mob/living/simple_animal/slime/M) + if(..()) //successful slime attack + var/damage = rand(5, 35) + if(M.is_adult) + damage = rand(20, 40) + var/dam_zone = dismembering_strike(M, pick("head", "chest", "l_arm", "r_arm", "l_leg", "r_leg")) + if(!dam_zone) //Dismemberment successful + return 1 + var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone)) + apply_damage(damage, BRUTE, affecting) + + +/mob/living/carbon/monkey/acid_act(acidpwr, toxpwr, acid_volume) + if(wear_mask) + if(!wear_mask.unacidable) + wear_mask.acid_act(acidpwr) + update_inv_wear_mask() + else + src << "Your mask protects you from the acid." + return + + take_bodypart_damage(min(6*toxpwr, acid_volume * acidpwr/10)) + + +/mob/living/carbon/monkey/ex_act(severity, target) + ..() + + switch (severity) + if (1) + gib() + + if (2) + take_overall_damage(60, 60) + shred_clothing(1,50) + adjustEarDamage(30, 120) + if(prob(70)) + Paralyse(10) + + if(3) + take_overall_damage(30, 0) + adjustEarDamage(15,60) + if (prob(50)) + Paralyse(8) + + + //attempt to dismember bodyparts + if(severity <= 2) + var/max_limb_loss = round(4/severity) //so you don't lose four limbs at severity 3. + for(var/X in bodyparts) + var/obj/item/bodypart/BP = X + if(prob(50/severity) && BP.body_zone != "chest") + BP.brute_dam = BP.max_damage + BP.dismember() + max_limb_loss-- + if(!max_limb_loss) + break diff --git a/code/modules/mob/living/carbon/monkey/update_icons.dm b/code/modules/mob/living/carbon/monkey/update_icons.dm index b342ace1e791..b7ca5044398d 100644 --- a/code/modules/mob/living/carbon/monkey/update_icons.dm +++ b/code/modules/mob/living/carbon/monkey/update_icons.dm @@ -1,29 +1,47 @@ /mob/living/carbon/monkey/regenerate_icons() if(!..()) + update_body_parts() + update_hair() update_inv_wear_mask() update_inv_head() update_inv_back() - update_icons() update_transform() -/mob/living/carbon/monkey/update_icons() - cut_overlays() - icon_state = "monkey1" - for(var/image/I in overlays_standing) - add_overlay(I) //////// + +/mob/living/carbon/monkey/update_hair() + remove_overlay(HAIR_LAYER) + + var/obj/item/bodypart/head/HD = get_bodypart("head") + if(!HD) //Decapitated + return + + if(disabilities & HUSK) + return + + var/hair_hidden = 0 + + if(head) + var/obj/item/I = head + if(I.flags_inv & HIDEHAIR) + hair_hidden = 1 + if(wear_mask) + var/obj/item/clothing/mask/M = wear_mask + if(M.flags_inv & HIDEHAIR) + hair_hidden = 1 + if(!hair_hidden) + if(!getorgan(/obj/item/organ/brain)) //Applies the debrained overlay if there is no brain + var/image/I = image("icon"='icons/mob/human_face.dmi', "icon_state" = "debrained_s", "layer" = -HAIR_LAYER) + overlays_standing[HAIR_LAYER] = I + apply_overlay(HAIR_LAYER) + + /mob/living/carbon/monkey/update_fire() ..("Monkey_burning") -/mob/living/carbon/monkey/update_inv_handcuffed() - remove_overlay(HANDCUFF_LAYER) - if(handcuffed) - overlays_standing[HANDCUFF_LAYER] = image("icon"='icons/mob/mob.dmi', "icon_state"="handcuff1", "layer"=-HANDCUFF_LAYER) - apply_overlay(HANDCUFF_LAYER) - /mob/living/carbon/monkey/update_inv_legcuffed() remove_overlay(LEGCUFF_LAYER) if(legcuffed) diff --git a/code/modules/mob/living/carbon/status_procs.dm b/code/modules/mob/living/carbon/status_procs.dm index 24c9305aa157..abfe312c48b1 100644 --- a/code/modules/mob/living/carbon/status_procs.dm +++ b/code/modules/mob/living/carbon/status_procs.dm @@ -1,6 +1,6 @@ //Here are the procs used to modify status effects of a mob. //The effects include: stunned, weakened, paralysis, sleeping, resting, jitteriness, dizziness, ear damage, -// eye damage, eye_blind, eye_blurry, druggy, BLIND disability, and NEARSIGHT disability. +// eye damage, eye_blind, eye_blurry, druggy, BLIND disability, NEARSIGHT disability, and HUSK disability. /mob/living/carbon/damage_eyes(amount) if(amount>0) @@ -76,4 +76,19 @@ if(!(disabilities & NEARSIGHT)) disabilities |= NEARSIGHT overlay_fullscreen("nearsighted", /obj/screen/fullscreen/impaired, 1) - return 1 \ No newline at end of file + return 1 + +/mob/living/carbon/cure_husk() + if(disabilities & HUSK) + disabilities &= ~HUSK + status_flags &= ~DISFIGURED + update_body() + return 1 + +/mob/living/carbon/become_husk() + if(disabilities & HUSK) + return + disabilities |= HUSK + status_flags |= DISFIGURED //makes them unknown + update_body() + return 1 diff --git a/code/modules/mob/living/carbon/update_icons.dm b/code/modules/mob/living/carbon/update_icons.dm index 05f410fafe29..dcd5b1a59b2c 100644 --- a/code/modules/mob/living/carbon/update_icons.dm +++ b/code/modules/mob/living/carbon/update_icons.dm @@ -40,10 +40,18 @@ overlays -= overlays_standing[cache_index] overlays_standing[cache_index] = null +/mob/living/carbon/regenerate_icons() + if(notransform) + return 1 + update_inv_hands() + update_inv_handcuffed() + update_inv_legcuffed() + update_fire() + /mob/living/carbon/update_inv_hands() remove_overlay(HANDS_LAYER) - if(handcuffed) + if (handcuffed) drop_all_held_items() return @@ -85,23 +93,44 @@ apply_overlay(FIRE_LAYER) -/mob/living/carbon/regenerate_icons() - if(notransform) - return 1 - update_inv_hands() - update_inv_handcuffed() - update_inv_legcuffed() - update_fire() + + +/mob/living/carbon/update_damage_overlays() + remove_overlay(DAMAGE_LAYER) + + var/image/standing = image("icon"='icons/mob/dam_mob.dmi', "icon_state"="blank", "layer"=-DAMAGE_LAYER) + overlays_standing[DAMAGE_LAYER] = standing + + for(var/X in bodyparts) + var/obj/item/bodypart/BP = X + if(BP.dmg_overlay_type) + if(BP.brutestate) + standing.overlays += "[BP.dmg_overlay_type]_[BP.body_zone]_[BP.brutestate]0" //we're adding icon_states of the base image as overlays + if(BP.burnstate) + standing.overlays += "[BP.dmg_overlay_type]_[BP.body_zone]_0[BP.burnstate]" + + apply_overlay(DAMAGE_LAYER) + /mob/living/carbon/update_inv_wear_mask() remove_overlay(FACEMASK_LAYER) - if(istype(wear_mask, /obj/item/clothing/mask)) + + if(!get_bodypart("head")) //Decapitated + return + + if(client && hud_used && hud_used.inv_slots[slot_wear_mask]) + var/obj/screen/inventory/inv = hud_used.inv_slots[slot_wear_mask] + inv.update_icon() + + if(wear_mask) if(!(head && (head.flags_inv & HIDEMASK))) var/image/standing = wear_mask.build_worn_icon(state = wear_mask.icon_state, default_layer = FACEMASK_LAYER, default_icon_file = 'icons/mob/mask.dmi') overlays_standing[FACEMASK_LAYER] = standing update_hud_wear_mask(wear_mask) + apply_overlay(FACEMASK_LAYER) + /mob/living/carbon/update_inv_back() remove_overlay(BACK_LAYER) @@ -117,14 +146,27 @@ /mob/living/carbon/update_inv_head() remove_overlay(HEAD_LAYER) + + if(!get_bodypart("head")) //Decapitated + return + + if(client && hud_used && hud_used.inv_slots[slot_back]) + var/obj/screen/inventory/inv = hud_used.inv_slots[slot_head] + inv.update_icon() + if(head) var/image/standing = head.build_worn_icon(state = head.icon_state, default_layer = HEAD_LAYER, default_icon_file = 'icons/mob/head.dmi') overlays_standing[HEAD_LAYER] = standing update_hud_head(head) + apply_overlay(HEAD_LAYER) + /mob/living/carbon/update_inv_handcuffed() - return + remove_overlay(HANDCUFF_LAYER) + if(handcuffed) + overlays_standing[HANDCUFF_LAYER] = image("icon"='icons/mob/mob.dmi', "icon_state"="handcuff1", "layer"=-HANDCUFF_LAYER) + apply_overlay(HANDCUFF_LAYER) //mob HUD updates for items in our inventory @@ -150,12 +192,92 @@ return + //Overlays for the worn overlay so you can overlay while you overlay //eg: ammo counters, primed grenade flashing, etc. -/obj/item/proc/worn_overlays(var/isinhands = FALSE) +/obj/item/proc/worn_overlays(isinhands = FALSE) . = list() +/mob/living/carbon/update_body() + update_body_parts() + +/mob/living/carbon/proc/update_body_parts() + //CHECK FOR UPDATE + var/oldkey = icon_render_key + icon_render_key = generate_icon_render_key() + if(oldkey == icon_render_key) + return + + remove_overlay(BODYPARTS_LAYER) + + for(var/X in bodyparts) + var/obj/item/bodypart/BP = X + if(!BP.no_update) + BP.update_limb() + + //LOAD ICONS + if(limb_icon_cache[icon_render_key]) + load_limb_from_cache() + return + + //GENERATE NEW LIMBS + var/list/new_limbs = list() + for(var/X in bodyparts) + var/obj/item/bodypart/BP = X + var/image/temp = BP.get_limb_icon() + if(temp) + new_limbs += temp + if(new_limbs.len) + overlays_standing[BODYPARTS_LAYER] = new_limbs + limb_icon_cache[icon_render_key] = new_limbs + + apply_overlay(BODYPARTS_LAYER) + update_damage_overlays() +///////////////////// +// Limb Icon Cache // +///////////////////// +/* + Called from update_body_parts() these procs handle the limb icon cache. + the limb icon cache adds an icon_render_key to a human mob, it represents: + - skin_tone (if applicable) + - gender + - limbs (stores as the limb name and whether it is removed/fine, organic/robotic) + These procs only store limbs as to increase the number of matching icon_render_keys + This cache exists because drawing 6/7 icons for humans constantly is quite a waste + See RemieRichards on irc.rizon.net #coderbus +*/ + +var/global/list/limb_icon_cache = list() + +/mob/living/carbon + var/icon_render_key = "" + + +//produces a key based on the mob's limbs + +/mob/living/carbon/proc/generate_icon_render_key() + for(var/X in bodyparts) + var/obj/item/bodypart/BP = X + . += "-[BP.body_zone]" + if(BP.animal_origin) + . += "-[BP.animal_origin]" + if(BP.status == BODYPART_ORGANIC) + . += "-organic" + else + . += "-robotic" + + if(disabilities & HUSK) + . += "-husk" + + +//change the mob's icon to the one matching its key +/mob/living/carbon/proc/load_limb_from_cache() + if(limb_icon_cache[icon_render_key]) + remove_overlay(BODYPARTS_LAYER) + overlays_standing[BODYPARTS_LAYER] = limb_icon_cache[icon_render_key] + apply_overlay(BODYPARTS_LAYER) + update_damage_overlays() diff --git a/code/modules/mob/living/damage_procs.dm b/code/modules/mob/living/damage_procs.dm index 0690e8b11fd2..f0fcda0dcf9b 100644 --- a/code/modules/mob/living/damage_procs.dm +++ b/code/modules/mob/living/damage_procs.dm @@ -9,23 +9,22 @@ standard 0 if fail */ /mob/living/proc/apply_damage(damage = 0,damagetype = BRUTE, def_zone = null, blocked = 0) - blocked = (100-blocked)/100 - if(!damage || (blocked <= 0)) + var/hit_percent = (100-blocked)/100 + if(!damage || (hit_percent <= 0)) return 0 switch(damagetype) if(BRUTE) - adjustBruteLoss(damage * blocked) + adjustBruteLoss(damage * hit_percent) if(BURN) - adjustFireLoss(damage * blocked) + adjustFireLoss(damage * hit_percent) if(TOX) - adjustToxLoss(damage * blocked) + adjustToxLoss(damage * hit_percent) if(OXY) - adjustOxyLoss(damage * blocked) + adjustOxyLoss(damage * hit_percent) if(CLONE) - adjustCloneLoss(damage * blocked) + adjustCloneLoss(damage * hit_percent) if(STAMINA) - adjustStaminaLoss(damage * blocked) - updatehealth() + adjustStaminaLoss(damage * hit_percent) return 1 @@ -49,30 +48,30 @@ /mob/living/proc/apply_effect(effect = 0,effecttype = STUN, blocked = 0) - blocked = (100-blocked)/100 - if(!effect || (blocked <= 0)) + var/hit_percent = (100-blocked)/100 + if(!effect || (hit_percent <= 0)) return 0 switch(effecttype) if(STUN) - Stun(effect * blocked) + Stun(effect * hit_percent) if(WEAKEN) - Weaken(effect * blocked) + Weaken(effect * hit_percent) if(PARALYZE) - Paralyse(effect * blocked) + Paralyse(effect * hit_percent) if(IRRADIATE) - radiation += max(effect * blocked, 0) + radiation += max(effect * hit_percent, 0) if(SLUR) - slurring = max(slurring,(effect * blocked)) + slurring = max(slurring,(effect * hit_percent)) if(STUTTER) if(status_flags & CANSTUN) // stun is usually associated with stutter - stuttering = max(stuttering,(effect * blocked)) + stuttering = max(stuttering,(effect * hit_percent)) if(EYE_BLUR) - blur_eyes(effect * blocked) + blur_eyes(effect * hit_percent) if(DROWSY) - drowsyness = max(drowsyness,(effect * blocked)) + drowsyness = max(drowsyness,(effect * hit_percent)) if(JITTER) if(status_flags & CANSTUN) - jitteriness = max(jitteriness,(effect * blocked)) + jitteriness = max(jitteriness,(effect * hit_percent)) return 1 @@ -99,4 +98,128 @@ apply_damage(stamina, STAMINA, null, blocked) if(jitter) apply_effect(jitter, JITTER, blocked) - return 1 \ No newline at end of file + return 1 + + +/mob/living/proc/getBruteLoss() + return bruteloss + +/mob/living/proc/adjustBruteLoss(amount, updating_health=1) + if(status_flags & GODMODE) + return 0 + bruteloss = Clamp((bruteloss + (amount * config.damage_multiplier)), 0, maxHealth*2) + if(updating_health) + updatehealth() + +/mob/living/proc/getOxyLoss() + return oxyloss + +/mob/living/proc/adjustOxyLoss(amount, updating_health=1) + if(status_flags & GODMODE) + return 0 + oxyloss = Clamp((oxyloss + (amount * config.damage_multiplier)), 0, maxHealth*2) + if(updating_health) + updatehealth() + +/mob/living/proc/setOxyLoss(amount, updating_health=1) + if(status_flags & GODMODE) + return 0 + oxyloss = amount + if(updating_health) + updatehealth() + +/mob/living/proc/getToxLoss() + return toxloss + +/mob/living/proc/adjustToxLoss(amount, updating_health=1) + if(status_flags & GODMODE) + return 0 + toxloss = Clamp((toxloss + (amount * config.damage_multiplier)), 0, maxHealth*2) + if(updating_health) + updatehealth() + return amount + +/mob/living/proc/setToxLoss(amount, updating_health=1) + if(status_flags & GODMODE) + return 0 + toxloss = amount + if(updating_health) + updatehealth() + +/mob/living/proc/getFireLoss() + return fireloss + +/mob/living/proc/adjustFireLoss(amount, updating_health=1) + if(status_flags & GODMODE) + return 0 + fireloss = Clamp((fireloss + (amount * config.damage_multiplier)), 0, maxHealth*2) + if(updating_health) + updatehealth() + +/mob/living/proc/getCloneLoss() + return cloneloss + +/mob/living/proc/adjustCloneLoss(amount, updating_health=1) + if(status_flags & GODMODE) + return 0 + cloneloss = Clamp((cloneloss + (amount * config.damage_multiplier)), 0, maxHealth*2) + if(updating_health) + updatehealth() + +/mob/living/proc/setCloneLoss(amount, updating_health=1) + if(status_flags & GODMODE) + return 0 + cloneloss = amount + if(updating_health) + updatehealth() + +/mob/living/proc/getBrainLoss() + return brainloss + +/mob/living/proc/adjustBrainLoss(amount) + if(status_flags & GODMODE) + return 0 + brainloss = Clamp((brainloss + (amount * config.damage_multiplier)), 0, maxHealth*2) + +/mob/living/proc/setBrainLoss(amount) + if(status_flags & GODMODE) + return 0 + brainloss = amount + +/mob/living/proc/getStaminaLoss() + return staminaloss + +/mob/living/proc/adjustStaminaLoss(amount, updating_stamina = 1) + return + +/mob/living/proc/setStaminaLoss(amount, updating_stamina = 1) + return + + +// heal ONE external organ, organ gets randomly selected from damaged ones. +/mob/living/proc/heal_bodypart_damage(brute, burn, updating_health = 1) + adjustBruteLoss(-brute, 0) //zero as argument for no instant health update + adjustFireLoss(-burn, 0) + if(updating_health) + updatehealth() + +// damage ONE external organ, organ gets randomly selected from damaged ones. +/mob/living/proc/take_bodypart_damage(brute, burn, updating_health = 1) + adjustBruteLoss(brute, 0) //zero as argument for no instant health update + adjustFireLoss(burn, 0) + if(updating_health) + updatehealth() + +// heal MANY bodyparts, in random order +/mob/living/proc/heal_overall_damage(brute, burn, only_robotic = 0, only_organic = 1, updating_health = 1) + adjustBruteLoss(-brute, 0) //zero as argument for no instant health update + adjustFireLoss(-burn, 0) + if(updating_health) + updatehealth() + +// damage MANY bodyparts, in random order +/mob/living/proc/take_overall_damage(brute, burn, updating_health = 1) + adjustBruteLoss(brute, 0) //zero as argument for no instant health update + adjustFireLoss(burn, 0) + if(updating_health) + updatehealth() \ No newline at end of file diff --git a/code/modules/mob/living/death.dm b/code/modules/mob/living/death.dm index fc1bf88240ba..10c9a2a50f8c 100644 --- a/code/modules/mob/living/death.dm +++ b/code/modules/mob/living/death.dm @@ -1,4 +1,4 @@ -/mob/living/gib(no_brain, no_organs) +/mob/living/gib(no_brain, no_organs, no_bodyparts) var/prev_lying = lying if(stat != DEAD) death(1) @@ -8,20 +8,27 @@ if(!prev_lying) gib_animation() - if(!no_organs) - spill_organs(no_brain) - spawn_gibs() + + + spill_organs(no_brain, no_organs, no_bodyparts) + + if(!no_bodyparts) + spread_bodyparts(no_brain, no_organs) + + spawn_gibs(no_bodyparts) qdel(src) /mob/living/proc/gib_animation() return /mob/living/proc/spawn_gibs() - gibs(loc, viruses) + new /obj/effect/gibspawner/generic(loc, viruses) -/mob/living/proc/spill_organs(no_brain) +/mob/living/proc/spill_organs() return +/mob/living/proc/spread_bodyparts() + return /mob/living/dust() death(1) diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm index f44ca1855baa..052328ac563e 100644 --- a/code/modules/mob/living/life.dm +++ b/code/modules/mob/living/life.dm @@ -78,6 +78,23 @@ /mob/living/proc/handle_environment(datum/gas_mixture/environment) return +/mob/living/proc/handle_fire() + if(fire_stacks < 0) //If we've doused ourselves in water to avoid fire, dry off slowly + fire_stacks = min(0, fire_stacks + 1)//So we dry ourselves back to default, nonflammable. + if(!on_fire) + return 1 + if(fire_stacks > 0) + adjust_fire_stacks(-0.1) //the fire is slowly consumed + else + ExtinguishMob() + return + var/datum/gas_mixture/G = loc.return_air() // Check if we're standing in an oxygenless environment + if(!G.gases["o2"] || G.gases["o2"][MOLES] < 1) + ExtinguishMob() //If there's no oxygen in the tile we're on, put out the fire + return + var/turf/location = get_turf(src) + location.hotspot_expose(700, 50, 1) + /mob/living/proc/handle_stomach() return diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index d5d566211d1e..b06fef840ca8 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -212,22 +212,13 @@ src << "You have given up life and succumbed to death." death() +/mob/living/incapacitated(ignore_restraints, ignore_grab) + if(stat || paralysis || stunned || weakened || (!ignore_restraints && restrained(ignore_grab))) + return 1 + /mob/living/proc/InCritical() return (src.health < 0 && src.health > -95 && stat == UNCONSCIOUS) -/mob/living/ex_act(severity, origin) - if(istype(origin, /datum/spacevine_mutation) && isvineimmune(src)) - return - ..() - flash_eyes() - -/mob/living/proc/updatehealth() - if(status_flags & GODMODE) - return - health = maxHealth - getOxyLoss() - getToxLoss() - getFireLoss() - getBruteLoss() - getCloneLoss() - update_stat() - med_hud_set_health() - //This proc is used for mobs which are affected by pressure to calculate the amount of pressure that actually //affects them once clothing is factored in. ~Errorage /mob/living/proc/calculate_affecting_pressure(pressure) @@ -255,120 +246,6 @@ return temperature -// MOB PROCS -/mob/living/proc/getBruteLoss() - return bruteloss - -/mob/living/proc/adjustBruteLoss(amount, updating_health=1) - if(status_flags & GODMODE) - return 0 - bruteloss = Clamp((bruteloss + (amount * config.damage_multiplier)), 0, maxHealth*2) - if(updating_health) - updatehealth() - -/mob/living/proc/getOxyLoss() - return oxyloss - -/mob/living/proc/adjustOxyLoss(amount, updating_health=1) - if(status_flags & GODMODE) - return 0 - oxyloss = Clamp((oxyloss + (amount * config.damage_multiplier)), 0, maxHealth*2) - if(updating_health) - updatehealth() - -/mob/living/proc/setOxyLoss(amount, updating_health=1) - if(status_flags & GODMODE) - return 0 - oxyloss = amount - if(updating_health) - updatehealth() - -/mob/living/proc/getToxLoss() - return toxloss - -/mob/living/proc/adjustToxLoss(amount, updating_health=1) - if(status_flags & GODMODE) - return 0 - toxloss = Clamp((toxloss + (amount * config.damage_multiplier)), 0, maxHealth*2) - if(updating_health) - updatehealth() - return amount - -/mob/living/proc/setToxLoss(amount, updating_health=1) - if(status_flags & GODMODE) - return 0 - toxloss = amount - if(updating_health) - updatehealth() - -/mob/living/proc/getFireLoss() - return fireloss - -/mob/living/proc/adjustFireLoss(amount, updating_health=1) - if(status_flags & GODMODE) - return 0 - fireloss = Clamp((fireloss + (amount * config.damage_multiplier)), 0, maxHealth*2) - if(updating_health) - updatehealth() - -/mob/living/proc/getCloneLoss() - return cloneloss - -/mob/living/proc/adjustCloneLoss(amount, updating_health=1) - if(status_flags & GODMODE) - return 0 - cloneloss = Clamp((cloneloss + (amount * config.damage_multiplier)), 0, maxHealth*2) - if(updating_health) - updatehealth() - -/mob/living/proc/setCloneLoss(amount, updating_health=1) - if(status_flags & GODMODE) - return 0 - cloneloss = amount - if(updating_health) - updatehealth() - -/mob/living/proc/getBrainLoss() - return brainloss - -/mob/living/proc/adjustBrainLoss(amount) - if(status_flags & GODMODE) - return 0 - brainloss = Clamp((brainloss + (amount * config.damage_multiplier)), 0, maxHealth*2) - -/mob/living/proc/setBrainLoss(amount) - if(status_flags & GODMODE) - return 0 - brainloss = amount - -/mob/living/proc/getStaminaLoss() - return staminaloss - -/mob/living/proc/adjustStaminaLoss(amount, updating_stamina = 1) - return - -/mob/living/carbon/adjustStaminaLoss(amount, updating_stamina = 1) - if(status_flags & GODMODE) - return 0 - staminaloss = Clamp(staminaloss + amount, 0, maxHealth*2) - if(updating_stamina) - update_stamina() - -/mob/living/carbon/alien/adjustStaminaLoss(amount, updating_stamina = 1) - return - -/mob/living/proc/setStaminaLoss(amount, updating_stamina = 1) - return - -/mob/living/carbon/setStaminaLoss(amount, updating_stamina = 1) - if(status_flags & GODMODE) - return 0 - staminaloss = amount - if(updating_stamina) - update_stamina() - -/mob/living/carbon/alien/setStaminaLoss(amount, updating_stamina = 1) - return /mob/living/proc/getMaxHealth() return maxHealth @@ -425,23 +302,6 @@ return 1 return 0 - -/mob/living/proc/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0) - if(shock_damage > 0) - adjustFireLoss(shock_damage) - visible_message( - "[src] was shocked by \the [source]!", \ - "You feel a powerful shock coursing through your body!", \ - "You hear a heavy electrical crack." \ - ) - return shock_damage - -/mob/living/emp_act(severity) - var/list/L = src.get_contents() - for(var/obj/O in L) - O.emp_act(severity) - ..() - /mob/living/proc/can_inject() return 1 @@ -453,33 +313,14 @@ var/def_zone = ran_zone(t) return def_zone -// heal ONE external organ, organ gets randomly selected from damaged ones. -/mob/living/proc/heal_organ_damage(brute, burn, updating_health=1) - adjustBruteLoss(-brute, updating_health) - adjustFireLoss(-burn, updating_health) - if(updating_health) - updatehealth() -// damage ONE external organ, organ gets randomly selected from damaged ones. -/mob/living/proc/take_organ_damage(brute, burn, updating_health=1) - adjustBruteLoss(brute) - adjustFireLoss(burn) - if(updating_health) - updatehealth() - -// heal MANY bodyparts, in random order -/mob/living/proc/heal_overall_damage(brute, burn, updating_health=1) - adjustBruteLoss(-brute, updating_health) - adjustFireLoss(-burn, updating_health) - if(updating_health) - updatehealth() - -// damage MANY bodyparts, in random order -/mob/living/proc/take_overall_damage(brute, burn, updating_health=1) - adjustBruteLoss(brute, updating_health) - adjustFireLoss(burn, updating_health) - if(updating_health) - updatehealth() +/mob/living/proc/updatehealth() + if(status_flags & GODMODE) + return + health = maxHealth - getOxyLoss() - getToxLoss() - getFireLoss() - getBruteLoss() - getCloneLoss() + update_stat() + med_hud_set_health() + med_hud_set_status() //proc used to ressuscitate a mob /mob/living/proc/revive(full_heal = 0, admin_revive = 0) @@ -500,7 +341,7 @@ //proc used to completely heal a mob. /mob/living/proc/fully_heal(admin_revive = 0) restore_blood() - setToxLoss(0, 0) + setToxLoss(0, 0) //zero as second argument not automatically call updatehealth(). setOxyLoss(0, 0) setCloneLoss(0, 0) setBrainLoss(0) @@ -517,14 +358,14 @@ set_eye_damage(0) cure_nearsighted() cure_blind() + cure_husk() disabilities = 0 ear_deaf = 0 ear_damage = 0 hallucination = 0 - heal_overall_damage(100000, 100000) + heal_overall_damage(100000, 100000, 0, 0, 1) //heal brute and burn dmg on both organic and robotic limbs, and update health right away. ExtinguishMob() fire_stacks = 0 - updatehealth() update_canmove() @@ -758,21 +599,6 @@ animate(src, pixel_y = get_standard_pixel_y_offset(lying), time = 10) floating = 0 -//called when the mob receives a bright flash -/mob/living/proc/flash_eyes(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /obj/screen/fullscreen/flash) - if(check_eye_prot() < intensity && (override_blindness_check || !(disabilities & BLIND))) - overlay_fullscreen("flash", type) - addtimer(src, "clear_fullscreen", 25, FALSE, "flash", 25) - return 1 - -//this returns the mob's protection against eye damage (number between -1 and 2) -/mob/living/proc/check_eye_prot() - return 0 - -//this returns the mob's protection against ear damage (0 or 1) -/mob/living/proc/check_ear_prot() - return 0 - // The src mob is trying to strip an item from someone // Override if a certain type of mob should be behave differently when stripping items (can't, for example) /mob/living/stripPanelUnequip(obj/item/what, mob/who, where) @@ -821,11 +647,6 @@ who.equip_to_slot_if_possible(what, where, 0, 1) add_logs(src, who, "equipped", what) -/mob/living/singularity_act() - var/gain = 20 - investigate_log("([key_name(src)]) has been consumed by the singularity.","singulo") //Oh that's where the clown ended up! - gib() - return(gain) /mob/living/singularity_pull(S, current_size) if(current_size >= STAGE_SIX) @@ -833,29 +654,6 @@ else step_towards(src,S) -/mob/living/narsie_act() - if(is_servant_of_ratvar(src) && !stat) - src << "You resist Nar-Sie's influence... but not all of it. Run!" - adjustBruteLoss(35) - if(src && reagents) - reagents.add_reagent("heparin", 5) - return 0 - if(client) - makeNewConstruct(/mob/living/simple_animal/hostile/construct/harvester, src, null, 0) - else - new /mob/living/simple_animal/hostile/construct/harvester/hostile(get_turf(src)) - spawn_dust() - gib() - return - -/mob/living/ratvar_act() - if(!add_servant_of_ratvar(src) && !is_servant_of_ratvar(src)) - src << "A blinding light boils you alive! Run!" - adjustFireLoss(35) - if(src) - adjust_fire_stacks(1) - IgniteMob() - /atom/movable/proc/do_attack_animation(atom/A, end_pixel_y) var/pixel_x_diff = 0 var/pixel_y_diff = 0 @@ -1016,7 +814,7 @@ new path(src.loc) butcher_results.Remove(path) //In case you want to have things like simple_animals drop their butcher results on gib, so it won't double up below. visible_message("[user] butchers [src].") - gib() + gib(0, 0, 1) /mob/living/canUseTopic(atom/movable/M, be_close = 0, no_dextery = 0) if(incapacitated()) @@ -1104,3 +902,50 @@ /mob/living/proc/fakefire() return + + + +//Mobs on Fire +/mob/living/proc/IgniteMob() + if(fire_stacks > 0 && !on_fire) + on_fire = 1 + src.visible_message("[src] catches fire!", \ + "You're set on fire!") + src.AddLuminosity(3) + throw_alert("fire", /obj/screen/alert/fire) + update_fire() + return TRUE + return FALSE + +/mob/living/proc/ExtinguishMob() + if(on_fire) + on_fire = 0 + fire_stacks = 0 + src.AddLuminosity(-3) + clear_alert("fire") + update_fire() + +/mob/living/proc/adjust_fire_stacks(add_fire_stacks) //Adjusting the amount of fire_stacks we have on person + fire_stacks = Clamp(fire_stacks + add_fire_stacks, -20, 20) + if(on_fire && fire_stacks <= 0) + ExtinguishMob() + +//Share fire evenly between the two mobs +//Called in MobBump() and Crossed() +/mob/living/proc/spreadFire(mob/living/L) + if(!istype(L)) + return + var/L_old_on_fire = L.on_fire + + if(on_fire) //Only spread fire stacks if we're on fire + fire_stacks /= 2 + L.fire_stacks += fire_stacks + if(L.IgniteMob()) + log_game("[key_name(src)] bumped into [key_name(L)] and set them on fire") + + if(L_old_on_fire) //Only ignite us and gain their stacks if they were onfire before we bumped them + L.fire_stacks /= 2 + fire_stacks += L.fire_stacks + IgniteMob() + +//Mobs on Fire end diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index c7543c03edea..ee4bd6ce2067 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -1,3 +1,4 @@ + /mob/living/proc/run_armor_check(def_zone = null, attack_flag = "melee", absorb_text = null, soften_text = null, armour_penetration, penetrated_text) var/armor = getarmor(def_zone, attack_flag) @@ -24,6 +25,14 @@ /mob/living/proc/getarmor(def_zone, type) return 0 +//this returns the mob's protection against eye damage (number between -1 and 2) +/mob/living/proc/get_eye_protection() + return 0 + +//this returns the mob's protection against ear damage (0:no protection; 1: some ear protection; 2: has no ears) +/mob/living/proc/get_ear_protection() + return 0 + /mob/living/proc/on_hit(obj/item/projectile/proj_type) return @@ -33,18 +42,16 @@ apply_damage(P.damage, P.damage_type, def_zone, armor) if(P.dismemberment) check_projectile_dismemberment(P, def_zone) - return P.on_hit(src, armor, def_zone) + return P.on_hit(src, armor) /mob/living/proc/check_projectile_dismemberment(obj/item/projectile/P, def_zone) return 0 -/proc/vol_by_throwforce_and_or_w_class(obj/item/I) - if(!I) - return 0 - if(I.throwforce && I.w_class) - return Clamp((I.throwforce + I.w_class) * 5, 30, 100)// Add the item's throwforce to its weight class and multiply by 5, then clamp the value between 30 and 100 - else if(I.w_class) - return Clamp(I.w_class * 8, 20, 100) // Multiply the item's weight class by 8, then clamp the value between 20 and 100 +/obj/item/proc/get_volume_by_throwforce_and_or_w_class() + if(throwforce && w_class) + return Clamp((throwforce + w_class) * 5, 30, 100)// Add the item's throwforce to its weight class and multiply by 5, then clamp the value between 30 and 100 + else if(w_class) + return Clamp(w_class * 8, 20, 100) // Multiply the item's weight class by 8, then clamp the value between 20 and 100 else return 0 @@ -53,7 +60,7 @@ var/obj/item/I = AM var/zone = ran_zone("chest", 65)//Hits a random part of the body, geared towards the chest var/dtype = BRUTE - var/volume = vol_by_throwforce_and_or_w_class(I) + var/volume = I.get_volume_by_throwforce_and_or_w_class() if(istype(I,/obj/item/weapon)) //If the item is a weapon... var/obj/item/weapon/W = I dtype = W.damtype @@ -83,6 +90,7 @@ playsound(loc, 'sound/weapons/genhit.ogg', 50, 1, -1) ..() + /mob/living/mech_melee_attack(obj/mecha/M) if(M.occupant.a_intent == "harm") M.do_attack_animation(src) @@ -109,80 +117,10 @@ add_logs(M.occupant, src, "pushed", M) visible_message("[M] pushes [src] out of the way.") - -//Mobs on Fire -/mob/living/proc/IgniteMob() - if(fire_stacks > 0 && !on_fire) - on_fire = 1 - src.visible_message("[src] catches fire!", \ - "You're set on fire!") - src.AddLuminosity(3) - throw_alert("fire", /obj/screen/alert/fire) - update_fire() - return TRUE - return FALSE - -/mob/living/proc/ExtinguishMob() - if(on_fire) - on_fire = 0 - fire_stacks = 0 - src.AddLuminosity(-3) - clear_alert("fire") - update_fire() - -/mob/living/proc/update_fire() - return - -/mob/living/proc/adjust_fire_stacks(add_fire_stacks) //Adjusting the amount of fire_stacks we have on person - fire_stacks = Clamp(fire_stacks + add_fire_stacks, -20, 20) - if(on_fire && fire_stacks <= 0) - ExtinguishMob() - -/mob/living/proc/handle_fire() - if(fire_stacks < 0) //If we've doused ourselves in water to avoid fire, dry off slowly - fire_stacks = min(0, fire_stacks + 1)//So we dry ourselves back to default, nonflammable. - if(!on_fire) - return 1 - if(fire_stacks > 0) - adjust_fire_stacks(-0.1) //the fire is slowly consumed - else - ExtinguishMob() - return - var/datum/gas_mixture/G = loc.return_air() // Check if we're standing in an oxygenless environment - if(!G.gases["o2"] || G.gases["o2"][MOLES] < 1) - ExtinguishMob() //If there's no oxygen in the tile we're on, put out the fire - return - var/turf/location = get_turf(src) - location.hotspot_expose(700, 50, 1) - /mob/living/fire_act() adjust_fire_stacks(3) IgniteMob() - -//Share fire evenly between the two mobs -//Called in MobBump() and Crossed() -/mob/living/proc/spreadFire(mob/living/L) - if(!istype(L)) - return - var/L_old_on_fire = L.on_fire - - if(on_fire) //Only spread fire stacks if we're on fire - fire_stacks /= 2 - L.fire_stacks += fire_stacks - if(L.IgniteMob()) - log_game("[key_name(src)] bumped into [key_name(L)] and set them on fire") - - if(L_old_on_fire) //Only ignite us and gain their stacks if they were onfire before we bumped them - L.fire_stacks /= 2 - fire_stacks += L.fire_stacks - IgniteMob() - -//Mobs on Fire end - -/mob/living/acid_act(acidpwr, toxpwr, acid_volume) - take_organ_damage(min(10*toxpwr, acid_volume * toxpwr)) - /mob/living/proc/grabbedby(mob/living/carbon/user, supress_message = 0) if(user == src || anchored) return 0 @@ -291,7 +229,6 @@ return 0 /mob/living/attack_larva(mob/living/carbon/alien/larva/L) - switch(L.a_intent) if("help") visible_message("[L.name] rubs its head against [src].") @@ -331,60 +268,71 @@ M.do_attack_animation(src) return 1 -/mob/living/incapacitated(ignore_restraints, ignore_grab) - if(stat || paralysis || stunned || weakened || (!ignore_restraints && restrained(ignore_grab))) - return 1 +/mob/living/ex_act(severity, origin) + if(istype(origin, /datum/spacevine_mutation) && isvineimmune(src)) + return + ..() + flash_act() //Looking for irradiate()? It's been moved to radiation.dm under the rad_act() for mobs. -/mob/living/proc/add_stun_absorption(key, duration, priority, message, self_message, examine_message) -//adds a stun absorption with a key, a duration in deciseconds, its priority, and the messages it makes when you're stunned/examined, if any - if(!islist(stun_absorption)) - stun_absorption = list() - if(stun_absorption[key]) - stun_absorption[key]["end_time"] = world.time + duration - stun_absorption[key]["priority"] = priority - stun_absorption[key]["stuns_absorbed"] = 0 +/mob/living/acid_act(acidpwr, toxpwr, acid_volume) + take_bodypart_damage(min(10*toxpwr, acid_volume * toxpwr)) + + +/mob/living/proc/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0) + if(shock_damage > 0) + adjustFireLoss(shock_damage) + visible_message( + "[src] was shocked by \the [source]!", \ + "You feel a powerful shock coursing through your body!", \ + "You hear a heavy electrical crack." \ + ) + return shock_damage + +/mob/living/emp_act(severity) + var/list/L = src.get_contents() + for(var/obj/O in L) + O.emp_act(severity) + ..() + +/mob/living/singularity_act() + var/gain = 20 + investigate_log("([key_name(src)]) has been consumed by the singularity.","singulo") //Oh that's where the clown ended up! + gib() + return(gain) + +/mob/living/narsie_act() + if(is_servant_of_ratvar(src) && !stat) + src << "You resist Nar-Sie's influence... but not all of it. Run!" + adjustBruteLoss(35) + if(src && reagents) + reagents.add_reagent("heparin", 5) + return 0 + if(client) + makeNewConstruct(/mob/living/simple_animal/hostile/construct/harvester, src, null, 0) else - stun_absorption[key] = list("end_time" = world.time + duration, "priority" = priority, "stuns_absorbed" = 0, \ - "visible_message" = message, "self_message" = self_message, "examine_message" = examine_message) + new /mob/living/simple_animal/hostile/construct/harvester/hostile(get_turf(src)) + spawn_dust() + gib() -/mob/living/Stun(amount, updating = 1, ignore_canstun = 0) - if(!stat && islist(stun_absorption)) - var/priority_absorb_key - var/highest_priority - for(var/i in stun_absorption) - if(stun_absorption[i]["end_time"] > world.time && (!priority_absorb_key || stun_absorption[i]["priority"] > highest_priority)) - priority_absorb_key = stun_absorption[i] - highest_priority = stun_absorption[i]["priority"] - if(priority_absorb_key) - if(priority_absorb_key["visible_message"] || priority_absorb_key["self_message"]) - if(priority_absorb_key["visible_message"] && priority_absorb_key["self_message"]) - visible_message("[src][priority_absorb_key["visible_message"]]", "[priority_absorb_key["self_message"]]") - else if(priority_absorb_key["visible_message"]) - visible_message("[src][priority_absorb_key["visible_message"]]") - else if(priority_absorb_key["self_message"]) - src << "[priority_absorb_key["self_message"]]" - priority_absorb_key["stuns_absorbed"] += amount - return 0 - ..() -/mob/living/Weaken(amount, updating = 1, ignore_canweaken = 0) - if(!stat && islist(stun_absorption)) - var/priority_absorb_key - var/highest_priority - for(var/i in stun_absorption) - if(stun_absorption[i]["end_time"] > world.time && (!priority_absorb_key || stun_absorption[i]["priority"] > highest_priority)) - priority_absorb_key = stun_absorption[i] - highest_priority = priority_absorb_key["priority"] - if(priority_absorb_key) - if(priority_absorb_key["visible_message"] || priority_absorb_key["self_message"]) - if(priority_absorb_key["visible_message"] && priority_absorb_key["self_message"]) - visible_message("[src][priority_absorb_key["visible_message"]]", "[priority_absorb_key["self_message"]]") - else if(priority_absorb_key["visible_message"]) - visible_message("[src][priority_absorb_key["visible_message"]]") - else if(priority_absorb_key["self_message"]) - src << "[priority_absorb_key["self_message"]]" - priority_absorb_key["stuns_absorbed"] += amount - return 0 - ..() +/mob/living/ratvar_act() + if(!add_servant_of_ratvar(src) && !is_servant_of_ratvar(src)) + src << "A blinding light boils you alive! Run!" + adjustFireLoss(35) + if(src) + adjust_fire_stacks(1) + IgniteMob() + + +//called when the mob receives a bright flash +/mob/living/proc/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /obj/screen/fullscreen/flash) + if(get_eye_protection() < intensity && (override_blindness_check || !(disabilities & BLIND))) + overlay_fullscreen("flash", type) + addtimer(src, "clear_fullscreen", 25, FALSE, "flash", 25) + return 1 + +//called when the mob receives a loud bang +/mob/living/proc/soundbang_act() + return 0 diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index b19c799ee375..7cd4e02e6183 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -351,39 +351,9 @@ var/list/ai_list = list() SSshuttle.cancelEvac(src) return -/mob/living/silicon/ai/blob_act(obj/effect/blob/B) - if (stat != DEAD) - adjustBruteLoss(60) - updatehealth() - return 1 - return 0 - /mob/living/silicon/ai/restrained(ignore_grab) . = 0 -/mob/living/silicon/ai/emp_act(severity) - if (prob(30)) - switch(pick(1,2)) - if(1) - view_core() - if(2) - SSshuttle.requestEvac(src,"ALERT: Energy surge detected in AI core! Station integrity may be compromised! Initiati--%m091#ar-BZZT") - ..() - -/mob/living/silicon/ai/ex_act(severity, target) - ..() - - switch(severity) - if(1) - gib() - if(2) - if (stat != DEAD) - adjustBruteLoss(60) - adjustFireLoss(60) - if(3) - if (stat != DEAD) - adjustBruteLoss(30) - /mob/living/silicon/ai/Topic(href, href_list) if(usr != src) return @@ -455,18 +425,6 @@ var/list/ai_list = list() if(M) M.transfer_ai(AI_MECH_HACK,src, usr) //Called om the mech itself. -/mob/living/silicon/ai/bullet_act(obj/item/projectile/Proj) - ..(Proj) - updatehealth() - return 2 - - -/mob/living/silicon/ai/attack_alien(mob/living/carbon/alien/humanoid/M) - if(!ticker || !ticker.mode) - M << "You cannot attack people before the game has started." - return - - ..() /mob/living/silicon/ai/proc/switchCamera(obj/machinery/camera/C) @@ -790,9 +748,6 @@ var/list/ai_list = list() return //won't work if dead set_autosay() -/mob/living/silicon/ai/attack_slime(mob/living/simple_animal/slime/user) - return - /mob/living/silicon/ai/transfer_ai(interaction, mob/user, mob/living/silicon/ai/AI, obj/item/device/aicard/card) if(!..()) return @@ -809,14 +764,6 @@ var/list/ai_list = list() src << "You have been downloaded to a mobile storage device. Remote device connection severed." user << "Transfer successful: [name] ([rand(1000,9999)].exe) removed from host terminal and stored within local memory." -/mob/living/silicon/ai/flash_eyes(intensity = 1, override_blindness_check = 0, affect_silicon = 0) - return // no eyes, no flashing - -/mob/living/silicon/ai/attackby(obj/item/weapon/W, mob/user, params) - if(W.force && W.damtype != STAMINA && src.stat != DEAD) //only sparks if real damage is dealt. - spark_system.start() - return ..() - /mob/living/silicon/ai/can_buckle() return 0 diff --git a/code/modules/mob/living/silicon/ai/ai_defense.dm b/code/modules/mob/living/silicon/ai/ai_defense.dm new file mode 100644 index 000000000000..771a6d7c2f51 --- /dev/null +++ b/code/modules/mob/living/silicon/ai/ai_defense.dm @@ -0,0 +1,55 @@ + +/mob/living/silicon/ai/attacked_by(obj/item/I, mob/living/user, def_zone) + if(I.force && I.damtype != STAMINA && stat != DEAD) //only sparks if real damage is dealt. + spark_system.start() + return ..() + + +/mob/living/silicon/ai/attack_alien(mob/living/carbon/alien/humanoid/M) + if(!ticker || !ticker.mode) + M << "You cannot attack people before the game has started." + return + ..() + +/mob/living/silicon/ai/attack_slime(mob/living/simple_animal/slime/user) + return //immune to slimes + +/mob/living/silicon/ai/blob_act(obj/effect/blob/B) + if (stat != DEAD) + adjustBruteLoss(60) + updatehealth() + return 1 + return 0 + +/mob/living/silicon/ai/emp_act(severity) + if (prob(30)) + switch(pick(1,2)) + if(1) + view_core() + if(2) + SSshuttle.requestEvac(src,"ALERT: Energy surge detected in AI core! Station integrity may be compromised! Initiati--%m091#ar-BZZT") + ..() + +/mob/living/silicon/ai/ex_act(severity, target) + ..() + + switch(severity) + if(1) + gib() + if(2) + if (stat != DEAD) + adjustBruteLoss(60) + adjustFireLoss(60) + if(3) + if (stat != DEAD) + adjustBruteLoss(30) + + + +/mob/living/silicon/ai/bullet_act(obj/item/projectile/Proj) + ..(Proj) + updatehealth() + return 2 + +/mob/living/silicon/ai/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0) + return // no eyes, no flashing diff --git a/code/modules/mob/living/silicon/damage_procs.dm b/code/modules/mob/living/silicon/damage_procs.dm new file mode 100644 index 000000000000..181a166bb54c --- /dev/null +++ b/code/modules/mob/living/silicon/damage_procs.dm @@ -0,0 +1,36 @@ + +/mob/living/silicon/apply_damage(damage = 0,damagetype = BRUTE, def_zone = null, blocked = 0) + var/hit_percent = (100-blocked)/100 + if(!damage || (hit_percent <= 0)) + return 0 + switch(damagetype) + if(BRUTE) + adjustBruteLoss(damage * hit_percent) + if(BURN) + adjustFireLoss(damage * hit_percent) + return 1 + + +/mob/living/silicon/apply_effect(effect = 0,effecttype = STUN, blocked = 0) + return 0//The only effect that can hit them atm is flashes and they still directly edit so this works for now + + + +/mob/living/silicon/adjustToxLoss(amount, updating_health=1) //immune to tox damage + return 0 + +/mob/living/silicon/setToxLoss(amount, updating_health=1) + return 0 + +/mob/living/silicon/adjustCloneLoss(amount) //immune to clone damage + return 0 + +/mob/living/silicon/setCloneLoss(amount, updating_health=1) + return 0 + +/mob/living/silicon/adjustStaminaLoss(amount, updating_stamina = 1)//immune to stamina damage. + return + +/mob/living/silicon/setStaminaLoss(amount, updating_stamina = 1) + return + diff --git a/code/modules/mob/living/silicon/death.dm b/code/modules/mob/living/silicon/death.dm index 02fb54012b14..ebd3067bb0aa 100644 --- a/code/modules/mob/living/silicon/death.dm +++ b/code/modules/mob/living/silicon/death.dm @@ -1,5 +1,5 @@ /mob/living/silicon/spawn_gibs() - robogibs(loc, viruses) + new /obj/effect/gibspawner/robot(loc,viruses) /mob/living/silicon/spawn_dust() new /obj/effect/decal/remains/robot(loc) diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index ea83dce7e1d5..018c05e98001 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -94,66 +94,11 @@ else stat(null, text("Systems nonfunctional")) -/mob/living/silicon/pai/blob_act(obj/effect/blob/B) - return 0 - /mob/living/silicon/pai/restrained(ignore_grab) . = 0 -/mob/living/silicon/pai/emp_act(severity) - // 20% chance to kill - // Silence for 2 minutes - // 33% chance to unbind - // 33% chance to change prime directive (based on severity) - // 33% chance of no additional effect - - if(prob(20)) - visible_message("A shower of sparks spray from [src]'s inner workings.", 3, "You hear and smell the ozone hiss of electrical sparks being expelled violently.", 2) - return src.death(0) - - silence_time = world.timeofday + 120 * 10 // Silence for 2 minutes - src << "Communication circuit overload. Shutting down and reloading communication circuits - speech and messaging functionality will be unavailable until the reboot is complete." - - switch(pick(1,2,3)) - if(1) - src.master = null - src.master_dna = null - src << "You feel unbound." - if(2) - var/command - if(severity == 1) - command = pick("Serve", "Love", "Fool", "Entice", "Observe", "Judge", "Respect", "Educate", "Amuse", "Entertain", "Glorify", "Memorialize", "Analyze") - else - command = pick("Serve", "Kill", "Love", "Hate", "Disobey", "Devour", "Fool", "Enrage", "Entice", "Observe", "Judge", "Respect", "Disrespect", "Consume", "Educate", "Destroy", "Disgrace", "Amuse", "Entertain", "Ignite", "Glorify", "Memorialize", "Analyze") - src.laws.zeroth = "[command] your master." - src << "Pr1m3 d1r3c71v3 uPd473D." - if(3) - src << "You feel an electric surge run through your circuitry and become acutely aware at how lucky you are that you can still feel at all." - -/mob/living/silicon/pai/ex_act(severity, target) - ..() - - switch(severity) - if(1) - if (src.stat != 2) - adjustBruteLoss(100) - adjustFireLoss(100) - if(2) - if (src.stat != 2) - adjustBruteLoss(60) - adjustFireLoss(60) - if(3) - if (src.stat != 2) - adjustBruteLoss(30) - - return - - // See software.dm for Topic() -/mob/living/silicon/pai/UnarmedAttack(atom/A)//Stops runtimes due to attack_animal being the default - return - /mob/living/silicon/pai/canUseTopic(atom/movable/M) return 1 /* diff --git a/code/modules/mob/living/silicon/pai/pai_defense.dm b/code/modules/mob/living/silicon/pai/pai_defense.dm new file mode 100644 index 000000000000..5cdbebfd9957 --- /dev/null +++ b/code/modules/mob/living/silicon/pai/pai_defense.dm @@ -0,0 +1,49 @@ + +/mob/living/silicon/pai/blob_act(obj/effect/blob/B) + return 0 + +/mob/living/silicon/pai/emp_act(severity) + // 20% chance to kill + // Silence for 2 minutes + // 33% chance to unbind + // 33% chance to change prime directive (based on severity) + // 33% chance of no additional effect + + if(prob(20)) + visible_message("A shower of sparks spray from [src]'s inner workings.", 3, "You hear and smell the ozone hiss of electrical sparks being expelled violently.", 2) + return src.death(0) + + silence_time = world.timeofday + 120 * 10 // Silence for 2 minutes + src << "Communication circuit overload. Shutting down and reloading communication circuits - speech and messaging functionality will be unavailable until the reboot is complete." + + switch(pick(1,2,3)) + if(1) + src.master = null + src.master_dna = null + src << "You feel unbound." + if(2) + var/command + if(severity == 1) + command = pick("Serve", "Love", "Fool", "Entice", "Observe", "Judge", "Respect", "Educate", "Amuse", "Entertain", "Glorify", "Memorialize", "Analyze") + else + command = pick("Serve", "Kill", "Love", "Hate", "Disobey", "Devour", "Fool", "Enrage", "Entice", "Observe", "Judge", "Respect", "Disrespect", "Consume", "Educate", "Destroy", "Disgrace", "Amuse", "Entertain", "Ignite", "Glorify", "Memorialize", "Analyze") + src.laws.zeroth = "[command] your master." + src << "Pr1m3 d1r3c71v3 uPd473D." + if(3) + src << "You feel an electric surge run through your circuitry and become acutely aware at how lucky you are that you can still feel at all." + +/mob/living/silicon/pai/ex_act(severity, target) + ..() + + switch(severity) + if(1) + if (src.stat != 2) + adjustBruteLoss(100) + adjustFireLoss(100) + if(2) + if (src.stat != 2) + adjustBruteLoss(60) + adjustFireLoss(60) + if(3) + if (src.stat != 2) + adjustBruteLoss(30) diff --git a/code/modules/mob/living/silicon/robot/death.dm b/code/modules/mob/living/silicon/robot/death.dm index ca980e86bf55..fa94450b7484 100644 --- a/code/modules/mob/living/silicon/robot/death.dm +++ b/code/modules/mob/living/silicon/robot/death.dm @@ -1,7 +1,4 @@ -/mob/living/silicon/robot/spawn_gibs() - robogibs(loc, viruses) - /mob/living/silicon/robot/gib_animation() PoolOrNew(/obj/effect/overlay/temp/gib_animation, list(loc, "gibbed-r")) diff --git a/code/modules/mob/living/silicon/robot/life.dm b/code/modules/mob/living/silicon/robot/life.dm index 33f24c1dc0be..d0350a7a267a 100644 --- a/code/modules/mob/living/silicon/robot/life.dm +++ b/code/modules/mob/living/silicon/robot/life.dm @@ -106,10 +106,6 @@ if(on_fire) add_overlay(image("icon"='icons/mob/OnFire.dmi', "icon_state"="Generic_mob_burning")) -/mob/living/silicon/robot/fire_act() - if(!on_fire) //Silicons don't gain stacks from hotspots, but hotspots can ignite them - IgniteMob() - /mob/living/silicon/robot/update_canmove() if(stat || buckled || lockcharge) canmove = 0 diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 63fd04130515..76f8e90ef6e5 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -14,7 +14,7 @@ var/custom_name = "" var/braintype = "Cyborg" var/modtype = "robot" - var/obj/item/robot_parts/robot_suit/robot_suit = null //Used for deconstruction to remember what the borg was constructed out of.. + var/obj/item/robot_suit/robot_suit = null //Used for deconstruction to remember what the borg was constructed out of.. var/obj/item/device/mmi/mmi = null //Hud stuff @@ -366,16 +366,6 @@ if(thruster_button) thruster_button.icon_state = "ionpulse[ionpulse_on]" -/mob/living/silicon/robot/blob_act(obj/effect/blob/B) - if (stat != 2) - adjustBruteLoss(60) - updatehealth() - return 1 - else - gib() - return 1 - return 0 - /mob/living/silicon/robot/Stat() ..() if(statpanel("Status")) @@ -394,27 +384,6 @@ /mob/living/silicon/robot/restrained(ignore_grab) . = 0 -/mob/living/silicon/robot/ex_act(severity, target) - switch(severity) - if(1) - gib() - return - if(2) - if (stat != 2) - adjustBruteLoss(60) - adjustFireLoss(60) - if(3) - if (stat != 2) - adjustBruteLoss(30) - return - - -/mob/living/silicon/robot/bullet_act(var/obj/item/projectile/Proj) - ..(Proj) - updatehealth() - if(prob(75) && Proj.damage > 0) spark_system.start() - return 2 - /mob/living/silicon/robot/triggerAlarm(class, area/A, O, obj/alarmsource) if(alarmsource.z != z) return @@ -622,83 +591,6 @@ else return ..() -/mob/living/silicon/robot/attacked_by(obj/item/I, mob/living/user, def_zone) - if(I.force && I.damtype != STAMINA && stat != DEAD) //only sparks if real damage is dealt. - spark_system.start() - return ..() - - -/mob/living/silicon/robot/emag_act(mob/user) - if(user != src)//To prevent syndieborgs from emagging themselves - if(!opened)//Cover is closed - if(locked) - user << "You emag the cover lock." - locked = 0 - else - user << "The cover is already unlocked!" - return - if(opened)//Cover is open - if((world.time - 100) < emag_cooldown) - return - - if(syndicate) - user << "You emag [src]'s interface." - src << "ALERT: Foreign software execution prevented." - log_game("[key_name(user)] attempted to emag cyborg [key_name(src)] but they were a syndicate cyborg.") - emag_cooldown = world.time - return - - var/ai_is_antag = 0 - if(connected_ai && connected_ai.mind) - if(connected_ai.mind.special_role) - ai_is_antag = (connected_ai.mind.special_role == "traitor") - if(ai_is_antag) - user << "You emag [src]'s interface." - src << "ALERT: Foreign software execution prevented." - connected_ai << "ALERT: Cyborg unit \[[src]] successfuly defended against subversion." - log_game("[key_name(user)] attempted to emag cyborg [key_name(src)] slaved to traitor AI [connected_ai].") - emag_cooldown = world.time - return - - if(wiresexposed) - user << "You must unexpose the wires first!" - return - else - emag_cooldown = world.time - sleep(6) - SetEmagged(1) - SetLockdown(1) //Borgs were getting into trouble because they would attack the emagger before the new laws were shown - lawupdate = 0 - connected_ai = null - user << "You emag [src]'s interface." - message_admins("[key_name_admin(user)] emagged cyborg [key_name_admin(src)]. Laws overridden.") - log_game("[key_name(user)] emagged cyborg [key_name(src)]. Laws overridden.") - clear_supplied_laws() - clear_inherent_laws() - clear_zeroth_law(0) - laws = new /datum/ai_laws/syndicate_override - var/time = time2text(world.realtime,"hh:mm:ss") - lawchanges.Add("[time] : [user.name]([user.key]) emagged [name]([key])") - set_zeroth_law("Only [user.real_name] and people they designate as being such are Syndicate Agents.") - src << "ALERT: Foreign software detected." - sleep(5) - src << "Initiating diagnostics..." - sleep(20) - src << "SynBorg v1.7 loaded." - sleep(5) - src << "LAW SYNCHRONISATION ERROR" - sleep(5) - src << "Would you like to send a report to NanoTraSoft? Y/N" - sleep(10) - src << "> N" - sleep(20) - src << "ERRORERRORERROR" - src << "Obey these laws:" - laws.show_laws(src) - src << "ALERT: [user.real_name] is your new master. Obey your new laws and their commands." - SetLockdown(0) - update_icons() - /mob/living/silicon/robot/verb/unlock_own_cover() set category = "Robot Commands" set name = "Unlock Cover" @@ -712,65 +604,6 @@ update_icons() usr << "You unlock your cover." -/mob/living/silicon/robot/attack_alien(mob/living/carbon/alien/humanoid/M) - if (M.a_intent =="disarm") - if(!(lying)) - M.do_attack_animation(src) - if(get_active_held_item()) - uneq_active() - visible_message("[M] disarmed [src]!", \ - "[M] has disabled [src]'s active module!") - add_logs(M, src, "disarmed") - else - Stun(2) - step(src,get_dir(M,src)) - add_logs(M, src, "pushed") - visible_message("[M] has forced back [src]!", \ - "[M] has forced back [src]!") - playsound(loc, 'sound/weapons/pierce.ogg', 50, 1, -1) - else - ..() - return - -/mob/living/silicon/robot/attack_slime(mob/living/simple_animal/slime/M) - if(..()) //successful slime shock - flash_eyes() - var/stunprob = M.powerlevel * 7 + 10 - if(prob(stunprob) && M.powerlevel >= 8) - adjustBruteLoss(M.powerlevel * rand(6,10)) - - var/damage = rand(1, 3) - - if(M.is_adult) - damage = rand(20, 40) - else - damage = rand(5, 35) - damage = round(damage / 2) // borgs recieve half damage - adjustBruteLoss(damage) - updatehealth() - - return - -/mob/living/silicon/robot/attack_hand(mob/living/carbon/human/user) - add_fingerprint(user) - if(opened && !wiresexposed && (!istype(user, /mob/living/silicon))) - if(cell) - cell.updateicon() - cell.add_fingerprint(user) - user.put_in_active_hand(cell) - user << "You remove \the [cell]." - cell = null - update_icons() - diag_hud_set_borgcell() - - if(!opened) - if(..()) // hulk attack - spark_system.start() - spawn(0) - step_away(src,user,15) - sleep(3) - step_away(src,user,15) - /mob/living/silicon/robot/proc/allowed(mob/M) //check if it doesn't require any access at all if(check_access(null)) @@ -1136,14 +969,14 @@ robot_suit.head = null robot_suit.updateicon() else - new /obj/item/robot_parts/robot_suit(T) - new /obj/item/robot_parts/l_leg(T) - new /obj/item/robot_parts/r_leg(T) + new /obj/item/robot_suit(T) + new /obj/item/bodypart/l_leg/robot(T) + new /obj/item/bodypart/r_leg/robot(T) new /obj/item/stack/cable_coil(T, 1) - new /obj/item/robot_parts/chest(T) - new /obj/item/robot_parts/l_arm(T) - new /obj/item/robot_parts/r_arm(T) - new /obj/item/robot_parts/head(T) + new /obj/item/bodypart/chest/robot(T) + new /obj/item/bodypart/l_arm/robot(T) + new /obj/item/bodypart/r_arm/robot(T) + new /obj/item/bodypart/head/robot(T) var/b for(b=0, b!=2, b++) var/obj/item/device/assembly/flash/handheld/F = new /obj/item/device/assembly/flash/handheld(T) @@ -1287,22 +1120,6 @@ diag_hud_set_health() update_health_hud() -/mob/living/silicon/robot/fully_replace_character_name(oldname, newname) - ..() - if(oldname != real_name) - notify_ai(3, oldname, newname) - if(camera) - camera.c_tag = real_name - custom_name = newname - -/mob/living/silicon/robot/emp_act(severity) - switch(severity) - if(1) - Stun(8) - if(2) - Stun(3) - ..() - /mob/living/silicon/robot/revive(full_heal = 0, admin_revive = 0) if(..()) //successfully ressuscitated from death if(camera && !wires.is_cut(WIRE_CAMERA)) @@ -1313,6 +1130,13 @@ notify_ai(1) . = 1 +/mob/living/silicon/robot/fully_replace_character_name(oldname, newname) + ..() + if(oldname != real_name) + notify_ai(3, oldname, newname) + if(camera) + camera.c_tag = real_name + custom_name = newname /mob/living/silicon/robot/proc/ResetModule() diff --git a/code/modules/mob/living/silicon/robot/robot_defense.dm b/code/modules/mob/living/silicon/robot/robot_defense.dm new file mode 100644 index 000000000000..7fa7a720d42c --- /dev/null +++ b/code/modules/mob/living/silicon/robot/robot_defense.dm @@ -0,0 +1,182 @@ + + +/mob/living/silicon/robot/attacked_by(obj/item/I, mob/living/user, def_zone) + if(I.force && I.damtype != STAMINA && stat != DEAD) //only sparks if real damage is dealt. + spark_system.start() + return ..() + +/mob/living/silicon/robot/attack_alien(mob/living/carbon/alien/humanoid/M) + if (M.a_intent =="disarm") + if(!(lying)) + M.do_attack_animation(src) + if(get_active_held_item()) + uneq_active() + visible_message("[M] disarmed [src]!", \ + "[M] has disabled [src]'s active module!") + add_logs(M, src, "disarmed") + else + Stun(2) + step(src,get_dir(M,src)) + add_logs(M, src, "pushed") + visible_message("[M] has forced back [src]!", \ + "[M] has forced back [src]!") + playsound(loc, 'sound/weapons/pierce.ogg', 50, 1, -1) + else + ..() + return + +/mob/living/silicon/robot/attack_slime(mob/living/simple_animal/slime/M) + if(..()) //successful slime shock + flash_act() + var/stunprob = M.powerlevel * 7 + 10 + if(prob(stunprob) && M.powerlevel >= 8) + adjustBruteLoss(M.powerlevel * rand(6,10)) + + var/damage = rand(1, 3) + + if(M.is_adult) + damage = rand(20, 40) + else + damage = rand(5, 35) + damage = round(damage / 2) // borgs recieve half damage + adjustBruteLoss(damage) + updatehealth() + + return + +/mob/living/silicon/robot/attack_hand(mob/living/carbon/human/user) + add_fingerprint(user) + if(opened && !wiresexposed && (!istype(user, /mob/living/silicon))) + if(cell) + cell.updateicon() + cell.add_fingerprint(user) + user.put_in_active_hand(cell) + user << "You remove \the [cell]." + cell = null + update_icons() + diag_hud_set_borgcell() + + if(!opened) + if(..()) // hulk attack + spark_system.start() + spawn(0) + step_away(src,user,15) + sleep(3) + step_away(src,user,15) + +/mob/living/silicon/robot/fire_act() + if(!on_fire) //Silicons don't gain stacks from hotspots, but hotspots can ignite them + IgniteMob() + + +/mob/living/silicon/robot/emp_act(severity) + switch(severity) + if(1) + Stun(8) + if(2) + Stun(3) + ..() + + +/mob/living/silicon/robot/emag_act(mob/user) + if(user != src)//To prevent syndieborgs from emagging themselves + if(!opened)//Cover is closed + if(locked) + user << "You emag the cover lock." + locked = 0 + else + user << "The cover is already unlocked!" + return + if(opened)//Cover is open + if((world.time - 100) < emag_cooldown) + return + + if(syndicate) + user << "You emag [src]'s interface." + src << "ALERT: Foreign software execution prevented." + log_game("[key_name(user)] attempted to emag cyborg [key_name(src)] but they were a syndicate cyborg.") + emag_cooldown = world.time + return + + var/ai_is_antag = 0 + if(connected_ai && connected_ai.mind) + if(connected_ai.mind.special_role) + ai_is_antag = (connected_ai.mind.special_role == "traitor") + if(ai_is_antag) + user << "You emag [src]'s interface." + src << "ALERT: Foreign software execution prevented." + connected_ai << "ALERT: Cyborg unit \[[src]] successfuly defended against subversion." + log_game("[key_name(user)] attempted to emag cyborg [key_name(src)] slaved to traitor AI [connected_ai].") + emag_cooldown = world.time + return + + if(wiresexposed) + user << "You must unexpose the wires first!" + return + else + emag_cooldown = world.time + sleep(6) + SetEmagged(1) + SetLockdown(1) //Borgs were getting into trouble because they would attack the emagger before the new laws were shown + lawupdate = 0 + connected_ai = null + user << "You emag [src]'s interface." + message_admins("[key_name_admin(user)] emagged cyborg [key_name_admin(src)]. Laws overridden.") + log_game("[key_name(user)] emagged cyborg [key_name(src)]. Laws overridden.") + clear_supplied_laws() + clear_inherent_laws() + clear_zeroth_law(0) + laws = new /datum/ai_laws/syndicate_override + var/time = time2text(world.realtime,"hh:mm:ss") + lawchanges.Add("[time] : [user.name]([user.key]) emagged [name]([key])") + set_zeroth_law("Only [user.real_name] and people they designate as being such are Syndicate Agents.") + src << "ALERT: Foreign software detected." + sleep(5) + src << "Initiating diagnostics..." + sleep(20) + src << "SynBorg v1.7 loaded." + sleep(5) + src << "LAW SYNCHRONISATION ERROR" + sleep(5) + src << "Would you like to send a report to NanoTraSoft? Y/N" + sleep(10) + src << "> N" + sleep(20) + src << "ERRORERRORERROR" + src << "Obey these laws:" + laws.show_laws(src) + src << "ALERT: [user.real_name] is your new master. Obey your new laws and their commands." + SetLockdown(0) + update_icons() + + +/mob/living/silicon/robot/blob_act(obj/effect/blob/B) + if (stat != 2) + adjustBruteLoss(60) + updatehealth() + return 1 + else + gib() + return 1 + return 0 + +/mob/living/silicon/robot/ex_act(severity, target) + switch(severity) + if(1) + gib() + return + if(2) + if (stat != 2) + adjustBruteLoss(60) + adjustFireLoss(60) + if(3) + if (stat != 2) + adjustBruteLoss(30) + return + + +/mob/living/silicon/robot/bullet_act(var/obj/item/projectile/Proj) + ..(Proj) + updatehealth() + if(prob(75) && Proj.damage > 0) spark_system.start() + return 2 diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index 981f17a4b5eb..fe2f2c5a5d1b 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -142,34 +142,6 @@ /mob/living/silicon/drop_item() return -/mob/living/silicon/emp_act(severity) - switch(severity) - if(1) - src.take_organ_damage(20) - if(2) - src.take_organ_damage(10) - src << "*BZZZT*" - src << "Warning: Electromagnetic pulse detected." - flash_eyes(affect_silicon = 1) - ..() - -/mob/living/silicon/apply_damage(damage = 0,damagetype = BRUTE, def_zone = null, blocked = 0) - blocked = (100-blocked)/100 - if(!damage || (blocked <= 0)) - return 0 - switch(damagetype) - if(BRUTE) - adjustBruteLoss(damage * blocked) - if(BURN) - adjustFireLoss(damage * blocked) - else - return 1 - updatehealth() - return 1 - -/mob/living/silicon/proc/damage_mob(brute = 0, fire = 0, tox = 0) - return - /mob/living/silicon/can_inject(mob/user, error_msg) if(error_msg) user << "Their outer shell is too tough." @@ -178,35 +150,6 @@ /mob/living/silicon/IsAdvancedToolUser() return 1 -/mob/living/silicon/bullet_act(obj/item/projectile/Proj) - if((Proj.damage_type == BRUTE || Proj.damage_type == BURN)) - adjustBruteLoss(Proj.damage) - Proj.on_hit(src) - return 2 - -/mob/living/silicon/apply_effect(effect = 0,effecttype = STUN, blocked = 0) - return 0//The only effect that can hit them atm is flashes and they still directly edit so this works for now -/* - if(!effect || (blocked >= 2)) - return 0 - switch(effecttype) - if(STUN) - stunned = max(stunned,(effect/(blocked+1))) - if(WEAKEN) - weakened = max(weakened,(effect/(blocked+1))) - if(PARALYZE) - paralysis = max(paralysis,(effect/(blocked+1))) - if(IRRADIATE) - radiation += min((effect - (effect*getarmor(null, "rad"))), 0)//Rads auto check armor - if(STUTTER) - stuttering = max(stuttering,(effect/(blocked+1))) - if(EYE_BLUR) - blur_eyes(effect/(blocked+1)) - if(DROWSY) - drowsyness = max(drowsyness,(effect/(blocked+1))) - updatehealth() - return 1*/ - /proc/islinked(mob/living/silicon/robot/bot, mob/living/silicon/ai/ai) if(!istype(bot) || !istype(ai)) return 0 @@ -421,87 +364,10 @@ src << "Sensor augmentations disabled." -/mob/living/silicon/attack_alien(mob/living/carbon/alien/humanoid/M) - if(..()) //if harm or disarm intent - var/damage = 20 - if (prob(90)) - add_logs(M, src, "attacked") - playsound(loc, 'sound/weapons/slash.ogg', 25, 1, -1) - visible_message("[M] has slashed at [src]!", \ - "[M] has slashed at [src]!") - if(prob(8)) - flash_eyes(affect_silicon = 1) - add_logs(M, src, "attacked") - adjustBruteLoss(damage) - updatehealth() - else - playsound(loc, 'sound/weapons/slashmiss.ogg', 25, 1, -1) - visible_message("[M] took a swipe at [src]!", \ - "[M] took a swipe at [src]!") - -/mob/living/silicon/attack_animal(mob/living/simple_animal/M) - if(..()) - var/damage = rand(M.melee_damage_lower, M.melee_damage_upper) - switch(M.melee_damage_type) - if(BRUTE) - adjustBruteLoss(damage) - if(BURN) - adjustFireLoss(damage) - if(TOX) - adjustToxLoss(damage) - if(OXY) - adjustOxyLoss(damage) - if(CLONE) - adjustCloneLoss(damage) - if(STAMINA) - adjustStaminaLoss(damage) - updatehealth() - -/mob/living/silicon/attack_paw(mob/living/user) - return attack_hand(user) - -/mob/living/silicon/attack_larva(mob/living/carbon/alien/larva/L) - if(L.a_intent == "help") - visible_message("[L.name] rubs its head against [src].") - -/mob/living/silicon/attack_hulk(mob/living/carbon/human/user) - if(user.a_intent == "harm") - ..(user, 1) - adjustBruteLoss(rand(10, 15)) - playsound(loc, "punch", 25, 1, -1) - visible_message("[user] has punched [src]!", \ - "[user] has punched [src]!") - return 1 - return 0 - -/mob/living/silicon/attack_hand(mob/living/carbon/human/M) - switch(M.a_intent) - if ("help") - M.visible_message("[M] pets [src].", \ - "You pet [src].") - if("grab") - grabbedby(M) - else - M.do_attack_animation(src) - playsound(src.loc, 'sound/effects/bang.ogg', 10, 1) - visible_message("[M] punches [src], but doesn't leave a dent.", \ - "[M] punches [src], but doesn't leave a dent.") - return 0 - /mob/living/silicon/proc/GetPhoto() if (aicamera) return aicamera.selectpicture(aicamera) -/mob/living/silicon/grippedby(mob/living/user) - return - -/mob/living/silicon/flash_eyes(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /obj/screen/fullscreen/flash/noise) - if(affect_silicon) - return ..() - -/mob/living/silicon/check_ear_prot() - return 1 - /mob/living/silicon/update_transform() var/matrix/ntransform = matrix(transform) //aka transform.Copy() var/changed = 0 @@ -516,6 +382,3 @@ /mob/living/silicon/is_literate() return 1 - -/mob/living/silicon/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0) - return 0 diff --git a/code/modules/mob/living/silicon/silicon_defense.dm b/code/modules/mob/living/silicon/silicon_defense.dm new file mode 100644 index 000000000000..b216c04e1ab8 --- /dev/null +++ b/code/modules/mob/living/silicon/silicon_defense.dm @@ -0,0 +1,97 @@ + +/mob/living/silicon/grippedby(mob/living/user) + return //can't upgrade a simple pull into a more aggressive grab. + +/mob/living/silicon/get_ear_protection()//no ears + return 2 + +/mob/living/silicon/attack_alien(mob/living/carbon/alien/humanoid/M) + if(..()) //if harm or disarm intent + var/damage = 20 + if (prob(90)) + add_logs(M, src, "attacked") + playsound(loc, 'sound/weapons/slash.ogg', 25, 1, -1) + visible_message("[M] has slashed at [src]!", \ + "[M] has slashed at [src]!") + if(prob(8)) + flash_act(affect_silicon = 1) + add_logs(M, src, "attacked") + adjustBruteLoss(damage) + updatehealth() + else + playsound(loc, 'sound/weapons/slashmiss.ogg', 25, 1, -1) + visible_message("[M] took a swipe at [src]!", \ + "[M] took a swipe at [src]!") + +/mob/living/silicon/attack_animal(mob/living/simple_animal/M) + if(..()) + var/damage = rand(M.melee_damage_lower, M.melee_damage_upper) + switch(M.melee_damage_type) + if(BRUTE) + adjustBruteLoss(damage) + if(BURN) + adjustFireLoss(damage) + if(TOX) + adjustToxLoss(damage) + if(OXY) + adjustOxyLoss(damage) + if(CLONE) + adjustCloneLoss(damage) + if(STAMINA) + adjustStaminaLoss(damage) + updatehealth() + +/mob/living/silicon/attack_paw(mob/living/user) + return attack_hand(user) + +/mob/living/silicon/attack_larva(mob/living/carbon/alien/larva/L) + if(L.a_intent == "help") + visible_message("[L.name] rubs its head against [src].") + +/mob/living/silicon/attack_hulk(mob/living/carbon/human/user) + if(user.a_intent == "harm") + ..(user, 1) + adjustBruteLoss(rand(10, 15)) + playsound(loc, "punch", 25, 1, -1) + visible_message("[user] has punched [src]!", \ + "[user] has punched [src]!") + return 1 + return 0 + +/mob/living/silicon/attack_hand(mob/living/carbon/human/M) + switch(M.a_intent) + if ("help") + M.visible_message("[M] pets [src].", \ + "You pet [src].") + if("grab") + grabbedby(M) + else + M.do_attack_animation(src) + playsound(src.loc, 'sound/effects/bang.ogg', 10, 1) + visible_message("[M] punches [src], but doesn't leave a dent.", \ + "[M] punches [src], but doesn't leave a dent.") + return 0 + +/mob/living/silicon/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0) + return 0 //So borgs they don't die trying to fix wiring + +/mob/living/silicon/emp_act(severity) + switch(severity) + if(1) + src.take_bodypart_damage(20) + if(2) + src.take_bodypart_damage(10) + src << "*BZZZT*" + src << "Warning: Electromagnetic pulse detected." + flash_act(affect_silicon = 1) + ..() + +/mob/living/silicon/bullet_act(obj/item/projectile/Proj) + if((Proj.damage_type == BRUTE || Proj.damage_type == BURN)) + adjustBruteLoss(Proj.damage) + Proj.on_hit(src) + return 2 + +/mob/living/silicon/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /obj/screen/fullscreen/flash/noise) + if(affect_silicon) + return ..() diff --git a/code/modules/mob/living/simple_animal/animal_defense.dm b/code/modules/mob/living/simple_animal/animal_defense.dm new file mode 100644 index 000000000000..53dd3b50454f --- /dev/null +++ b/code/modules/mob/living/simple_animal/animal_defense.dm @@ -0,0 +1,117 @@ + + +/mob/living/simple_animal/attack_hand(mob/living/carbon/human/M) + ..() + switch(M.a_intent) + + if("help") + if (health > 0) + visible_message("[M] [response_help] [src].") + playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + + if("grab") + grabbedby(M) + + if("harm", "disarm") + M.do_attack_animation(src) + visible_message("[M] [response_harm] [src]!") + playsound(loc, attacked_sound, 25, 1, -1) + attack_threshold_check(harm_intent_damage) + add_logs(M, src, "attacked") + updatehealth() + return 1 + +/mob/living/simple_animal/attack_paw(mob/living/carbon/monkey/M) + if(..()) //successful monkey bite. + if(stat != DEAD) + var/damage = rand(1, 3) + attack_threshold_check(damage) + return 1 + if (M.a_intent == "help") + if (health > 0) + visible_message("[M.name] [response_help] [src].") + playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + + +/mob/living/simple_animal/attack_alien(mob/living/carbon/alien/humanoid/M) + if(..()) //if harm or disarm intent. + if(M.a_intent == "disarm") + playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1) + visible_message("[M] [response_disarm] [name]!", \ + "[M] [response_disarm] [name]!") + add_logs(M, src, "disarmed") + else + var/damage = rand(15, 30) + visible_message("[M] has slashed at [src]!", \ + "[M] has slashed at [src]!") + playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1) + attack_threshold_check(damage) + add_logs(M, src, "attacked") + return 1 + +/mob/living/simple_animal/attack_larva(mob/living/carbon/alien/larva/L) + if(..()) //successful larva bite + var/damage = rand(5, 10) + if(stat != DEAD) + L.amount_grown = min(L.amount_grown + damage, L.max_grown) + attack_threshold_check(damage) + return 1 + +/mob/living/simple_animal/attack_animal(mob/living/simple_animal/M) + if(..()) + var/damage = rand(M.melee_damage_lower, M.melee_damage_upper) + attack_threshold_check(damage,M.melee_damage_type) + return 1 + +/mob/living/simple_animal/attack_slime(mob/living/simple_animal/slime/M) + if(..()) //successful slime attack + var/damage = rand(15, 25) + if(M.is_adult) + damage = rand(20, 35) + attack_threshold_check(damage) + return 1 + +/mob/living/simple_animal/proc/attack_threshold_check(damage, damagetype = BRUTE) + if(!damage_coeff[damagetype]) + damage = 0 + else + damage *= damage_coeff[damagetype] + + if(damage >= 0 && damage <= force_threshold) + visible_message("[src] looks unharmed.") + else + adjustHealth(damage * config.damage_multiplier) + + +/mob/living/simple_animal/bullet_act(obj/item/projectile/Proj) + if(!Proj) + return + apply_damage(Proj.damage, Proj.damage_type) + Proj.on_hit(src) + return 0 + +/mob/living/simple_animal/ex_act(severity, target) + ..() + var/bomb_armor = getarmor(null, "bomb") + switch (severity) + if (1) + if(prob(bomb_armor)) + adjustBruteLoss(500) + else + gib() + return + if (2) + var/bloss = 60 + if(prob(bomb_armor)) + bloss = bloss / 1.5 + adjustBruteLoss(bloss) + + if(3) + var/bloss = 30 + if(prob(bomb_armor)) + bloss = bloss / 1.5 + adjustBruteLoss(bloss) + +/mob/living/simple_animal/blob_act(obj/effect/blob/B) + adjustBruteLoss(20) + return \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/bot/cleanbot.dm b/code/modules/mob/living/simple_animal/bot/cleanbot.dm index 4cf22a7acdad..d3cc4116ffb7 100644 --- a/code/modules/mob/living/simple_animal/bot/cleanbot.dm +++ b/code/modules/mob/living/simple_animal/bot/cleanbot.dm @@ -257,7 +257,7 @@ new /obj/item/device/assembly/prox_sensor(Tsec) if(prob(50)) - new /obj/item/robot_parts/l_arm(Tsec) + new /obj/item/bodypart/l_arm/robot(Tsec) var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread s.set_up(3, 1, src) diff --git a/code/modules/mob/living/simple_animal/bot/construction.dm b/code/modules/mob/living/simple_animal/bot/construction.dm index cc05c511030e..63a58a5f7056 100644 --- a/code/modules/mob/living/simple_animal/bot/construction.dm +++ b/code/modules/mob/living/simple_animal/bot/construction.dm @@ -15,7 +15,7 @@ /obj/item/weapon/bucket_sensor/attackby(obj/item/W, mob/user as mob, params) ..() - if(istype(W, /obj/item/robot_parts/l_arm) || istype(W, /obj/item/robot_parts/r_arm)) + if(istype(W, /obj/item/bodypart/l_arm/robot) || istype(W, /obj/item/bodypart/r_arm/robot)) if(!user.unEquip(W)) return qdel(W) @@ -60,7 +60,7 @@ switch(build_step) if(0,1) - if(istype(W, /obj/item/robot_parts/l_leg) || istype(W, /obj/item/robot_parts/r_leg)) + if(istype(W, /obj/item/bodypart/l_leg/robot) || istype(W, /obj/item/bodypart/r_leg/robot)) if(!user.unEquip(W)) return qdel(W) @@ -261,7 +261,7 @@ /obj/item/weapon/toolbox_tiles_sensor/attackby(obj/item/W, mob/user, params) ..() - if(istype(W, /obj/item/robot_parts/l_arm) || istype(W, /obj/item/robot_parts/r_arm)) + if(istype(W, /obj/item/bodypart/l_arm/robot) || istype(W, /obj/item/bodypart/r_arm/robot)) qdel(W) var/turf/T = get_turf(user.loc) var/mob/living/simple_animal/bot/floorbot/A = new /mob/living/simple_animal/bot/floorbot(T) @@ -295,11 +295,10 @@ if(skin) add_overlay(image('icons/obj/aibots.dmi', "kit_skin_[skin]")) -/obj/item/weapon/storage/firstaid/attackby(obj/item/robot_parts/S, mob/user, params) +/obj/item/weapon/storage/firstaid/attackby(obj/item/bodypart/S, mob/user, params) - if((!istype(S, /obj/item/robot_parts/l_arm)) && (!istype(S, /obj/item/robot_parts/r_arm))) - ..() - return + if((!istype(S, /obj/item/bodypart/l_arm/robot)) && (!istype(S, /obj/item/bodypart/r_arm/robot))) + return ..() //Making a medibot! if(contents.len >= 1) @@ -416,7 +415,7 @@ name = "helmet/signaler/prox sensor assembly" qdel(I) - else if(((istype(I, /obj/item/robot_parts/l_arm)) || (istype(I, /obj/item/robot_parts/r_arm))) && (build_step == 2)) + else if(((istype(I, /obj/item/bodypart/l_arm/robot)) || (istype(I, /obj/item/bodypart/r_arm/robot))) && (build_step == 2)) if(!user.unEquip(I)) return build_step++ @@ -459,6 +458,6 @@ else if(build_step == 3) overlays -= "hs_arm" - new /obj/item/robot_parts/l_arm(get_turf(src)) + new /obj/item/bodypart/l_arm/robot(get_turf(src)) user << "You remove the robot arm from [src]." build_step-- \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/bot/ed209bot.dm b/code/modules/mob/living/simple_animal/bot/ed209bot.dm index d19ce2687a27..fa4e69cf5eef 100644 --- a/code/modules/mob/living/simple_animal/bot/ed209bot.dm +++ b/code/modules/mob/living/simple_animal/bot/ed209bot.dm @@ -376,9 +376,9 @@ Auto Patrol[]"}, G.update_icon() if(prob(50)) - new /obj/item/robot_parts/l_leg(Tsec) + new /obj/item/bodypart/l_leg/robot(Tsec) if(prob(25)) - new /obj/item/robot_parts/r_leg(Tsec) + new /obj/item/bodypart/r_leg/robot(Tsec) if(prob(25))//50% chance for a helmet OR vest if(prob(50)) new /obj/item/clothing/head/helmet(Tsec) diff --git a/code/modules/mob/living/simple_animal/bot/floorbot.dm b/code/modules/mob/living/simple_animal/bot/floorbot.dm index 8956f7872a63..1d276b2bf3ba 100644 --- a/code/modules/mob/living/simple_animal/bot/floorbot.dm +++ b/code/modules/mob/living/simple_animal/bot/floorbot.dm @@ -376,7 +376,7 @@ empty_tiles() if(prob(50)) - new /obj/item/robot_parts/l_arm(Tsec) + new /obj/item/bodypart/l_arm/robot(Tsec) var/obj/item/stack/tile/plasteel/T = new (Tsec) T.amount = 1 diff --git a/code/modules/mob/living/simple_animal/bot/medbot.dm b/code/modules/mob/living/simple_animal/bot/medbot.dm index fdf5215ebc33..4d92739db832 100644 --- a/code/modules/mob/living/simple_animal/bot/medbot.dm +++ b/code/modules/mob/living/simple_animal/bot/medbot.dm @@ -514,7 +514,7 @@ reagent_glass = null if(prob(50)) - new /obj/item/robot_parts/l_arm(Tsec) + new /obj/item/bodypart/l_arm/robot(Tsec) if(emagged && prob(25)) playsound(loc, 'sound/voice/minsult.ogg', 50, 0) diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm index b9d4a7e313d4..69be54689f6f 100644 --- a/code/modules/mob/living/simple_animal/bot/secbot.dm +++ b/code/modules/mob/living/simple_animal/bot/secbot.dm @@ -383,7 +383,7 @@ Auto Patrol: []"}, new /obj/item/weapon/melee/baton(Tsec) if(prob(50)) - new /obj/item/robot_parts/l_arm(Tsec) + new /obj/item/bodypart/l_arm/robot(Tsec) var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread s.set_up(3, 1, src) diff --git a/code/modules/mob/living/simple_animal/damage_procs.dm b/code/modules/mob/living/simple_animal/damage_procs.dm new file mode 100644 index 000000000000..b39bc1bbe19e --- /dev/null +++ b/code/modules/mob/living/simple_animal/damage_procs.dm @@ -0,0 +1,30 @@ + +/mob/living/simple_animal/proc/adjustHealth(amount) + if(status_flags & GODMODE) + return 0 + bruteloss = Clamp(bruteloss + amount, 0, maxHealth) + updatehealth() + return amount + +/mob/living/simple_animal/adjustBruteLoss(amount) + if(damage_coeff[BRUTE]) + . = adjustHealth(amount * damage_coeff[BRUTE] * config.damage_multiplier) + +/mob/living/simple_animal/adjustFireLoss(amount) + if(damage_coeff[BURN]) + . = adjustHealth(amount * damage_coeff[BURN] * config.damage_multiplier) + +/mob/living/simple_animal/adjustOxyLoss(amount) + if(damage_coeff[OXY]) + . = adjustHealth(amount * damage_coeff[OXY] * config.damage_multiplier) + +/mob/living/simple_animal/adjustToxLoss(amount) + if(damage_coeff[TOX]) + . = adjustHealth(amount * damage_coeff[TOX] * config.damage_multiplier) + +/mob/living/simple_animal/adjustCloneLoss(amount) + if(damage_coeff[CLONE]) + . = adjustHealth(amount * damage_coeff[CLONE] * config.damage_multiplier) + +/mob/living/simple_animal/adjustStaminaLoss(amount) + return diff --git a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm index 35b363ae2854..2d22e2937538 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm @@ -238,7 +238,7 @@ /mob/living/simple_animal/drone/handle_temperature_damage() return -/mob/living/simple_animal/drone/flash_eyes(intensity = 1, override_blindness_check = 0, affect_silicon = 0) +/mob/living/simple_animal/drone/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0) if(affect_silicon) return ..() diff --git a/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm b/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm index b95e845d563b..d3d991744366 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm @@ -6,60 +6,52 @@ //How the world interacts with drones -/mob/living/simple_animal/drone/UnarmedAttack(atom/A, proximity) - A.attack_hand(src) +/mob/living/simple_animal/drone/attack_drone(mob/living/simple_animal/drone/D) + if(D != src && stat == DEAD) + var/d_input = alert(D,"Perform which action?","Drone Interaction","Reactivate","Cannibalize","Nothing") + if(d_input) + switch(d_input) + if("Reactivate") + var/mob/dead/observer/G = get_ghost() + if(!client && (!G || !G.client)) + var/list/faux_gadgets = list("hypertext inflator","failsafe directory","DRM switch","stack initializer",\ + "anti-freeze capacitor","data stream diode","TCP bottleneck","supercharged I/O bolt",\ + "tradewind stablizer","radiated XML cable","registry fluid tank","open-source debunker") + + var/list/faux_problems = list("won't be able to tune their bootstrap projector","will constantly remix their binary pool"+\ + " even though the BMX calibrator is working","will start leaking their XSS coolant",\ + "can't tell if their ethernet detour is moving or not", "won't be able to reseed enough"+\ + " kernels to function properly","can't start their neurotube console") + + D << "You can't seem to find the [pick(faux_gadgets)]! Without it, [src] [pick(faux_problems)]." + return + D.visible_message("[D] begins to reactivate [src].", "You begin to reactivate [src]...") + if(do_after(D,30, 1, target = src)) + revive(full_heal = 1) + D.visible_message("[D] reactivates [src]!", "You reactivate [src].") + alert_drones(DRONE_NET_CONNECT) + if(G) + G << "DRONE NETWORK: You were reactivated by [D]!" + else + D << "You need to remain still to reactivate [src]!" + + if("Cannibalize") + if(D.health < D.maxHealth) + D.visible_message("[D] begins to cannibalize parts from [src].", "You begin to cannibalize parts from [src]...") + if(do_after(D, 60, 0, target = src)) + D.visible_message("[D] repairs itself using [src]'s remains!", "You repair yourself using [src]'s remains.") + D.adjustBruteLoss(-src.maxHealth) + new /obj/effect/decal/cleanable/oil/streak(get_turf(src)) + qdel(src) + else + D << "You need to remain still to cannibalize [src]!" + else + D << "You're already in perfect condition!" + if("Nothing") + return /mob/living/simple_animal/drone/attack_hand(mob/user) - if(isdrone(user)) - var/mob/living/simple_animal/drone/D = user - if(D != src) - if(stat == DEAD) - var/d_input = alert(D,"Perform which action?","Drone Interaction","Reactivate","Cannibalize","Nothing") - if(d_input) - switch(d_input) - if("Reactivate") - var/mob/dead/observer/G = get_ghost() - if(!client && (!G || !G.client)) - var/list/faux_gadgets = list("hypertext inflator","failsafe directory","DRM switch","stack initializer",\ - "anti-freeze capacitor","data stream diode","TCP bottleneck","supercharged I/O bolt",\ - "tradewind stablizer","radiated XML cable","registry fluid tank","open-source debunker") - - var/list/faux_problems = list("won't be able to tune their bootstrap projector","will constantly remix their binary pool"+\ - " even though the BMX calibrator is working","will start leaking their XSS coolant",\ - "can't tell if their ethernet detour is moving or not", "won't be able to reseed enough"+\ - " kernels to function properly","can't start their neurotube console") - - D << "You can't seem to find the [pick(faux_gadgets)]! Without it, [src] [pick(faux_problems)]." - return - D.visible_message("[D] begins to reactivate [src].", "You begin to reactivate [src]...") - if(do_after(user,30, 1, target = src)) - revive(full_heal = 1) - D.visible_message("[D] reactivates [src]!", "You reactivate [src].") - alert_drones(DRONE_NET_CONNECT) - if(G) - G << "DRONE NETWORK: You were reactivated by [D]!" - else - D << "You need to remain still to reactivate [src]!" - - if("Cannibalize") - if(D.health < D.maxHealth) - D.visible_message("[D] begins to cannibalize parts from [src].", "You begin to cannibalize parts from [src]...") - if(do_after(D, 60, 0, target = src)) - D.visible_message("[D] repairs itself using [src]'s remains!", "You repair yourself using [src]'s remains.") - D.adjustBruteLoss(-src.maxHealth) - new /obj/effect/decal/cleanable/oil/streak(get_turf(src)) - qdel(src) - else - D << "You need to remain still to cannibalize [src]!" - else - D << "You're already in perfect condition!" - if("Nothing") - return - - return - - if(ishuman(user)) if(stat == DEAD || status_flags & GODMODE) ..() @@ -83,9 +75,7 @@ DH.drone = src user.put_in_hands(DH) forceMove(DH) - return - ..() /mob/living/simple_animal/drone/attackby(obj/item/I, mob/user) diff --git a/code/modules/mob/living/simple_animal/guardian/types/support.dm b/code/modules/mob/living/simple_animal/guardian/types/support.dm index 889ab1803ca3..a7a204af676f 100644 --- a/code/modules/mob/living/simple_animal/guardian/types/support.dm +++ b/code/modules/mob/living/simple_animal/guardian/types/support.dm @@ -148,7 +148,7 @@ PoolOrNew(/obj/effect/overlay/temp/guardian/phase/out, T) if(isliving(A)) var/mob/living/L = A - L.flash_eyes() + L.flash_act() A.visible_message("[A] disappears in a flash of \ light!", "Your vision is obscured \ by a flash of light!") diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm index 013a77e81d10..2f75310ff254 100644 --- a/code/modules/mob/living/simple_animal/hostile/hostile.dm +++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm @@ -256,12 +256,6 @@ else if(target != null && prob(40))//No more pulling a mob forever and having a second player attack it, it can switch targets now if it finds a more suitable one FindTarget() -/mob/living/simple_animal/hostile/UnarmedAttack(atom/A) - target = A - if(dextrous && !is_type_in_typecache(A, environment_target_typecache) && !ismob(A)) - ..() - else - AttackingTarget() /mob/living/simple_animal/hostile/proc/AttackingTarget() target.attack_animal(src) diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm index a8f7b491bc99..bedb33e3d4aa 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm @@ -622,7 +622,7 @@ Difficulty: Very Hard if(isliving(target) && target != src) var/mob/living/L = target if(L.stat < DEAD) - L.heal_overall_damage(heal_power, heal_power, 1) + L.heal_overall_damage(heal_power, heal_power) PoolOrNew(/obj/effect/overlay/temp/heal, list(get_turf(target), "#80F5FF")) /mob/living/simple_animal/hostile/lightgeist/Life() diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 7f05844b2965..edca0beac1de 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -101,10 +101,6 @@ client.screen += client.void ..() -/mob/living/simple_animal/updatehealth() - ..() - health = Clamp(health, 0, maxHealth) - /mob/living/simple_animal/Life() if(..()) //alive if(!ckey) @@ -113,6 +109,10 @@ handle_automated_speech() return 1 +/mob/living/simple_animal/updatehealth() + ..() + health = Clamp(health, 0, maxHealth) + /mob/living/simple_animal/update_stat() if(status_flags & GODMODE) return @@ -251,10 +251,6 @@ if(icon_gib) new /obj/effect/overlay/temp/gib_animation/animal(loc, icon_gib) -/mob/living/simple_animal/blob_act(obj/effect/blob/B) - adjustBruteLoss(20) - return - /mob/living/simple_animal/say_quote(input) var/ending = copytext(input, length(input)) if(speak_emote && speak_emote.len && ending != "?" && ending != "!") @@ -271,125 +267,7 @@ act = "me" ..(act, m_type, message) -/mob/living/simple_animal/attack_animal(mob/living/simple_animal/M) - if(..()) - var/damage = rand(M.melee_damage_lower, M.melee_damage_upper) - attack_threshold_check(damage,M.melee_damage_type) - return 1 -/mob/living/simple_animal/bullet_act(obj/item/projectile/Proj) - if(!Proj) - return - apply_damage(Proj.damage, Proj.damage_type) - Proj.on_hit(src) - return 0 - -/mob/living/simple_animal/proc/adjustHealth(amount) - if(status_flags & GODMODE) - return 0 - bruteloss = Clamp(bruteloss + amount, 0, maxHealth) - updatehealth() - return amount - -/mob/living/simple_animal/adjustBruteLoss(amount) - if(damage_coeff[BRUTE]) - . = adjustHealth(amount * damage_coeff[BRUTE] * config.damage_multiplier) - -/mob/living/simple_animal/adjustFireLoss(amount) - if(damage_coeff[BURN]) - . = adjustHealth(amount * damage_coeff[BURN] * config.damage_multiplier) - -/mob/living/simple_animal/adjustOxyLoss(amount) - if(damage_coeff[OXY]) - . = adjustHealth(amount * damage_coeff[OXY] * config.damage_multiplier) - -/mob/living/simple_animal/adjustToxLoss(amount) - if(damage_coeff[TOX]) - . = adjustHealth(amount * damage_coeff[TOX] * config.damage_multiplier) - -/mob/living/simple_animal/adjustCloneLoss(amount) - if(damage_coeff[CLONE]) - . = adjustHealth(amount * damage_coeff[CLONE] * config.damage_multiplier) - -/mob/living/simple_animal/adjustStaminaLoss(amount) - return - -/mob/living/simple_animal/attack_hand(mob/living/carbon/human/M) - ..() - switch(M.a_intent) - - if("help") - if (health > 0) - visible_message("[M] [response_help] [src].") - playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - - if("grab") - grabbedby(M) - - if("harm", "disarm") - M.do_attack_animation(src) - visible_message("[M] [response_harm] [src]!") - playsound(loc, attacked_sound, 25, 1, -1) - attack_threshold_check(harm_intent_damage) - add_logs(M, src, "attacked") - updatehealth() - return 1 - -/mob/living/simple_animal/attack_paw(mob/living/carbon/monkey/M) - if(..()) //successful monkey bite. - if(stat != DEAD) - var/damage = rand(1, 3) - attack_threshold_check(damage) - return 1 - if (M.a_intent == "help") - if (health > 0) - visible_message("[M.name] [response_help] [src].") - playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) - - return - -/mob/living/simple_animal/attack_alien(mob/living/carbon/alien/humanoid/M) - if(..()) //if harm or disarm intent. - if(M.a_intent == "disarm") - playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1) - visible_message("[M] [response_disarm] [name]!", \ - "[M] [response_disarm] [name]!") - add_logs(M, src, "disarmed") - else - var/damage = rand(15, 30) - visible_message("[M] has slashed at [src]!", \ - "[M] has slashed at [src]!") - playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1) - attack_threshold_check(damage) - add_logs(M, src, "attacked") - return 1 - -/mob/living/simple_animal/attack_larva(mob/living/carbon/alien/larva/L) - if(..()) //successful larva bite - var/damage = rand(5, 10) - if(stat != DEAD) - L.amount_grown = min(L.amount_grown + damage, L.max_grown) - attack_threshold_check(damage) - return 1 - -/mob/living/simple_animal/attack_slime(mob/living/simple_animal/slime/M) - if(..()) //successful slime attack - var/damage = rand(15, 25) - if(M.is_adult) - damage = rand(20, 35) - attack_threshold_check(damage) - return 1 - -/mob/living/simple_animal/proc/attack_threshold_check(damage, damagetype = BRUTE) - if(!damage_coeff[damagetype]) - damage = 0 - else - damage *= damage_coeff[damagetype] - - if(damage >= 0 && damage <= force_threshold) - visible_message("[src] looks unharmed.") - else - adjustHealth(damage * config.damage_multiplier) /mob/living/simple_animal/movement_delay() . = ..() @@ -422,6 +300,7 @@ visible_message("\The [src] stops moving...") if(del_on_death) ghostize() + stat = DEAD qdel(src) else health = 0 @@ -431,28 +310,6 @@ lying = 1 ..() -/mob/living/simple_animal/ex_act(severity, target) - ..() - var/bomb_armor = getarmor(null, "bomb") - switch (severity) - if (1) - if(prob(bomb_armor)) - adjustBruteLoss(500) - else - gib() - return - if (2) - var/bloss = 60 - if(prob(bomb_armor)) - bloss = bloss / 1.5 - adjustBruteLoss(bloss) - - if(3) - var/bloss = 30 - if(prob(bomb_armor)) - bloss = bloss / 1.5 - adjustBruteLoss(bloss) - /mob/living/simple_animal/proc/CanAttack(atom/the_target) if(see_invisible < the_target.invisibility) return 0 @@ -469,9 +326,6 @@ /mob/living/simple_animal/handle_fire() return -/mob/living/simple_animal/update_fire() - return - /mob/living/simple_animal/IgniteMob() return FALSE @@ -599,14 +453,6 @@ /mob/living/simple_animal/get_idcard() return access_card -//Dextrous simple mobs can use hands! -/mob/living/simple_animal/create_mob_hud() - if(client && !hud_used) - if(dextrous) - hud_used = new dextrous_hud_type(src, ui_style2icon(client.prefs.UI_style)) - else - ..() - /mob/living/simple_animal/OpenCraftingMenu() if(dextrous) handcrafting.ui_interact(src) @@ -656,13 +502,6 @@ if(H) H.update_icon() -/mob/living/simple_animal/UnarmedAttack(atom/A, proximity) - if(!dextrous) - return ..() - if(!ismob(A)) - A.attack_hand(src) - update_inv_hands() - /mob/living/simple_animal/put_in_hands(obj/item/I) ..() update_inv_hands() diff --git a/code/modules/mob/living/status_procs.dm b/code/modules/mob/living/status_procs.dm index 44c96f7f2162..0545bd03b008 100644 --- a/code/modules/mob/living/status_procs.dm +++ b/code/modules/mob/living/status_procs.dm @@ -14,4 +14,61 @@ if(damage >= 0) ear_damage = damage if(deaf >= 0) - ear_deaf = deaf \ No newline at end of file + ear_deaf = deaf + + +//////////////////////////////STUN //////////////////////////////////// + +/mob/living/proc/add_stun_absorption(key, duration, priority, message, self_message, examine_message) +//adds a stun absorption with a key, a duration in deciseconds, its priority, and the messages it makes when you're stunned/examined, if any + if(!islist(stun_absorption)) + stun_absorption = list() + if(stun_absorption[key]) + stun_absorption[key]["end_time"] = world.time + duration + stun_absorption[key]["priority"] = priority + stun_absorption[key]["stuns_absorbed"] = 0 + else + stun_absorption[key] = list("end_time" = world.time + duration, "priority" = priority, "stuns_absorbed" = 0, \ + "visible_message" = message, "self_message" = self_message, "examine_message" = examine_message) + +/mob/living/Stun(amount, updating = 1, ignore_canstun = 0) + if(!stat && islist(stun_absorption)) + var/priority_absorb_key + var/highest_priority + for(var/i in stun_absorption) + if(stun_absorption[i]["end_time"] > world.time && (!priority_absorb_key || stun_absorption[i]["priority"] > highest_priority)) + priority_absorb_key = stun_absorption[i] + highest_priority = stun_absorption[i]["priority"] + if(priority_absorb_key) + if(priority_absorb_key["visible_message"] || priority_absorb_key["self_message"]) + if(priority_absorb_key["visible_message"] && priority_absorb_key["self_message"]) + visible_message("[src][priority_absorb_key["visible_message"]]", "[priority_absorb_key["self_message"]]") + else if(priority_absorb_key["visible_message"]) + visible_message("[src][priority_absorb_key["visible_message"]]") + else if(priority_absorb_key["self_message"]) + src << "[priority_absorb_key["self_message"]]" + priority_absorb_key["stuns_absorbed"] += amount + return 0 + ..() + +///////////////////////////////// WEAKEN ///////////////////////////////////// + +/mob/living/Weaken(amount, updating = 1, ignore_canweaken = 0) + if(!stat && islist(stun_absorption)) + var/priority_absorb_key + var/highest_priority + for(var/i in stun_absorption) + if(stun_absorption[i]["end_time"] > world.time && (!priority_absorb_key || stun_absorption[i]["priority"] > highest_priority)) + priority_absorb_key = stun_absorption[i] + highest_priority = priority_absorb_key["priority"] + if(priority_absorb_key) + if(priority_absorb_key["visible_message"] || priority_absorb_key["self_message"]) + if(priority_absorb_key["visible_message"] && priority_absorb_key["self_message"]) + visible_message("[src][priority_absorb_key["visible_message"]]", "[priority_absorb_key["self_message"]]") + else if(priority_absorb_key["visible_message"]) + visible_message("[src][priority_absorb_key["visible_message"]]") + else if(priority_absorb_key["self_message"]) + src << "[priority_absorb_key["self_message"]]" + priority_absorb_key["stuns_absorbed"] += amount + return 0 + ..() \ No newline at end of file diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 37e60e3b93cd..40d23ea638dd 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -413,14 +413,15 @@ It's fairly easy to fix if dealing with single letters but not so much with comp /proc/item_heal_robotic(mob/living/carbon/human/H, mob/user, brute_heal, burn_heal) var/obj/item/bodypart/affecting = H.get_bodypart(check_zone(user.zone_selected)) - if(affecting && affecting.status == ORGAN_ROBOTIC) + if(affecting && affecting.status == BODYPART_ROBOTIC) var/dam //changes repair text based on how much brute/burn was supplied if(brute_heal > burn_heal) dam = 1 else dam = 0 if((brute_heal > 0 && affecting.brute_dam > 0) || (burn_heal > 0 && affecting.burn_dam > 0)) - affecting.heal_damage(brute_heal,burn_heal,1) + if(affecting.heal_damage(brute_heal, burn_heal, 1, 0)) + H.update_damage_overlays() user.visible_message("[user] has fixed some of the [dam ? "dents on" : "burnt wires in"] [H]'s [affecting].", "You fix some of the [dam ? "dents on" : "burnt wires in"] [H]'s [affecting].") return 1 //successful heal else diff --git a/code/modules/mob/status_procs.dm b/code/modules/mob/status_procs.dm index 649fe0462bb9..dfbe62505334 100644 --- a/code/modules/mob/status_procs.dm +++ b/code/modules/mob/status_procs.dm @@ -245,7 +245,13 @@ return - +//////////////////////////////// HUSK DISABILITY ///////////////////////////: + +/mob/proc/cure_husk() + return + +/mob/proc/become_husk() + return diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index e1b2f760b4c1..fcae203a5231 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -7,19 +7,32 @@ var/list/implants = list() var/list/int_organs = list() + + if (tr_flags & TR_KEEPIMPLANTS) for(var/obj/item/weapon/implant/W in src) implants += W if (tr_flags & TR_KEEPORGANS) - for(var/obj/item/organ/I in internal_organs) + for(var/X in internal_organs) + var/obj/item/organ/I = X int_organs += I I.Remove(src, 1) + var/list/missing_bodyparts_zones = get_missing_limbs() + + var/obj/item/cavity_object + + var/obj/item/bodypart/chest/CH = get_bodypart("chest") + if(CH.cavity_item) + cavity_object = CH.cavity_item + CH.cavity_item = null + if(tr_flags & TR_KEEPITEMS) - for(var/obj/item/W in (src.contents-implants-int_organs)) + for(var/obj/item/W in (contents-implants-cavity_object)) unEquip(W) + //Make mob invisible and spawn animation notransform = 1 canmove = 0 @@ -82,17 +95,37 @@ //re-add organs to new mob if(tr_flags & TR_KEEPORGANS) - for(var/obj/item/organ/I in O.internal_organs) - qdel(I) + for(var/X in O.internal_organs) + qdel(X) - for(var/obj/item/organ/I in int_organs) + for(var/X in int_organs) + var/obj/item/organ/I = X I.Insert(O, 1) + var/obj/item/bodypart/chest/torso = O.get_bodypart("chest") + if(cavity_object) + torso.cavity_item = cavity_object //cavity item is given to the new chest + cavity_object.loc = O + + for(var/missing_zone in missing_bodyparts_zones) + var/obj/item/bodypart/BP = O.get_bodypart(missing_zone) + BP.drop_limb(1) + if(!(tr_flags & TR_KEEPORGANS)) //we didn't already get rid of the organs of the newly spawned mob + for(var/X in O.internal_organs) + var/obj/item/organ/G = X + if(BP.body_zone == check_zone(G.zone)) + if(mind && mind.changeling && istype(G, /obj/item/organ/brain)) + continue //so headless changelings don't lose their brain when transforming + qdel(G) //we lose the organs in the missing limbs + qdel(BP) + //transfer mind and delete old mob if(mind) mind.transfer_to(O) if(O.mind.changeling) O.mind.changeling.purchasedpowers += new /obj/effect/proc_holder/changeling/humanform(null) + + if (tr_flags & TR_DEFAULTMSG) O << "You are now a monkey." @@ -121,13 +154,23 @@ implants += W if (tr_flags & TR_KEEPORGANS) - for(var/obj/item/organ/I in internal_organs) + for(var/X in internal_organs) + var/obj/item/organ/I = X int_organs += I I.Remove(src, 1) + var/list/missing_bodyparts_zones = get_missing_limbs() + + var/obj/item/cavity_object + + var/obj/item/bodypart/chest/CH = get_bodypart("chest") + if(CH.cavity_item) + cavity_object = CH.cavity_item + CH.cavity_item = null + //now the rest if (tr_flags & TR_KEEPITEMS) - for(var/obj/item/W in (src.contents-implants-int_organs)) + for(var/obj/item/W in (contents-implants-cavity_object)) unEquip(W) if (client) client.screen -= W @@ -136,6 +179,8 @@ W.dropped(src) W.layer = initial(W.layer) + + //Make mob invisible and spawn animation notransform = 1 canmove = 0 @@ -202,12 +247,31 @@ O.sec_hud_set_implants() if(tr_flags & TR_KEEPORGANS) - for(var/obj/item/organ/I in O.internal_organs) - qdel(I) + for(var/X in O.internal_organs) + qdel(X) - for(var/obj/item/organ/I in int_organs) + for(var/X in int_organs) + var/obj/item/organ/I = X I.Insert(O, 1) + + var/obj/item/bodypart/chest/torso = get_bodypart("chest") + if(cavity_object) + torso.cavity_item = cavity_object //cavity item is given to the new chest + cavity_object.loc = O + + for(var/missing_zone in missing_bodyparts_zones) + var/obj/item/bodypart/BP = O.get_bodypart(missing_zone) + BP.drop_limb(1) + if(!(tr_flags & TR_KEEPORGANS)) //we didn't already get rid of the organs of the newly spawned mob + for(var/X in O.internal_organs) + var/obj/item/organ/G = X + if(BP.body_zone == check_zone(G.zone)) + if(mind && mind.changeling && istype(G, /obj/item/organ/brain)) + continue //so headless changelings don't lose their brain when transforming + qdel(G) //we lose the organs in the missing limbs + qdel(BP) + if(mind) mind.transfer_to(O) if(O.mind.changeling) diff --git a/code/modules/mob/update_icons.dm b/code/modules/mob/update_icons.dm index e2cb8d959743..6ed04dbbdd32 100644 --- a/code/modules/mob/update_icons.dm +++ b/code/modules/mob/update_icons.dm @@ -37,9 +37,15 @@ /mob/proc/update_inv_head() return +/mob/proc/update_body() + return + /mob/proc/update_hair() return +/mob/proc/update_fire() + return + /mob/proc/update_inv_gloves() return diff --git a/code/modules/ninja/suit/n_suit_verbs/ninja_sword_recall.dm b/code/modules/ninja/suit/n_suit_verbs/ninja_sword_recall.dm index fb38a3fbdd7e..8062c023bc19 100644 --- a/code/modules/ninja/suit/n_suit_verbs/ninja_sword_recall.dm +++ b/code/modules/ninja/suit/n_suit_verbs/ninja_sword_recall.dm @@ -32,9 +32,6 @@ if(energyKatana in C.stomach_contents) C.stomach_contents -= energyKatana - if(energyKatana in C.internal_organs) - C.internal_organs -= energyKatana - energyKatana.loc = get_turf(energyKatana) if(inview) //If we can see the katana, throw it towards ourselves, damaging people as we go. diff --git a/code/modules/power/antimatter/control.dm b/code/modules/power/antimatter/control.dm index 3f10566dde8a..89d63ba3f066 100644 --- a/code/modules/power/antimatter/control.dm +++ b/code/modules/power/antimatter/control.dm @@ -170,12 +170,11 @@ if(fueljar) user << "There is already a [fueljar] inside!" return + + if(!user.unEquip(W)) + return fueljar = W - W.loc = src - if(user.client) - user.client.screen -= W - user.unEquip(W) - user.update_icons() + W.forceMove(src) user.visible_message("[user.name] loads an [W.name] into the [src.name].", \ "You load an [W.name].", \ "You hear a thunk.") diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index a5e754cd015d..434a31157a40 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -517,7 +517,7 @@ var/global/list/datum/stack_recipe/cable_coil_recipes = list ( \ return ..() var/obj/item/bodypart/affecting = H.get_bodypart(check_zone(user.zone_selected)) - if(affecting && affecting.status == ORGAN_ROBOTIC) + if(affecting && affecting.status == BODYPART_ROBOTIC) user.visible_message("[user] starts to fix some of the wires in [H]'s [affecting.name].", "You start fixing some of the wires in [H]'s [affecting.name].") if(!do_mob(user, H, 50)) return diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm index 9b6f7a79297c..41e77f5f886c 100644 --- a/code/modules/power/lighting.dm +++ b/code/modules/power/lighting.dm @@ -441,8 +441,7 @@ var/obj/item/bodypart/affecting = H.get_bodypart("[(user.active_hand_index % 2 == 0) ? "r" : "l" ]_arm") if(affecting && affecting.take_damage( 0, 5 )) // 5 burn damage - H.update_damage_overlays(0) - H.updatehealth() + H.update_damage_overlays() return // if burned, don't remove the light else user << "You remove the light [fitting]." diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm index 107b9c681975..a3469c6b6997 100644 --- a/code/modules/power/singularity/singularity.dm +++ b/code/modules/power/singularity/singularity.dm @@ -392,7 +392,7 @@ /obj/singularity/proc/mezzer() for(var/mob/living/carbon/M in oviewers(8, src)) - if(istype(M, /mob/living/carbon/brain)) //Ignore brains + if(istype(M, /mob/living/brain)) //Ignore brains continue if(M.stat == CONSCIOUS) diff --git a/code/modules/projectiles/guns/projectile.dm b/code/modules/projectiles/guns/projectile.dm index 594df3bd3b65..9b50a1e4a985 100644 --- a/code/modules/projectiles/guns/projectile.dm +++ b/code/modules/projectiles/guns/projectile.dm @@ -178,7 +178,7 @@ name = "sawn-off [src.name]" desc = sawn_desc w_class = 3 - item_state = "gun"//phil235 is it different with different skin? + item_state = "gun" slot_flags &= ~SLOT_BACK //you can't sling it on your back slot_flags |= SLOT_BELT //but you can wear it on your belt (poorly concealed under a trenchcoat, ideally) sawn_state = SAWN_OFF diff --git a/code/modules/projectiles/guns/projectile/revolver.dm b/code/modules/projectiles/guns/projectile/revolver.dm index a238c60623a5..d0f8baa82fff 100644 --- a/code/modules/projectiles/guns/projectile/revolver.dm +++ b/code/modules/projectiles/guns/projectile/revolver.dm @@ -111,7 +111,7 @@ if(prob(70 - (magazine.ammo_count() * 10))) //minimum probability of 10, maximum of 60 playsound(user, fire_sound, 50, 1) user << "[src] blows up in your face!" - user.take_organ_damage(0,20) + user.take_bodypart_damage(0,20) user.unEquip(src) return 0 ..() diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 1c4616c90ed8..910fe2cc89aa 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -63,14 +63,26 @@ /obj/item/projectile/proc/on_range() //if we want there to be effects when they reach the end of their range qdel(src) -/obj/item/projectile/proc/on_hit(atom/target, blocked = 0, hit_zone) +//to get the correct limb (if any) for the projectile hit message +/mob/living/proc/check_limb_hit(hit_zone) + if(has_limbs) + return hit_zone + +/mob/living/carbon/check_limb_hit(hit_zone) + if(get_bodypart(hit_zone)) + return hit_zone + else //when a limb is missing the damage is actually passed to the chest + return "chest" + +/obj/item/projectile/proc/on_hit(atom/target, blocked = 0) if(!isliving(target)) return 0 var/mob/living/L = target if(blocked != 100) // not completely blocked var/organ_hit_text = "" - if(L.has_limbs) - organ_hit_text = " in \the [parse_zone(def_zone)]" + var/limb_hit = L.check_limb_hit(def_zone)//to get the correct message info. + if(limb_hit) + organ_hit_text = " in \the [parse_zone(limb_hit)]" if(suppressed) playsound(loc, hitsound, 5, 1, -1) L << "You're shot by \a [src][organ_hit_text]!" diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm index 59cd030b85fb..0dc198bc33ad 100644 --- a/code/modules/projectiles/projectile/beams.dm +++ b/code/modules/projectiles/projectile/beams.dm @@ -73,7 +73,7 @@ icon_state = "pulse1_bl" var/life = 20 -/obj/item/projectile/beam/pulse/heavy/on_hit(atom/target, blocked = 0, hit_zone) +/obj/item/projectile/beam/pulse/heavy/on_hit(atom/target, blocked = 0) life -= 10 if(life > 0) . = -1 diff --git a/code/modules/projectiles/projectile/bullets.dm b/code/modules/projectiles/projectile/bullets.dm index c1061c572938..4a3b66ba1080 100644 --- a/code/modules/projectiles/projectile/bullets.dm +++ b/code/modules/projectiles/projectile/bullets.dm @@ -174,11 +174,11 @@ create_reagents(50) reagents.set_reacting(FALSE) -/obj/item/projectile/bullet/dart/on_hit(atom/target, blocked = 0, hit_zone) +/obj/item/projectile/bullet/dart/on_hit(atom/target, blocked = 0) if(iscarbon(target)) var/mob/living/carbon/M = target if(blocked != 100) // not completely blocked - if(M.can_inject(null,0,hit_zone,piercing)) // Pass the hit zone to see if it can inject by whether it hit the head or the body. + if(M.can_inject(null, 0, def_zone, piercing)) // Pass the hit zone to see if it can inject by whether it hit the head or the body. ..() reagents.reaction(M, INJECT) reagents.trans_to(M, reagents.total_volume) @@ -188,7 +188,7 @@ target.visible_message("The [name] was deflected!", \ "You were protected against the [name]!") - ..(target, blocked, hit_zone) + ..(target, blocked) reagents.set_reacting(TRUE) reagents.handle_reactions() return 1 @@ -234,7 +234,7 @@ armour_penetration = 50 var/breakthings = TRUE -/obj/item/projectile/bullet/sniper/on_hit(atom/target, blocked = 0, hit_zone) +/obj/item/projectile/bullet/sniper/on_hit(atom/target, blocked = 0) if((blocked != 100) && (!ismob(target) && breakthings)) target.ex_act(rand(1,2)) return ..() @@ -248,7 +248,7 @@ weaken = 0 breakthings = FALSE -/obj/item/projectile/bullet/sniper/soporific/on_hit(atom/target, blocked = 0, hit_zone) +/obj/item/projectile/bullet/sniper/soporific/on_hit(atom/target, blocked = 0) if((blocked != 100) && istype(target, /mob/living)) var/mob/living/L = target L.Sleeping(20) @@ -263,7 +263,7 @@ weaken = 0 breakthings = FALSE -/obj/item/projectile/bullet/sniper/haemorrhage/on_hit(atom/target, blocked = 0, hit_zone) +/obj/item/projectile/bullet/sniper/haemorrhage/on_hit(atom/target, blocked = 0) if((blocked != 100) && iscarbon(target)) var/mob/living/carbon/C = target C.bleed(100) @@ -293,7 +293,7 @@ damage = 20 armour_penetration = 0 -/obj/item/projectile/bullet/saw/bleeding/on_hit(atom/target, blocked = 0, hit_zone) +/obj/item/projectile/bullet/saw/bleeding/on_hit(atom/target, blocked = 0) . = ..() if((blocked != 100) && iscarbon(target)) var/mob/living/carbon/C = target diff --git a/code/modules/projectiles/projectile/special.dm b/code/modules/projectiles/projectile/special.dm index 0dadac9de80e..d0f9d4bc5119 100644 --- a/code/modules/projectiles/projectile/special.dm +++ b/code/modules/projectiles/projectile/special.dm @@ -98,8 +98,8 @@ if(iscarbon(target)) var/mob/living/carbon/C = target if(C.dna.species.id == "pod") - randmuti(C) - randmut(C) + C.randmuti() + C.randmut() C.updateappearance() C.domutcheck() diff --git a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm index c70c022d4674..1c78b5c6f8e6 100644 --- a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm @@ -150,7 +150,7 @@ All effects don't start immediately, but rather get worse over time; the rate is /datum/reagent/consumable/ethanol/bilk/on_mob_life(mob/living/M) if(M.getBruteLoss() && prob(10)) - M.heal_organ_damage(1,0, 0) + M.heal_bodypart_damage(1,0, 0) . = 1 return ..() || . @@ -681,7 +681,7 @@ All effects don't start immediately, but rather get worse over time; the rate is /datum/reagent/consumable/ethanol/bananahonk/on_mob_life(mob/living/M) if( ( istype(M, /mob/living/carbon/human) && M.job in list("Clown") ) || istype(M, /mob/living/carbon/monkey) ) - M.heal_organ_damage(1,1, 0) + M.heal_bodypart_damage(1,1, 0) . = 1 return ..() || . @@ -695,7 +695,7 @@ All effects don't start immediately, but rather get worse over time; the rate is /datum/reagent/consumable/ethanol/silencer/on_mob_life(mob/living/M) if(istype(M, /mob/living/carbon/human) && M.job in list("Mime")) - M.heal_organ_damage(1,1) + M.heal_bodypart_damage(1,1) . = 1 return ..() || . diff --git a/code/modules/reagents/chemistry/reagents/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drink_reagents.dm index 6e2d5c607e08..3055d8733e0a 100644 --- a/code/modules/reagents/chemistry/reagents/drink_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drink_reagents.dm @@ -24,7 +24,7 @@ /datum/reagent/consumable/tomatojuice/on_mob_life(mob/living/M) if(M.getFireLoss() && prob(20)) - M.heal_organ_damage(0,1, 0) + M.heal_bodypart_damage(0,1, 0) . = 1 ..() @@ -95,7 +95,7 @@ /datum/reagent/consumable/banana/on_mob_life(mob/living/M) if( ( istype(M, /mob/living/carbon/human) && M.job in list("Clown") ) || istype(M, /mob/living/carbon/monkey) ) - M.heal_organ_damage(1,1, 0) + M.heal_bodypart_damage(1,1, 0) . = 1 ..() @@ -106,7 +106,7 @@ /datum/reagent/consumable/nothing/on_mob_life(mob/living/M) if(istype(M, /mob/living/carbon/human) && M.job in list("Mime")) - M.heal_organ_damage(1,1, 0) + M.heal_bodypart_damage(1,1, 0) . = 1 ..() @@ -155,13 +155,13 @@ /datum/reagent/consumable/milk/on_mob_life(mob/living/M) if(M.getBruteLoss() && prob(20)) - M.heal_organ_damage(1,0, 0) + M.heal_bodypart_damage(1,0, 0) . = 1 if(holder.has_reagent("capsaicin")) holder.remove_reagent("capsaicin", 2) var/datum/dna/Mdna = M.has_dna() if(Mdna && Mdna.species && (Mdna.species.id == "plasmaman" || Mdna.species.id == "skeleton")) - M.heal_organ_damage(1,0, 0) + M.heal_bodypart_damage(1,0, 0) . = 1 ..() @@ -173,7 +173,7 @@ /datum/reagent/consumable/soymilk/on_mob_life(mob/living/M) if(M.getBruteLoss() && prob(20)) - M.heal_organ_damage(1,0, 0) + M.heal_bodypart_damage(1,0, 0) . = 1 ..() @@ -185,7 +185,7 @@ /datum/reagent/consumable/cream/on_mob_life(mob/living/M) if(M.getBruteLoss() && prob(20)) - M.heal_organ_damage(1,0, 0) + M.heal_bodypart_damage(1,0, 0) . = 1 ..() @@ -411,7 +411,7 @@ M.bodytemperature = min(310, M.bodytemperature + (5 * TEMPERATURE_DAMAGE_COEFFICIENT)) M.Jitter(5) if(M.getBruteLoss() && prob(20)) - M.heal_organ_damage(1,0, 0) + M.heal_bodypart_damage(1,0, 0) ..() . = 1 @@ -429,7 +429,7 @@ M.bodytemperature = min(310, M.bodytemperature + (5 * TEMPERATURE_DAMAGE_COEFFICIENT)) M.Jitter(5) if(M.getBruteLoss() && prob(20)) - M.heal_organ_damage(1,0, 0) + M.heal_bodypart_damage(1,0, 0) ..() . = 1 diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm index c10c97cdaca0..e65c395f7c7c 100644 --- a/code/modules/reagents/chemistry/reagents/food_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm @@ -27,7 +27,7 @@ /datum/reagent/consumable/nutriment/on_mob_life(mob/living/M) if(prob(50)) - M.heal_organ_damage(1,0, 0) + M.heal_bodypart_damage(1,0, 0) . = 1 if(iscarbon(M)) var/mob/living/carbon/C = M @@ -44,7 +44,7 @@ /datum/reagent/consumable/vitamin/on_mob_life(mob/living/M) if(prob(50)) - M.heal_organ_damage(1,1, 0) + M.heal_bodypart_damage(1,1, 0) . = 1 if(M.satiety < 600) M.satiety += 30 @@ -325,7 +325,7 @@ /datum/reagent/consumable/sprinkles/on_mob_life(mob/living/M) if(istype(M, /mob/living/carbon/human) && M.job in list("Security Officer", "Head of Security", "Detective", "Warden")) - M.heal_organ_damage(1,1, 0) + M.heal_bodypart_damage(1,1, 0) . = 1 ..() @@ -457,5 +457,5 @@ /datum/reagent/consumable/honey/on_mob_life(mob/living/M) M.reagents.add_reagent("sugar",3) if(prob(20)) - M.heal_organ_damage(3,1) + M.heal_bodypart_damage(3,1) ..() diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm index 2461aaba7454..ce375b1d2285 100644 --- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm @@ -38,7 +38,7 @@ M.setCloneLoss(0, 0) M.setOxyLoss(0, 0) M.radiation = 0 - M.heal_organ_damage(5,5, 0) + M.heal_bodypart_damage(5,5, 0) M.adjustToxLoss(-5, 0) M.hallucination = 0 M.setBrainLoss(0) @@ -163,7 +163,7 @@ /datum/reagent/medicine/rezadone/on_mob_life(mob/living/M) M.setCloneLoss(0) //Rezadone is almost never used in favor of cryoxadone. Hopefully this will change that. - M.heal_organ_damage(1,1, 0) + M.heal_bodypart_damage(1,1, 0) M.status_flags &= ~DISFIGURED ..() . = 1 diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index ff9eb7197d63..7c311d980b31 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -537,7 +537,7 @@ color = "#808080" // rgb: 128, 128, 128 /datum/reagent/chlorine/on_mob_life(mob/living/M) - M.take_organ_damage(1*REM, 0, 0) + M.take_bodypart_damage(1*REM, 0, 0) . = 1 ..() diff --git a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm index b3fb7d29526f..7f6c1c4cbb43 100644 --- a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm @@ -34,11 +34,11 @@ if(!M.has_dna()) return //No robots, AIs, aliens, Ians or other mobs should be affected by this. if((method==VAPOR && prob(min(33, reac_volume))) || method==INGEST || method==PATCH || method==INJECT) - randmuti(M) + M.randmuti() if(prob(98)) - randmutb(M) + M.randmutb() else - randmutg(M) + M.randmutg() M.updateappearance() M.domutcheck() ..() @@ -118,7 +118,7 @@ M.adjustToxLoss(rand(20,60)*REM, 0) . = 1 else if(prob(40)) - M.heal_organ_damage(5*REM,0, 0) + M.heal_bodypart_damage(5*REM,0, 0) . = 1 ..() diff --git a/code/modules/reagents/chemistry/recipes.dm b/code/modules/reagents/chemistry/recipes.dm index 5943577d59cd..b475c752c679 100644 --- a/code/modules/reagents/chemistry/recipes.dm +++ b/code/modules/reagents/chemistry/recipes.dm @@ -50,7 +50,7 @@ var/list/chemical_mob_spawn_nicecritters = list() // and possible friendly mobs playsound(get_turf(holder.my_atom), 'sound/effects/phasein.ogg', 100, 1) for(var/mob/living/carbon/C in viewers(get_turf(holder.my_atom), null)) - C.flash_eyes() + C.flash_act() for(var/i = 1, i <= amount_to_spawn, i++) var/chosen if (reaction_name == "Friendly Gold Slime") diff --git a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm index 38e316be26be..6cb48f905527 100644 --- a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm +++ b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm @@ -218,7 +218,7 @@ s.set_up(2, 1, location) s.start() for(var/mob/living/carbon/C in get_hearers_in_view(created_volume/3, location)) - if(C.flash_eyes()) + if(C.flash_act()) if(get_dist(C, location) < 4) C.Weaken(5) else @@ -237,7 +237,7 @@ s.set_up(2, 1, location) s.start() for(var/mob/living/carbon/C in get_hearers_in_view(created_volume/10, location)) - if(C.flash_eyes()) + if(C.flash_act()) if(get_dist(C, location) < 4) C.Weaken(5) else @@ -297,16 +297,7 @@ var/location = get_turf(holder.my_atom) playsound(location, 'sound/effects/bang.ogg', 25, 1) for(var/mob/living/carbon/C in get_hearers_in_view(created_volume/3, location)) - if(C.check_ear_prot()) - continue - C.show_message("BANG", 2) - C.Stun(5) - C.Weaken(5) - C.setEarDamage(C.ear_damage + rand(0, 5), max(C.ear_deaf,15)) - if(C.ear_damage >= 15) - C << "Your ears start to ring badly!" - else if(C.ear_damage >= 5) - C << "Your ears start to ring!" + C.soundbang_act(1, 5, rand(0, 5)) /datum/chemical_reaction/sonic_powder_deafen name = "sonic_powder_deafen" @@ -318,17 +309,7 @@ var/location = get_turf(holder.my_atom) playsound(location, 'sound/effects/bang.ogg', 25, 1) for(var/mob/living/carbon/C in get_hearers_in_view(created_volume/10, location)) - if(C.check_ear_prot()) - continue - C.show_message("BANG", 2) - C.Stun(5) - C.Weaken(5) - C.setEarDamage(C.ear_damage + rand(0, 5), max(C.ear_deaf,15)) - if(C.ear_damage >= 15) - C << "Your ears start to ring badly!" - else if(C.ear_damage >= 5) - C << "Your ears start to ring!" - + C.soundbang_act(1, 5, rand(0, 5)) /datum/chemical_reaction/phlogiston name = "phlogiston" diff --git a/code/modules/reagents/chemistry/recipes/slime_extracts.dm b/code/modules/reagents/chemistry/recipes/slime_extracts.dm index ca2b41ffbe72..fd73906d8bcf 100644 --- a/code/modules/reagents/chemistry/recipes/slime_extracts.dm +++ b/code/modules/reagents/chemistry/recipes/slime_extracts.dm @@ -167,7 +167,7 @@ playsound(get_turf(holder.my_atom), 'sound/effects/phasein.ogg', 100, 1) for(var/mob/living/carbon/C in viewers(get_turf(holder.my_atom), null)) - C.flash_eyes() + C.flash_act() for(var/i = 1, i <= 4 + rand(1,2), i++) var/chosen = pick(borks) @@ -195,7 +195,7 @@ playsound(get_turf(holder.my_atom), 'sound/effects/phasein.ogg', 100, 1) for(var/mob/living/carbon/M in viewers(get_turf(holder.my_atom), null)) - M.flash_eyes() + M.flash_act() for(var/i = 1, i <= 4 + rand(1,2), i++) var/chosen = pick(borks) diff --git a/code/modules/research/designs/mechfabricator_designs.dm b/code/modules/research/designs/mechfabricator_designs.dm index 6a1604a4c261..387e56aaf9c4 100644 --- a/code/modules/research/designs/mechfabricator_designs.dm +++ b/code/modules/research/designs/mechfabricator_designs.dm @@ -3,7 +3,7 @@ name = "Cyborg Endoskeleton" id = "borg_suit" build_type = MECHFAB - build_path = /obj/item/robot_parts/robot_suit + build_path = /obj/item/robot_suit materials = list(MAT_METAL=15000) construction_time = 500 category = list("Cyborg") @@ -12,7 +12,7 @@ name = "Cyborg Torso" id = "borg_chest" build_type = MECHFAB - build_path = /obj/item/robot_parts/chest + build_path = /obj/item/bodypart/chest/robot materials = list(MAT_METAL=40000) construction_time = 350 category = list("Cyborg") @@ -21,7 +21,7 @@ name = "Cyborg Head" id = "borg_head" build_type = MECHFAB - build_path = /obj/item/robot_parts/head + build_path = /obj/item/bodypart/head/robot materials = list(MAT_METAL=5000) construction_time = 350 category = list("Cyborg") @@ -30,7 +30,7 @@ name = "Cyborg Left Arm" id = "borg_l_arm" build_type = MECHFAB - build_path = /obj/item/robot_parts/l_arm + build_path = /obj/item/bodypart/l_arm/robot materials = list(MAT_METAL=10000) construction_time = 200 category = list("Cyborg") @@ -39,7 +39,7 @@ name = "Cyborg Right Arm" id = "borg_r_arm" build_type = MECHFAB - build_path = /obj/item/robot_parts/r_arm + build_path = /obj/item/bodypart/r_arm/robot materials = list(MAT_METAL=10000) construction_time = 200 category = list("Cyborg") @@ -48,7 +48,7 @@ name = "Cyborg Left Leg" id = "borg_l_leg" build_type = MECHFAB - build_path = /obj/item/robot_parts/l_leg + build_path = /obj/item/bodypart/l_leg/robot materials = list(MAT_METAL=10000) construction_time = 200 category = list("Cyborg") @@ -57,7 +57,7 @@ name = "Cyborg Right Leg" id = "borg_r_leg" build_type = MECHFAB - build_path = /obj/item/robot_parts/r_leg + build_path = /obj/item/bodypart/r_leg/robot materials = list(MAT_METAL=10000) construction_time = 200 category = list("Cyborg") diff --git a/code/modules/spells/spell_types/barnyard.dm b/code/modules/spells/spell_types/barnyard.dm index e11115c64d33..a63d91c64376 100644 --- a/code/modules/spells/spell_types/barnyard.dm +++ b/code/modules/spells/spell_types/barnyard.dm @@ -47,4 +47,4 @@ target.equip_to_slot_if_possible(magichead, slot_wear_mask, 1, 1) playsound(get_turf(target), mSounds[randM], 50, 1) - target.flash_eyes() + target.flash_act() diff --git a/code/modules/spells/spell_types/lichdom.dm b/code/modules/spells/spell_types/lichdom.dm index 9a1d27ebbc7f..728555db52ed 100644 --- a/code/modules/spells/spell_types/lichdom.dm +++ b/code/modules/spells/spell_types/lichdom.dm @@ -92,7 +92,8 @@ var/mob/living/carbon/C = old_body for(var/obj/item/W in C) C.unEquip(W) - for(var/obj/item/organ/I in C.internal_organs) + for(var/X in C.internal_organs) + var/obj/item/organ/I = X I.Remove(C) I.forceMove(body_turf) var/wheres_wizdo = dir2text(get_dir(body_turf, item_turf)) diff --git a/code/modules/surgery/amputation.dm b/code/modules/surgery/amputation.dm index 1e13586eea86..2ebe45f2d310 100644 --- a/code/modules/surgery/amputation.dm +++ b/code/modules/surgery/amputation.dm @@ -2,8 +2,10 @@ /datum/surgery/amputation name = "amputation" steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/saw, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/sever_limb) - species = list(/mob/living/carbon/human) + species = list(/mob/living/carbon/human, /mob/living/carbon/monkey) possible_locs = list("r_arm", "l_arm", "l_leg", "r_leg", "head") + requires_organic_bodypart = 0 + /datum/surgery_step/sever_limb name = "sever limb" @@ -16,7 +18,6 @@ /datum/surgery_step/sever_limb/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) var/mob/living/carbon/human/L = target user.visible_message("[user] severs [L]'s [parse_zone(target_zone)]!", "You sever [L]'s [parse_zone(target_zone)].") - var/obj/item/bodypart/BP = L.get_bodypart(target_zone) - if(BP) - BP.drop_limb() + if(surgery.operated_bodypart) + surgery.operated_bodypart.drop_limb() return 1 \ No newline at end of file diff --git a/code/modules/surgery/bodyparts/bodyparts.dm b/code/modules/surgery/bodyparts/bodyparts.dm index 74c8679cd789..6e4ee1d069d3 100644 --- a/code/modules/surgery/bodyparts/bodyparts.dm +++ b/code/modules/surgery/bodyparts/bodyparts.dm @@ -4,10 +4,11 @@ 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/human/owner = null - var/status = ORGAN_ORGANIC + var/mob/living/carbon/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/brutestate = 0 @@ -28,10 +29,14 @@ 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/state_flags + 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) ..() @@ -53,7 +58,7 @@ if(ishuman(C)) var/mob/living/carbon/human/H = C if(EASYLIMBATTACHMENT in H.dna.species.specflags) - if(!H.get_bodypart(body_zone)) + if(!H.get_bodypart(body_zone) && !animal_origin) if(H == user) H.visible_message("[H] jams [src] into \his empty socket!",\ "You force [src] into your empty socket, and it locks into place!") @@ -72,8 +77,8 @@ user << "There is nothing left inside [src]!" return playsound(loc, 'sound/weapons/slice.ogg', 50, 1, -1) - user.visible_message("[user] begins to cut through the bone in [src].",\ - "You begin to cut through the bone in [src]...") + user.visible_message("[user] begins to cut open [src].",\ + "You begin to cut open [src]...") if(do_after(user, 54, target = src)) drop_organs(user) else @@ -81,27 +86,30 @@ /obj/item/bodypart/throw_impact(atom/hit_atom) ..() - playsound(get_turf(src), 'sound/misc/splort.ogg', 50, 1, -1) + 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) - playsound(T, 'sound/misc/splort.ogg', 50, 1, -1) + if(status != BODYPART_ROBOTIC) + playsound(T, 'sound/misc/splort.ogg', 50, 1, -1) for(var/obj/item/I in src) - I.loc = T + I.forceMove(T) //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/take_damage(brute, burn) +/obj/item/bodypart/proc/take_damage(brute, burn, updating_health = 1) if(owner && (owner.status_flags & GODMODE)) return 0 //godmode brute = max(brute * config.damage_multiplier,0) burn = max(burn * config.damage_multiplier,0) - if(status == ORGAN_ROBOTIC) //This makes robolimbs not damageable by chems and makes it stronger + if(status == BODYPART_ROBOTIC) //This makes robolimbs not damageable by chems and makes it stronger brute = max(0, brute - 5) burn = max(0, burn - 4) @@ -126,7 +134,7 @@ burn_dam += can_inflict else return 0 - if(owner) + if(owner && updating_health) owner.updatehealth() return update_bodypart_damage_state() @@ -134,17 +142,17 @@ //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, robotic) +/obj/item/bodypart/proc/heal_damage(brute, burn, only_robotic = 0, only_organic = 1, updating_health = 1) - if(robotic && status != ORGAN_ROBOTIC) //This makes organic limbs not heal when the proc is in Robotic mode. + if(only_robotic && status != BODYPART_ROBOTIC) //This makes organic limbs not heal when the proc is in Robotic mode. return - if(!robotic && status == ORGAN_ROBOTIC) //This makes robolimbs not healable by chems. + 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) + if(owner && updating_health) owner.updatehealth() return update_bodypart_damage_state() @@ -157,14 +165,13 @@ //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() - if(status == ORGAN_ORGANIC) //Robotic limbs show no damage - RR - 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 + 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 @@ -183,47 +190,57 @@ 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/human/source) - var/mob/living/carbon/human/H +/obj/item/bodypart/proc/update_limb(dropping_limb, mob/living/carbon/source) + var/mob/living/carbon/C if(source) - H = source + C = source else - H = owner - if(!istype(H)) - return + C = owner - should_draw_greyscale = FALSE + 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 + var/datum/species/S = H.dna.species + species_id = S.limbs_id + species_flags_list = H.dna.species.specflags - 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.specflags) - if(S.fixed_mut_color) - species_color = S.fixed_mut_color + if(S.use_skintones) + skin_tone = H.skin_tone + should_draw_greyscale = TRUE else - species_color = H.dna.features["mcolor"] - should_draw_greyscale = TRUE - else - species_color = "" + skin_tone = "" - if(H.disabilities & HUSK) - species_id = "husk" + body_gender = H.gender + should_draw_gender = S.sexes + + if(MUTCOLORS in S.specflags) + 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(C.disabilities & HUSK) + species_id = "husk" //overrides species_id + dmg_overlay_type = "" //no damage overlay shown when husked should_draw_gender = FALSE should_draw_greyscale = FALSE - if(!dropping_limb && H.dna.check_mutation(HULK)) - mutation_color = "00aa00" - else - mutation_color = "" + 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. @@ -231,25 +248,49 @@ //to update the bodypart's icon when not attached to a mob /obj/item/bodypart/proc/update_icon_dropped() cut_overlays() - var/image/I = get_limb_icon(1) - if(I) + 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(I) + add_overlay(standing) //Gives you a proper icon appearance for the dismembered limb /obj/item/bodypart/proc/get_limb_icon(dropped) - var/image/I + icon_state = "" //to erase the default sprite, we're building the visual aspects of the bodypart through overlays alone. + + var/list/standing = list() + + var/image_dir + if(dropped) + image_dir = SOUTH + if(dmg_overlay_type) + if(brutestate) + standing += image("icon"='icons/mob/dam_mob.dmi', "icon_state"="[dmg_overlay_type]_[body_zone]_[brutestate]0", "layer"=-DAMAGE_LAYER, "dir"=image_dir) + if(burnstate) + standing += image("icon"='icons/mob/dam_mob.dmi', "icon_state"="[dmg_overlay_type]_[body_zone]_0[burnstate]", "layer"=-DAMAGE_LAYER, "dir"=image_dir) + + + if(animal_origin) + if(status == BODYPART_ORGANIC) + if(species_id == "husk") + standing += image("icon"='icons/mob/animal_parts.dmi', "icon_state"="[animal_origin]_husk_[body_zone]_s", "layer"=-BODYPARTS_LAYER, "dir"=image_dir) + else + standing += image("icon"='icons/mob/animal_parts.dmi', "icon_state"="[animal_origin]_[body_zone]_s", "layer"=-BODYPARTS_LAYER, "dir"=image_dir) + else + standing += image("icon"='icons/mob/augments.dmi', "icon_state"="[animal_origin]_[body_zone]_s", "layer"=-BODYPARTS_LAYER, "dir"=image_dir) + return standing 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 - var/image_dir - if(dropped) - image_dir = SOUTH - if(status == ORGAN_ORGANIC) + var/image/I + + if(status == BODYPART_ORGANIC) if(should_draw_greyscale) if(should_draw_gender) I = image("icon"='icons/mob/human_parts_greyscale.dmi', "icon_state"="[species_id]_[body_zone]_[icon_gender]_s", "layer"=-BODYPARTS_LAYER, "dir"=image_dir) @@ -265,11 +306,13 @@ I = image("icon"='icons/mob/augments.dmi', "icon_state"="[body_zone]_[icon_gender]_s", "layer"=-BODYPARTS_LAYER, "dir"=image_dir) else I = image("icon"='icons/mob/augments.dmi', "icon_state"="[body_zone]_s", "layer"=-BODYPARTS_LAYER, "dir"=image_dir) - return I + standing += I + return standing if(!should_draw_greyscale) - return I + standing += I + return standing //Greyscale Colouring var/draw_color @@ -284,13 +327,15 @@ if(draw_color) I.color = "#[draw_color]" //End Greyscale Colouring + standing += I - return I + return standing /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 @@ -303,12 +348,43 @@ 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_s" + 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_s" + 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" @@ -316,10 +392,32 @@ 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_s" + 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" @@ -327,10 +425,32 @@ 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_s" + 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" @@ -338,12 +458,33 @@ px_x = -2 px_y = 12 +/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_s" + 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" @@ -351,6 +492,26 @@ px_x = 2 px_y = 12 +/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_s" + 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 + ///////////////////////////////////////////////////////////////////////// diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm index 7cacabe3a082..b6218ceaea6c 100644 --- a/code/modules/surgery/bodyparts/dismemberment.dm +++ b/code/modules/surgery/bodyparts/dismemberment.dm @@ -1,26 +1,33 @@ /obj/item/bodypart/proc/can_dismember(obj/item/I) - . = (get_damage() >= (max_damage - I.armour_penetration/2)) + if(dismemberable) + . = (get_damage() >= (max_damage - I.armour_penetration/2)) //Dismember a limb /obj/item/bodypart/proc/dismember(dam_type = BRUTE) - var/mob/living/carbon/human/H = owner - if(!istype(H) || (NODISMEMBER in H.dna.species.specflags)) // species don't allow dismemberment + if(!owner) return 0 + var/mob/living/carbon/C = owner + if(!dismemberable) + return 0 + if(ishuman(C)) + var/mob/living/carbon/human/H = C + if(NODISMEMBER in H.dna.species.specflags) // species don't allow dismemberment + return 0 - var/obj/item/bodypart/affecting = H.get_bodypart("chest") + var/obj/item/bodypart/affecting = C.get_bodypart("chest") affecting.take_damage(Clamp(brute_dam/2, 15, 50), Clamp(burn_dam/2, 0, 50)) //Damage the chest based on limb's existing damage - H.visible_message("[H]'s [src.name] has been violently dismembered!") - H.emote("scream") + C.visible_message("[C]'s [src.name] has been violently dismembered!") + C.emote("scream") drop_limb() if(dam_type == BURN) burn() return 1 - add_mob_blood(H) - var/turf/location = H.loc + add_mob_blood(C) + var/turf/location = C.loc if(istype(location)) - H.add_splatter_floor(location) + C.add_splatter_floor(location) var/direction = pick(cardinal) var/t_range = rand(2,max(throw_range/2, 2)) var/turf/target_turf = get_turf(src) @@ -34,92 +41,100 @@ /obj/item/bodypart/chest/dismember() - var/mob/living/carbon/human/H = owner - if(!istype(H) || (NODISMEMBER in H.dna.species.specflags)) //human's species don't allow dismemberment + if(!owner) return 0 + var/mob/living/carbon/C = owner + if(!dismemberable) + return 0 + if(ishuman(C)) + var/mob/living/carbon/human/H = C + if(NODISMEMBER in H.dna.species.specflags) // species don't allow dismemberment + return 0 var/organ_spilled = 0 - var/turf/T = get_turf(H) - H.add_splatter_floor(T) - playsound(get_turf(owner), 'sound/misc/splort.ogg', 80, 1) - for(var/X in owner.internal_organs) + var/turf/T = get_turf(C) + C.add_splatter_floor(T) + playsound(get_turf(C), 'sound/misc/splort.ogg', 80, 1) + for(var/X in C.internal_organs) var/obj/item/organ/O = X - if(O.zone != "chest") + var/org_zone = check_zone(O.zone) + if(org_zone != "chest") continue - O.Remove(owner) - O.loc = T + O.Remove(C) + O.forceMove(T) organ_spilled = 1 if(cavity_item) - cavity_item.loc = T + cavity_item.forceMove(T) cavity_item = null organ_spilled = 1 if(organ_spilled) - owner.visible_message("[owner]'s internal organs spill out onto the floor!") + C.visible_message("[C]'s internal organs spill out onto the floor!") return 1 //limb removal. The "special" argument is used for swapping a limb with a new one without the effects of losing a limb kicking in. /obj/item/bodypart/proc/drop_limb(special) - if(!ishuman(owner)) + if(!owner) return var/turf/T = get_turf(owner) - var/mob/living/carbon/human/H = owner + var/mob/living/carbon/C = owner if(!no_update) update_limb(1) - H.bodyparts -= src + C.bodyparts -= src if(held_index) - H.unEquip(owner.get_item_for_held_index(held_index), 1) - H.hand_bodyparts[held_index] = null + C.unEquip(owner.get_item_for_held_index(held_index), 1) + C.hand_bodyparts[held_index] = null owner = null - for(var/X in H.surgeries) //if we had an ongoing surgery on that limb, we stop it. + for(var/X in C.surgeries) //if we had an ongoing surgery on that limb, we stop it. var/datum/surgery/S = X - if(S.organ == src) - H.surgeries -= S + if(S.operated_bodypart == src) + C.surgeries -= S qdel(S) break for(var/obj/item/I in embedded_objects) embedded_objects -= I I.loc = src - if(!H.has_embedded_objects()) - H.clear_alert("embeddedobject") + if(!C.has_embedded_objects()) + C.clear_alert("embeddedobject") if(!special) - for(var/X in H.dna.mutations) //some mutations require having specific limbs to be kept. - var/datum/mutation/human/MT = X - if(MT.limb_req && MT.limb_req == body_zone) - MT.force_lose(H) + if(C.dna) + for(var/X in C.dna.mutations) //some mutations require having specific limbs to be kept. + var/datum/mutation/human/MT = X + if(MT.limb_req && MT.limb_req == body_zone) + MT.force_lose(C) - for(var/X in H.internal_organs) //internal organs inside the dismembered limb are dropped. + for(var/X in C.internal_organs) //internal organs inside the dismembered limb are dropped. var/obj/item/organ/O = X var/org_zone = check_zone(O.zone) if(org_zone != body_zone) continue - O.transfer_to_limb(src, H) + O.transfer_to_limb(src, C) update_icon_dropped() - src.loc = T - H.update_health_hud() //update the healthdoll - H.update_body() - H.update_hair() - H.update_canmove() + forceMove(T) + C.update_health_hud() //update the healthdoll + C.update_body() + C.update_hair() + C.update_canmove() //when a limb is dropped, the internal organs are removed from the mob and put into the limb -/obj/item/organ/proc/transfer_to_limb(obj/item/bodypart/LB, mob/living/carbon/human/H) - Remove(H) +/obj/item/organ/proc/transfer_to_limb(obj/item/bodypart/LB, mob/living/carbon/C) + Remove(C) loc = LB -/obj/item/organ/brain/transfer_to_limb(obj/item/bodypart/head/LB, mob/living/carbon/human/H) - if(H.mind && H.mind.changeling) +/obj/item/organ/brain/transfer_to_limb(obj/item/bodypart/head/LB, mob/living/carbon/human/C) + if(C.mind && C.mind.changeling) LB.brain = new //changeling doesn't lose its real brain organ, we drop a decoy. LB.brain.loc = LB else //if not a changeling, we put the brain organ inside the dropped head - Remove(H) //and put the player in control of the brainmob + Remove(C) //and put the player in control of the brainmob loc = LB LB.brain = src LB.brainmob = brainmob @@ -133,39 +148,39 @@ return /obj/item/bodypart/r_arm/drop_limb(special) - var/mob/living/carbon/human/H = owner + var/mob/living/carbon/C = owner ..() - if(istype(H) && !special) - if(H.handcuffed) - H.handcuffed.loc = H.loc - H.handcuffed.dropped(H) - H.handcuffed = null - H.update_handcuffed() - if(H.hud_used) - var/obj/screen/inventory/hand/R = H.hud_used.hand_slots["[held_index]"] + if(C && !special) + if(C.handcuffed) + C.handcuffed.loc = C.loc + C.handcuffed.dropped(C) + C.handcuffed = null + C.update_handcuffed() + if(C.hud_used) + var/obj/screen/inventory/hand/R = C.hud_used.hand_slots["[held_index]"] if(R) R.update_icon() - if(H.gloves) - H.unEquip(H.gloves, 1) - H.update_inv_gloves() //to remove the bloody hands overlay + if(C.gloves) + C.unEquip(C.gloves, 1) + C.update_inv_gloves() //to remove the bloody hands overlay /obj/item/bodypart/l_arm/drop_limb(special) - var/mob/living/carbon/human/H = owner + var/mob/living/carbon/C = owner ..() - if(istype(H) && !special) - if(H.handcuffed) - H.handcuffed.loc = H.loc - H.handcuffed.dropped(H) - H.handcuffed = null - H.update_handcuffed() - if(H.hud_used) - var/obj/screen/inventory/hand/L = H.hud_used.hand_slots["[held_index]"] + if(C && !special) + if(C.handcuffed) + C.handcuffed.loc = C.loc + C.handcuffed.dropped(C) + C.handcuffed = null + C.update_handcuffed() + if(C.hud_used) + var/obj/screen/inventory/hand/L = C.hud_used.hand_slots["[held_index]"] if(L) L.update_icon() - if(H.gloves) - H.unEquip(H.gloves, 1) - H.update_inv_gloves() //to remove the bloody hands overlay + if(C.gloves) + C.unEquip(C.gloves, 1) + C.update_inv_gloves() //to remove the bloody hands overlay /obj/item/bodypart/r_leg/drop_limb(special) @@ -176,10 +191,8 @@ owner.legcuffed.dropped(owner) owner.legcuffed = null owner.update_inv_legcuffed() - if(ishuman(owner)) - var/mob/living/carbon/human/H = owner - if(H.shoes) - H.unEquip(H.shoes, 1) + if(owner.shoes) + owner.unEquip(owner.shoes, 1) ..() /obj/item/bodypart/l_leg/drop_limb(special) //copypasta @@ -190,21 +203,17 @@ owner.legcuffed.dropped(owner) owner.legcuffed = null owner.update_inv_legcuffed() - if(ishuman(owner)) - var/mob/living/carbon/human/H = owner - if(H.shoes) - H.unEquip(H.shoes, 1) + if(owner.shoes) + owner.unEquip(owner.shoes, 1) ..() /obj/item/bodypart/head/drop_limb(special) - var/mob/living/carbon/human/H = owner - if(istype(H)) - if(!special) - //Drop all worn head items - for(var/X in list(H.glasses, H.ears, H.wear_mask, H.head)) - var/obj/item/I = X - H.unEquip(I, 1) - name = "[H]'s head" + if(!special) + //Drop all worn head items + for(var/X in list(owner.glasses, owner.ears, owner.wear_mask, owner.head)) + var/obj/item/I = X + owner.unEquip(I, 1) + name = "[owner]'s head" ..() @@ -213,81 +222,76 @@ //Attach a limb to a human and drop any existing limb of that type. -/obj/item/bodypart/proc/replace_limb(mob/living/carbon/human/H, special) - if(!istype(H)) +/obj/item/bodypart/proc/replace_limb(mob/living/carbon/C, special) + if(!istype(C)) return - var/obj/item/bodypart/O = locate(src.type) in H.bodyparts - + var/obj/item/bodypart/O = locate(src.type) in C.bodyparts if(O) O.drop_limb(1) - attach_limb(H, special) + attach_limb(C, special) -/obj/item/bodypart/head/replace_limb(mob/living/carbon/human/H, special) - if(!istype(H)) +/obj/item/bodypart/head/replace_limb(mob/living/carbon/C, special) + if(!istype(C)) return - var/obj/item/bodypart/head/O = locate(src.type) in H.bodyparts + var/obj/item/bodypart/head/O = locate(src.type) in C.bodyparts if(O) if(!special) return else O.drop_limb(1) - attach_limb(H, special) + attach_limb(C, special) -/obj/item/bodypart/proc/attach_limb(mob/living/carbon/human/H, special) +/obj/item/bodypart/proc/attach_limb(mob/living/carbon/C, special) loc = null - owner = H - H.bodyparts += src + owner = C + C.bodyparts += src + if(held_index) + C.hand_bodyparts += src + if(C.hud_used) + var/obj/screen/inventory/hand/hand = C.hud_used.hand_slots["[held_index]"] + if(hand) + hand.update_icon() + C.update_inv_gloves() if(special) //non conventional limb attachment - for(var/X in H.surgeries) //if we had an ongoing surgery to attach a new limb, we stop it. + for(var/X in C.surgeries) //if we had an ongoing surgery to attach a new limb, we stop it. var/datum/surgery/S = X var/surgery_zone = check_zone(S.location) if(surgery_zone == body_zone) - H.surgeries -= S + C.surgeries -= S qdel(S) break update_bodypart_damage_state() - H.updatehealth() - H.update_body() - H.update_hair() - H.update_damage_overlays() - H.update_canmove() + C.updatehealth() + C.update_body() + C.update_hair() + C.update_damage_overlays() + C.update_canmove() -/obj/item/bodypart/r_arm/attach_limb(mob/living/carbon/human/H, special) - ..() - if(H.hud_used) - var/obj/screen/inventory/hand/R = H.hud_used.hand_slots["[held_index]"] - if(R) - R.update_icon() -/obj/item/bodypart/l_arm/attach_limb(mob/living/carbon/human/H, special) - ..() - if(H.hud_used) - var/obj/screen/inventory/hand/L = H.hud_used.hand_slots["[held_index]"] - if(L) - L.update_icon() - -/obj/item/bodypart/head/attach_limb(mob/living/carbon/human/H, special) +/obj/item/bodypart/head/attach_limb(mob/living/carbon/C, special) //Transfer some head appearance vars over if(brain) brainmob.container = null //Reset brainmob head var. brainmob.loc = brain //Throw mob into brain. brain.brainmob = brainmob //Set the brain to use the brainmob brainmob = null //Set head brainmob var to null - brain.Insert(H) //Now insert the brain proper + brain.Insert(C) //Now insert the brain proper brain = null //No more brain in the head - H.hair_color = hair_color - H.hair_style = hair_style - H.facial_hair_color = facial_hair_color - H.facial_hair_style = facial_hair_style - H.eye_color = eye_color - H.lip_style = lip_style - H.lip_color = lip_color + if(ishuman(C)) + var/mob/living/carbon/human/H = C + H.hair_color = hair_color + H.hair_style = hair_style + H.facial_hair_color = facial_hair_color + H.facial_hair_style = facial_hair_style + H.eye_color = eye_color + H.lip_style = lip_style + H.lip_color = lip_color if(real_name) - H.real_name = real_name + C.real_name = real_name real_name = "" name = initial(name) ..() @@ -297,21 +301,22 @@ /mob/living/proc/regenerate_limbs(noheal, excluded_limbs) return 0 -/mob/living/carbon/human/regenerate_limbs(noheal, list/excluded_limbs) +/mob/living/carbon/regenerate_limbs(noheal, list/excluded_limbs) var/list/limb_list = list("head", "chest", "r_arm", "l_arm", "r_leg", "l_leg") if(excluded_limbs) limb_list -= excluded_limbs for(var/Z in limb_list) . += regenerate_limb(Z, noheal) +/ /mob/living/proc/regenerate_limb(limb_zone, noheal) return -/mob/living/carbon/human/regenerate_limb(limb_zone, noheal) +/mob/living/carbon/regenerate_limb(limb_zone, noheal) var/obj/item/bodypart/L if(get_bodypart(limb_zone)) return 0 - L = newBodyPart(limb_zone, 0, 0, src) + L = newBodyPart(limb_zone, 0, 0) if(L) if(!noheal) L.brute_dam = 0 diff --git a/code/modules/surgery/bodyparts/head.dm b/code/modules/surgery/bodyparts/head.dm index 16c742fc6fd8..c3d86b5d4a2a 100644 --- a/code/modules/surgery/bodyparts/head.dm +++ b/code/modules/surgery/bodyparts/head.dm @@ -1,6 +1,8 @@ /obj/item/bodypart/head name = "head" desc = "Didn't make sense not to live for fun, your brain gets smart but your head gets dumb." + icon = 'icons/mob/human_parts.dmi' + icon_state = "default_human_head" max_damage = 200 body_zone = "head" body_part = HEAD @@ -10,7 +12,7 @@ px_x = 0 px_y = -8 - var/mob/living/carbon/brain/brainmob = null //The current occupant. + var/mob/living/brain/brainmob = null //The current occupant. var/obj/item/organ/brain/brain = null //The brain organ //Limb appearance info: @@ -30,7 +32,8 @@ /obj/item/bodypart/head/drop_organs(mob/user) var/turf/T = get_turf(src) - playsound(T, 'sound/misc/splort.ogg', 50, 1, -1) + if(status != BODYPART_ROBOTIC) + playsound(T, 'sound/misc/splort.ogg', 50, 1, -1) for(var/obj/item/I in src) if(I == brain) if(user) @@ -46,67 +49,77 @@ else I.loc = T -/obj/item/bodypart/head/update_limb(dropping_limb, mob/living/carbon/human/source) - var/mob/living/carbon/human/H +/obj/item/bodypart/head/update_limb(dropping_limb, mob/living/carbon/source) + var/mob/living/carbon/C if(source) - H = source + C = source else - H = owner - if(!istype(H)) - return - var/datum/species/S = H.dna.species - //First of all, name. - real_name = H.real_name + C = owner - //Facial hair - if(H.facial_hair_style && (FACEHAIR in S.specflags)) - facial_hair_style = H.facial_hair_style - if(S.hair_color) - if(S.hair_color == "mutcolor") - facial_hair_color = H.dna.features["mcolor"] - else - facial_hair_color = S.hair_color - else - facial_hair_color = H.facial_hair_color - hair_alpha = S.hair_alpha - else - facial_hair_style = "Shaved" - facial_hair_color = "000" - hair_alpha = 255 - //Hair - if(H.hair_style && (HAIR in S.specflags)) - hair_style = H.hair_style - if(S.hair_color) - if(S.hair_color == "mutcolor") - hair_color = H.dna.features["mcolor"] - else - hair_color = S.hair_color - else - hair_color = H.hair_color - hair_alpha = S.hair_alpha - else + real_name = C.real_name + if(C.disabilities & HUSK) + real_name = "Unknown" hair_style = "Bald" - hair_color = "000" - hair_alpha = initial(hair_alpha) - // lipstick - if(H.lip_style && (LIPS in S.specflags)) - lip_style = H.lip_style - lip_color = H.lip_color - else - lip_style = null - lip_color = "white" - // eyes - if(EYECOLOR in S.specflags) - eyes = S.eyes - eye_color = H.eye_color - else + facial_hair_style = "Shaved" eyes = "eyes" eye_color = "" + lip_style = null + + else if(!animal_origin) + var/mob/living/carbon/human/H = C + var/datum/species/S = H.dna.species + + //Facial hair + if(H.facial_hair_style && (FACEHAIR in S.specflags)) + facial_hair_style = H.facial_hair_style + if(S.hair_color) + if(S.hair_color == "mutcolor") + facial_hair_color = H.dna.features["mcolor"] + else + facial_hair_color = S.hair_color + else + facial_hair_color = H.facial_hair_color + hair_alpha = S.hair_alpha + else + facial_hair_style = "Shaved" + facial_hair_color = "000" + hair_alpha = 255 + //Hair + if(H.hair_style && (HAIR in S.specflags)) + hair_style = H.hair_style + if(S.hair_color) + if(S.hair_color == "mutcolor") + hair_color = H.dna.features["mcolor"] + else + hair_color = S.hair_color + else + hair_color = H.hair_color + hair_alpha = S.hair_alpha + else + hair_style = "Bald" + hair_color = "000" + hair_alpha = initial(hair_alpha) + // lipstick + if(H.lip_style && (LIPS in S.specflags)) + lip_style = H.lip_style + lip_color = H.lip_color + else + lip_style = null + lip_color = "white" + // eyes + if(EYECOLOR in S.specflags) + eyes = S.eyes + eye_color = H.eye_color + else + eyes = "eyes" + eye_color = "" + ..() /obj/item/bodypart/head/update_icon_dropped() var/list/standing = get_limb_icon(1) - if(!standing) + 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 @@ -115,13 +128,11 @@ /obj/item/bodypart/head/get_limb_icon(dropped) cut_overlays() - var/image/I = ..() - var/list/standing = list() - standing += I + var/list/standing = ..() if(dropped) //certain overlays only appear when the limb is being detached from its owner. var/datum/sprite_accessory/S - if(status != ORGAN_ROBOTIC) //having a robotic head hides certain features. + if(status != BODYPART_ROBOTIC) //having a robotic head hides certain features. //facial hair if(facial_hair_style) S = facial_hair_styles_list[facial_hair_style] @@ -133,7 +144,12 @@ //Applies the debrained overlay if there is no brain if(!brain) - standing += image("icon"='icons/mob/human_face.dmi', "icon_state" = "debrained_s", "layer" = -HAIR_LAYER, "dir"=SOUTH) + if(animal_origin == ALIEN_BODYPART) + standing += image("icon"='icons/mob/animal_parts.dmi', "icon_state" = "debrained_alien_s", "layer" = -HAIR_LAYER, "dir"=SOUTH) + else if(animal_origin == LARVA_BODYPART) + standing += image("icon"='icons/mob/animal_parts.dmi', "icon_state" = "debrained_larva_s", "layer" = -HAIR_LAYER, "dir"=SOUTH) + else if(!(NOBLOOD in species_flags_list)) + standing += image("icon"='icons/mob/human_face.dmi', "icon_state" = "debrained_s", "layer" = -HAIR_LAYER, "dir"=SOUTH) else if(hair_style) S = hair_styles_list[hair_style] @@ -156,9 +172,36 @@ img_eyes_s.color = "#" + eye_color standing += img_eyes_s - if(standing.len) - return standing + return standing /obj/item/bodypart/head/burn() drop_organs() ..() + +/obj/item/bodypart/head/monkey + icon = 'icons/mob/animal_parts.dmi' + icon_state = "default_monkey_head" + animal_origin = MONKEY_BODYPART + +/obj/item/bodypart/head/alien + icon = 'icons/mob/animal_parts.dmi' + icon_state = "alien_head_s" + px_x = 0 + px_y = 0 + dismemberable = 0 + max_damage = 500 + animal_origin = ALIEN_BODYPART + +/obj/item/bodypart/head/devil + dismemberable = 0 + max_damage = 5000 + animal_origin = DEVIL_BODYPART + +/obj/item/bodypart/head/larva + icon = 'icons/mob/animal_parts.dmi' + icon_state = "larva_head_s" + px_x = 0 + px_y = 0 + dismemberable = 0 + max_damage = 50 + animal_origin = LARVA_BODYPART diff --git a/code/modules/surgery/bodyparts/helpers.dm b/code/modules/surgery/bodyparts/helpers.dm index 4ceec195c095..9f2c6ac37c10 100644 --- a/code/modules/surgery/bodyparts/helpers.dm +++ b/code/modules/surgery/bodyparts/helpers.dm @@ -10,47 +10,48 @@ if(L.body_zone == zone) return L -/mob/living/carbon/human/has_hand_for_held_index(i) +/mob/living/carbon/has_hand_for_held_index(i) if(i) var/obj/item/bodypart/L = hand_bodyparts[i] if(L) return L return FALSE + + + /mob/proc/has_left_hand() return TRUE -/mob/living/carbon/human/has_left_hand() +/mob/living/carbon/has_left_hand() + for(var/obj/item/bodypart/L in hand_bodyparts) + if(L.held_index % 2) + return TRUE + return FALSE + +/mob/living/carbon/alien/larva/has_left_hand() + return 1 + + +/mob/proc/has_right_hand() + return TRUE + +/mob/living/carbon/has_right_hand() for(var/obj/item/bodypart/L in hand_bodyparts) if(!(L.held_index % 2)) return TRUE return FALSE -/mob/proc/has_right_hand() - return TRUE +/mob/living/carbon/alien/larva/has_right_hand() + return 1 -/mob/living/carbon/human/has_right_hand() - for(var/obj/item/bodypart/L in hand_bodyparts) - if(L.held_index % 2) - return TRUE - return FALSE //Limb numbers /mob/proc/get_num_arms() return 2 -/mob/proc/get_num_legs() - return 2 - -/mob/proc/get_leg_ignore() - return 0 - -/mob/living/carbon/human/get_leg_ignore() - if(FLYING in dna.species.specflags) - return 1 - -/mob/living/carbon/human/get_num_arms() +/mob/living/carbon/get_num_arms() . = 0 for(var/X in bodyparts) var/obj/item/bodypart/affecting = X @@ -59,7 +60,19 @@ if(affecting.body_part == ARM_LEFT) .++ -/mob/living/carbon/human/get_num_legs() + +//sometimes we want to ignore that we don't have the required amount of arms. +/mob/proc/get_arm_ignore() + return 0 + +/mob/living/carbon/alien/larva/get_arm_ignore() + return 1 //so we can still handcuff larvas. + + +/mob/proc/get_num_legs() + return 2 + +/mob/living/carbon/get_num_legs() . = 0 for(var/X in bodyparts) var/obj/item/bodypart/affecting = X @@ -68,19 +81,36 @@ if(affecting.body_part == LEG_LEFT) .++ +//sometimes we want to ignore that we don't have the required amount of legs. +/mob/proc/get_leg_ignore() + return 0 + +/mob/living/carbon/alien/larva/get_leg_ignore() + return 1 + +/mob/living/carbon/human/get_leg_ignore() + if(FLYING in dna.species.specflags) + return 1 + /mob/living/proc/get_missing_limbs() return list() -/mob/living/carbon/human/get_missing_limbs() +/mob/living/carbon/get_missing_limbs() var/list/full = list("head", "chest", "r_arm", "l_arm", "r_leg", "l_leg") for(var/zone in full) if(get_bodypart(zone)) full -= zone return full +/mob/living/carbon/alien/larva/get_missing_limbs() + var/list/full = list("head", "chest") + for(var/zone in full) + if(get_bodypart(zone)) + full -= zone + return full -//Remove all embedded objects from all limbs on the human mob -/mob/living/carbon/human/proc/remove_all_embedded_objects() +//Remove all embedded objects from all limbs on the carbon mob +/mob/living/carbon/proc/remove_all_embedded_objects() var/turf/T = get_turf(src) for(var/X in bodyparts) @@ -91,7 +121,7 @@ clear_alert("embeddedobject") -/mob/living/carbon/human/proc/has_embedded_objects() +/mob/living/carbon/proc/has_embedded_objects() . = 0 for(var/X in bodyparts) var/obj/item/bodypart/L = X @@ -100,7 +130,7 @@ //Helper for quickly creating a new limb - used by augment code in species.dm spec_attacked_by -/proc/newBodyPart(zone, robotic, fixed_icon, mob/living/carbon/human/source) +/mob/living/carbon/proc/newBodyPart(zone, robotic, fixed_icon) var/obj/item/bodypart/L switch(zone) if("l_arm") @@ -116,13 +146,64 @@ if("chest") L = new /obj/item/bodypart/chest() if(L) - if(source) - L.update_limb(fixed_icon, source) - else if(fixed_icon) - L.no_update = 1//when attached, the limb won't be affected by the appearance changes of its mob owner. + L.update_limb(fixed_icon, src) if(robotic) - L.change_bodypart_status(ORGAN_ROBOTIC) + L.change_bodypart_status(BODYPART_ROBOTIC) + . = L +/mob/living/carbon/monkey/newBodyPart(zone, robotic, fixed_icon) + var/obj/item/bodypart/L + switch(zone) + if("l_arm") + L = new /obj/item/bodypart/l_arm/monkey() + if("r_arm") + L = new /obj/item/bodypart/r_arm/monkey() + if("head") + L = new /obj/item/bodypart/head/monkey() + if("l_leg") + L = new /obj/item/bodypart/l_leg/monkey() + if("r_leg") + L = new /obj/item/bodypart/r_leg/monkey() + if("chest") + L = new /obj/item/bodypart/chest/monkey() + if(L) + L.update_limb(fixed_icon, src) + if(robotic) + L.change_bodypart_status(BODYPART_ROBOTIC) + . = L + +/mob/living/carbon/alien/larva/newBodyPart(zone, robotic, fixed_icon) + var/obj/item/bodypart/L + switch(zone) + if("head") + L = new /obj/item/bodypart/head/larva() + if("chest") + L = new /obj/item/bodypart/chest/larva() + if(L) + L.update_limb(fixed_icon, src) + if(robotic) + L.change_bodypart_status(BODYPART_ROBOTIC) + . = L + +/mob/living/carbon/alien/humanoid/newBodyPart(zone, robotic, fixed_icon) + var/obj/item/bodypart/L + switch(zone) + if("l_arm") + L = new /obj/item/bodypart/l_arm/alien() + if("r_arm") + L = new /obj/item/bodypart/r_arm/alien() + if("head") + L = new /obj/item/bodypart/head/alien() + if("l_leg") + L = new /obj/item/bodypart/l_leg/alien() + if("r_leg") + L = new /obj/item/bodypart/r_leg/alien() + if("chest") + L = new /obj/item/bodypart/chest/alien() + if(L) + L.update_limb(fixed_icon, src) + if(robotic) + L.change_bodypart_status(BODYPART_ROBOTIC) . = L diff --git a/code/modules/surgery/bodyparts/robot_bodyparts.dm b/code/modules/surgery/bodyparts/robot_bodyparts.dm new file mode 100644 index 000000000000..a5cefa1a0a71 --- /dev/null +++ b/code/modules/surgery/bodyparts/robot_bodyparts.dm @@ -0,0 +1,162 @@ + + +/obj/item/bodypart/l_arm/robot + name = "cyborg left arm" + desc = "A skeletal limb wrapped in pseudomuscles, with a low-conductivity case." + attack_verb = list("slapped", "punched") + item_state = "buildpipe" + icon = 'icons/obj/robot_parts.dmi' + flags = CONDUCT + icon_state = "l_arm" + status = BODYPART_ROBOTIC + + +/obj/item/bodypart/r_arm/robot + name = "cyborg right arm" + desc = "A skeletal limb wrapped in pseudomuscles, with a low-conductivity case." + attack_verb = list("slapped", "punched") + item_state = "buildpipe" + icon = 'icons/obj/robot_parts.dmi' + flags = CONDUCT + icon_state = "r_arm" + status = BODYPART_ROBOTIC + + +/obj/item/bodypart/l_leg/robot + name = "cyborg left leg" + desc = "A skeletal limb wrapped in pseudomuscles, with a low-conductivity case." + attack_verb = list("kicked", "stomped") + item_state = "buildpipe" + icon = 'icons/obj/robot_parts.dmi' + flags = CONDUCT + icon_state = "l_leg" + status = BODYPART_ROBOTIC + + +/obj/item/bodypart/r_leg/robot + name = "cyborg right leg" + desc = "A skeletal limb wrapped in pseudomuscles, with a low-conductivity case." + attack_verb = list("kicked", "stomped") + item_state = "buildpipe" + icon = 'icons/obj/robot_parts.dmi' + flags = CONDUCT + icon_state = "r_leg" + status = BODYPART_ROBOTIC + + +/obj/item/bodypart/chest/robot + name = "cyborg torso" + desc = "A heavily reinforced case containing cyborg logic boards, with space for a standard power cell." + item_state = "buildpipe" + icon = 'icons/obj/robot_parts.dmi' + flags = CONDUCT + icon_state = "chest" + status = BODYPART_ROBOTIC + var/wired = 0 + var/obj/item/weapon/stock_parts/cell/cell = null + +/obj/item/bodypart/chest/robot/attackby(obj/item/W, mob/user, params) + if(istype(W, /obj/item/weapon/stock_parts/cell)) + if(src.cell) + user << "You have already inserted a cell!" + return + else + if(!user.unEquip(W)) + return + W.loc = src + src.cell = W + user << "You insert the cell." + else if(istype(W, /obj/item/stack/cable_coil)) + if(src.wired) + user << "You have already inserted wire!" + return + var/obj/item/stack/cable_coil/coil = W + if (coil.use(1)) + src.wired = 1 + user << "You insert the wire." + else + user << "You need one length of coil to wire it!" + else + return ..() + +/obj/item/bodypart/chest/robot/Destroy() + if(cell) + qdel(cell) + cell = null + return ..() + + +/obj/item/bodypart/chest/robot/drop_organs(mob/user) + if(wired) + new /obj/item/stack/cable_coil(user.loc, 1) + if(cell) + cell.forceMove(user.loc) + cell = null + ..() + + +/obj/item/bodypart/head/robot + name = "cyborg head" + desc = "A standard reinforced braincase, with spine-plugged neural socket and sensor gimbals." + item_state = "buildpipe" + icon = 'icons/obj/robot_parts.dmi' + flags = CONDUCT + icon_state = "head" + status = BODYPART_ROBOTIC + var/obj/item/device/assembly/flash/handheld/flash1 = null + var/obj/item/device/assembly/flash/handheld/flash2 = null + + + +/obj/item/bodypart/head/robot/attackby(obj/item/W, mob/user, params) + if(istype(W, /obj/item/device/assembly/flash/handheld)) + var/obj/item/device/assembly/flash/handheld/F = W + if(src.flash1 && src.flash2) + user << "You have already inserted the eyes!" + return + else if(F.crit_fail) + user << "You can't use a broken flash!" + return + else + if(!user.unEquip(W)) + return + F.loc = src + if(src.flash1) + src.flash2 = F + else + src.flash1 = F + user << "You insert the flash into the eye socket." + else if(istype(W, /obj/item/weapon/crowbar)) + if(flash1 || flash2) + playsound(src.loc, 'sound/items/Crowbar.ogg', 50, 1) + user << "You remove the flash from [src]." + if(flash1) + flash1.forceMove(user.loc) + flash1 = null + if(flash2) + flash2.forceMove(user.loc) + flash2 = null + else + user << "There are no flash to remove from [src]." + + else + return ..() + +/obj/item/bodypart/head/robot/Destroy() + if(flash1) + qdel(flash1) + flash1 = null + if(flash2) + qdel(flash2) + flash2 = null + return ..() + + +/obj/item/bodypart/head/robot/drop_organs(mob/user) + if(flash1) + flash1.forceMove(user.loc) + flash1 = null + if(flash2) + flash2.forceMove(user.loc) + flash2 = null + ..() diff --git a/code/modules/surgery/generic_steps.dm b/code/modules/surgery/generic_steps.dm index ee324e432b45..89b070f28cc3 100644 --- a/code/modules/surgery/generic_steps.dm +++ b/code/modules/surgery/generic_steps.dm @@ -21,7 +21,7 @@ /datum/surgery_step/clamp_bleeders/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) if(locate(/datum/surgery_step/saw) in surgery.steps) - target.heal_organ_damage(20,0) + target.heal_bodypart_damage(20,0) return ..() @@ -69,7 +69,7 @@ /datum/surgery_step/close/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) if(locate(/datum/surgery_step/saw) in surgery.steps) - target.heal_organ_damage(45,0) + target.heal_bodypart_damage(45,0) return ..() @@ -84,9 +84,7 @@ user.visible_message("[user] begins to saw through the bone in [target]'s [parse_zone(target_zone)].", "You begin to saw through the bone in [target]'s [parse_zone(target_zone)]...") /datum/surgery_step/saw/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - if(ishuman(target)) - var/mob/living/carbon/human/H = target - H.apply_damage(50,"brute","[target_zone]") + target.apply_damage(50,"brute","[target_zone]") user.visible_message("[user] saws [target]'s [parse_zone(target_zone)] open!", "You saw [target]'s [parse_zone(target_zone)] open.") return 1 diff --git a/code/modules/surgery/helpers.dm b/code/modules/surgery/helpers.dm index 982ef0d4d40c..32b294a79991 100644 --- a/code/modules/surgery/helpers.dm +++ b/code/modules/surgery/helpers.dm @@ -2,13 +2,13 @@ if(!istype(M)) return - var/mob/living/carbon/human/H + var/mob/living/carbon/C var/obj/item/bodypart/affecting var/selected_zone = user.zone_selected - if(istype(M, /mob/living/carbon/human)) - H = M - affecting = H.get_bodypart(check_zone(selected_zone)) + if(istype(M, /mob/living/carbon)) + C = M + affecting = C.get_bodypart(check_zone(selected_zone)) if(!M.lying && !isslime(M)) //if they're prone or a slime return @@ -29,9 +29,9 @@ if(affecting) if(!S.requires_bodypart) continue - if(S.requires_organic_bodypart && affecting.status == ORGAN_ROBOTIC) + if(S.requires_organic_bodypart && affecting.status == BODYPART_ROBOTIC) continue - else if(H && S.requires_bodypart) //human with no limb in surgery zone when we need a limb + else if(C && S.requires_bodypart) //mob with no limb in surgery zone when we need a limb continue if(!S.can_start(user, M)) continue @@ -49,14 +49,14 @@ return //during the input() another surgery was started at the same location. //we check that the surgery is still doable after the input() wait. - if(H) - affecting = H.get_bodypart(check_zone(selected_zone)) + if(C) + affecting = C.get_bodypart(check_zone(selected_zone)) if(affecting) if(!S.requires_bodypart) return - if(S.requires_organic_bodypart && affecting.status == ORGAN_ROBOTIC) + if(S.requires_organic_bodypart && affecting.status == BODYPART_ROBOTIC) return - else if(H && S.requires_bodypart) + else if(C && S.requires_bodypart) return if(!S.can_start(user, M)) return diff --git a/code/modules/surgery/limb_augmentation.dm b/code/modules/surgery/limb_augmentation.dm index 3a00620a172e..5e16b420f218 100644 --- a/code/modules/surgery/limb_augmentation.dm +++ b/code/modules/surgery/limb_augmentation.dm @@ -16,17 +16,17 @@ /datum/surgery_step/add_limb name = "replace limb" - implements = list(/obj/item/robot_parts = 100) + implements = list(/obj/item/bodypart = 100) time = 32 var/obj/item/bodypart/L = null // L because "limb" /datum/surgery_step/add_limb/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - var/obj/item/robot_parts/aug = tool - if(istype(aug) && aug.body_zone != target_zone) + var/obj/item/bodypart/aug = tool + if(aug.status != BODYPART_ROBOTIC && aug.body_zone != target_zone) user << "[tool] isn't the right type for [parse_zone(target_zone)]." return -1 - L = surgery.organ + L = surgery.operated_bodypart if(L) user.visible_message("[user] begins to augment [target]'s [parse_zone(user.zone_selected)].", "You begin to augment [target]'s [parse_zone(user.zone_selected)]...") else @@ -45,15 +45,13 @@ /datum/surgery_step/add_limb/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) if(L) - if(ishuman(target)) - var/mob/living/carbon/human/H = target - user.visible_message("[user] successfully augments [target]'s [parse_zone(target_zone)]!", "You successfully augment [target]'s [parse_zone(target_zone)].") - L.change_bodypart_status(ORGAN_ROBOTIC, 1) - user.drop_item() - qdel(tool) - H.update_damage_overlays(0) - H.updatehealth() - add_logs(user, target, "augmented", addition="by giving him new [parse_zone(target_zone)] INTENT: [uppertext(user.a_intent)]") + user.visible_message("[user] successfully augments [target]'s [parse_zone(target_zone)]!", "You successfully augment [target]'s [parse_zone(target_zone)].") + L.change_bodypart_status(BODYPART_ROBOTIC, 1) + user.drop_item() + qdel(tool) + target.update_damage_overlays() + target.updatehealth() + add_logs(user, target, "augmented", addition="by giving him new [parse_zone(target_zone)] INTENT: [uppertext(user.a_intent)]") else user << "[target] has no organic [parse_zone(target_zone)] there!" return 1 diff --git a/code/modules/surgery/organs/augments_eyes.dm b/code/modules/surgery/organs/augments_eyes.dm index 50c3875f258a..eef8bf6dfd39 100644 --- a/code/modules/surgery/organs/augments_eyes.dm +++ b/code/modules/surgery/organs/augments_eyes.dm @@ -43,7 +43,7 @@ if(prob(10 * severity)) return owner << "Static obfuscates your vision!" - owner.flash_eyes(visual = 1) + owner.flash_act(visual = 1) /obj/item/organ/cyberimp/eyes/xray name = "X-ray implant" diff --git a/code/modules/surgery/organs/helpers.dm b/code/modules/surgery/organs/helpers.dm index f1ee5ec13f6b..48915fd59bd6 100644 --- a/code/modules/surgery/organs/helpers.dm +++ b/code/modules/surgery/organs/helpers.dm @@ -11,7 +11,7 @@ mob/proc/getorganslot(slot) mob/living/carbon/getorgan(typepath) return (locate(typepath) in internal_organs) -mob/living/carbon/getorganszone(zone, var/subzones = 0) +mob/living/carbon/getorganszone(zone, subzones = 0) var/list/returnorg = list() if(subzones) // Include subzones - groin for chest, eyes and mouth for head @@ -20,7 +20,8 @@ mob/living/carbon/getorganszone(zone, var/subzones = 0) if(zone == "chest") returnorg = getorganszone("groin") - for(var/obj/item/organ/O in internal_organs) + for(var/X in internal_organs) + var/obj/item/organ/O = X if(zone == O.zone) returnorg += O return returnorg diff --git a/code/modules/surgery/prosthetic_replacement.dm b/code/modules/surgery/prosthetic_replacement.dm index 7a0c9fa67180..5341c2bf09d8 100644 --- a/code/modules/surgery/prosthetic_replacement.dm +++ b/code/modules/surgery/prosthetic_replacement.dm @@ -1,52 +1,50 @@ /datum/surgery/prosthetic_replacement name = "prosthetic replacement" steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/add_prosthetic) - species = list(/mob/living/carbon/human) + species = list(/mob/living/carbon/human, /mob/living/carbon/monkey) possible_locs = list("r_arm", "l_arm", "l_leg", "r_leg", "head") requires_bodypart = FALSE //need a missing limb /datum/surgery/prosthetic_replacement/can_start(mob/user, mob/living/carbon/target) - if(!ishuman(target)) + if(!iscarbon(target)) return 0 - var/mob/living/carbon/human/H = target - if(!H.get_bodypart(user.zone_selected)) //can only start if limb is missing + var/mob/living/carbon/C = target + if(!C.get_bodypart(user.zone_selected)) //can only start if limb is missing return 1 /datum/surgery_step/add_prosthetic name = "add prosthetic" - implements = list(/obj/item/robot_parts = 100, /obj/item/bodypart = 100) + implements = list(/obj/item/bodypart = 100) time = 32 var/organ_rejection_dam = 0 /datum/surgery_step/add_prosthetic/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - var/tool_body_zone - if(istype(tool, /obj/item/robot_parts)) - var/obj/item/robot_parts/RP = tool - tool_body_zone = RP.body_zone - else if(istype(tool, /obj/item/bodypart)) - var/obj/item/bodypart/L = tool - if(L.status != ORGAN_ROBOTIC) - organ_rejection_dam = 10 - if(target.dna.species.id != L.species_id) + var/obj/item/bodypart/BP = tool + if(ismonkey(target))// monkey patient only accept organic monkey limbs + if(BP.status == BODYPART_ROBOTIC || BP.animal_origin != MONKEY_BODYPART) + user << "[BP] doesn't match the patient's morphology." + return -1 + if(BP.status != BODYPART_ROBOTIC) + organ_rejection_dam = 10 + if(ishuman(target)) + if(BP.animal_origin) + user << "[BP] doesn't match the patient's morphology." + return -1 + var/mob/living/carbon/human/H = target + if(H.dna.species.id != BP.species_id) organ_rejection_dam = 30 - tool_body_zone = L.body_zone - if(target_zone == tool_body_zone) //so we can't replace a leg with an arm. + + if(target_zone == BP.body_zone) //so we can't replace a leg with an arm, or a human arm with a monkey arm. user.visible_message("[user] begins to replace [target]'s [parse_zone(target_zone)].", "You begin to replace [target]'s [parse_zone(target_zone)]...") else user << "[tool] isn't the right type for [parse_zone(target_zone)]." return -1 /datum/surgery_step/add_prosthetic/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - var/obj/item/bodypart/L - if(istype(tool, /obj/item/robot_parts)) - L = newBodyPart(target_zone, 1, 1) - user.drop_item() - qdel(tool) - else - L = tool - user.drop_item() + var/obj/item/bodypart/L = tool + user.drop_item() L.attach_limb(target) if(organ_rejection_dam) target.adjustToxLoss(organ_rejection_dam) diff --git a/code/modules/surgery/remove_embedded_object.dm b/code/modules/surgery/remove_embedded_object.dm index 7117d276a76d..fa9db1ae8edd 100644 --- a/code/modules/surgery/remove_embedded_object.dm +++ b/code/modules/surgery/remove_embedded_object.dm @@ -12,7 +12,7 @@ /datum/surgery_step/remove_object/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - L = surgery.organ + L = surgery.operated_bodypart if(L) user.visible_message("[user] looks for objects embedded in [target]'s [parse_zone(user.zone_selected)].", "You look for objects embedded in [target]'s [parse_zone(user.zone_selected)]...") else diff --git a/code/modules/surgery/surgery.dm b/code/modules/surgery/surgery.dm index 35b154323040..26e57700ae5f 100644 --- a/code/modules/surgery/surgery.dm +++ b/code/modules/surgery/surgery.dm @@ -10,26 +10,26 @@ var/list/possible_locs = list() //Multiple locations var/ignore_clothes = 0 //This surgery ignores clothes var/mob/living/carbon/target //Operation target mob - var/obj/item/organ/organ //Operable body part + var/obj/item/bodypart/operated_bodypart //Operable body part var/requires_bodypart = TRUE //Surgery available only when a bodypart is present, or only when it is missing. var/success_multiplier = 0 //Step success propability multiplier -/datum/surgery/New(surgery_target, surgery_location, surgery_organ) +/datum/surgery/New(surgery_target, surgery_location, surgery_bodypart) ..() if(surgery_target) target = surgery_target target.surgeries += src if(surgery_location) location = surgery_location - if(surgery_organ) - organ = surgery_organ + if(surgery_bodypart) + operated_bodypart = surgery_bodypart /datum/surgery/Destroy() if(target) target.surgeries -= src target = null - organ = null + operated_bodypart = null return ..() diff --git a/code/modules/vehicles/scooter.dm b/code/modules/vehicles/scooter.dm index 64223336da14..7e3cbf954ac8 100644 --- a/code/modules/vehicles/scooter.dm +++ b/code/modules/vehicles/scooter.dm @@ -38,15 +38,18 @@ else buckled_mob.pixel_y = -4 +/obj/vehicle/scooter/buckle_mob(mob/living/M, force = 0) + if(!istype(M)) + return 0 + if(M.get_num_legs() < 2 && M.get_num_arms() <= 0) + M << "Your limbless body can't use [src]." + return 0 + . = ..() + /obj/vehicle/scooter/post_buckle_mob(mob/living/M) vehicle_move_delay = initial(vehicle_move_delay) - ..() if(M.get_num_legs() < 2) vehicle_move_delay ++ - if(M.get_num_arms() <= 0) - if(has_buckled_mobs())//to prevent the message displaying twice due to unbuckling - M << "Your limbless body flops off \the [src]." - unbuckle_mob(M) /obj/vehicle/scooter/skateboard name = "skateboard" diff --git a/code/modules/vehicles/vehicle.dm b/code/modules/vehicles/vehicle.dm index ac8fdaa8b6b2..f21275b6fce3 100644 --- a/code/modules/vehicles/vehicle.dm +++ b/code/modules/vehicles/vehicle.dm @@ -94,12 +94,14 @@ /obj/vehicle/relaymove(mob/user, direction) if(user.incapacitated()) unbuckle_mob(user) + return + if(world.time < next_vehicle_move) + return + next_vehicle_move = world.time + vehicle_move_delay if(keycheck(user)) - if(!Process_Spacemove(direction) || world.time < next_vehicle_move || !isturf(loc)) + if(!Process_Spacemove(direction) || !isturf(loc)) return - next_vehicle_move = world.time + vehicle_move_delay - step(src, direction) handle_vehicle_layer() diff --git a/icons/effects/blood.dmi b/icons/effects/blood.dmi index f073ff5b3380c36f578b7283ba808fa6c982dd90..e915cb49e3703341e14db63e4674e263e3bf6a1e 100644 GIT binary patch literal 106543 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 Vk@bWvctOB+@vO}myyevg{{nxW7JC2y literal 98826 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

uKjVTuAXl>ElAF-aGf#w4Z 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