From 00738bd2a39ed05e996949313bebe1c0b8123008 Mon Sep 17 00:00:00 2001 From: Remie Richards Date: Fri, 2 Sep 2016 02:09:32 +0100 Subject: [PATCH 01/41] More than 2 hands!? WHAAAAAAT --- code/__DEFINES/clothing.dm | 36 +- code/__DEFINES/misc.dm | 55 ++- code/__HELPERS/mobs.dm | 12 +- code/_onclick/autoclick.dm | 2 +- code/_onclick/click.dm | 8 +- code/_onclick/cyborg.dm | 2 +- code/_onclick/hud/_defines.dm | 21 +- code/_onclick/hud/alien.dm | 37 +- code/_onclick/hud/blob_overmind.dm | 4 +- code/_onclick/hud/devil.dm | 37 +- code/_onclick/hud/generic_dextrous.dm | 37 +- code/_onclick/hud/guardian.dm | 4 +- code/_onclick/hud/hud.dm | 41 +- code/_onclick/hud/human.dm | 38 +- code/_onclick/hud/monkey.dm | 36 +- code/_onclick/hud/robot.dm | 6 +- code/_onclick/hud/screen_objects.dm | 38 +- code/_onclick/hud/swarmer.dm | 4 +- code/_onclick/telekinesis.dm | 2 +- .../datums/diseases/advance/symptoms/cough.dm | 2 +- code/datums/diseases/wizarditis.dm | 9 +- code/datums/martial.dm | 3 +- code/datums/martial/krav_maga.dm | 14 +- code/datums/wires/wires.dm | 2 +- code/game/gamemodes/antag_spawner.dm | 2 +- .../gamemodes/changeling/powers/mutations.dm | 27 +- .../gamemodes/changeling/powers/tiny_prick.dm | 5 +- code/game/gamemodes/clock_cult/clock_items.dm | 10 +- code/game/gamemodes/clock_cult/clock_mobs.dm | 2 +- .../gamemodes/clock_cult/clock_unsorted.dm | 4 +- code/game/gamemodes/cult/cult.dm | 4 +- code/game/gamemodes/cult/runes.dm | 2 +- .../gamemodes/devil/true_devil/_true_devil.dm | 21 +- .../gamemodes/devil/true_devil/inventory.dm | 15 +- code/game/gamemodes/gang/gang.dm | 4 +- .../miniantags/abduction/abduction_gear.dm | 3 +- .../miniantags/abduction/machinery/console.dm | 2 +- code/game/gamemodes/nuclear/nuclear.dm | 4 +- code/game/gamemodes/nuclear/nuclearbomb.dm | 2 +- code/game/gamemodes/revolution/revolution.dm | 4 +- code/game/gamemodes/traitor/traitor.dm | 4 +- code/game/gamemodes/wizard/artefact.dm | 36 +- code/game/gamemodes/wizard/wizard.dm | 6 +- code/game/machinery/PDApainter.dm | 2 +- code/game/machinery/computer/card.dm | 4 +- code/game/machinery/computer/cloning.dm | 2 +- .../game/machinery/computer/communications.dm | 4 +- .../machinery/computer/gulag_teleporter.dm | 4 +- code/game/machinery/computer/medical.dm | 4 +- code/game/machinery/computer/prisoner.dm | 2 +- code/game/machinery/computer/security.dm | 8 +- .../machinery/computer/telecrystalconsoles.dm | 2 +- code/game/machinery/gulag_item_reclaimer.dm | 4 +- code/game/machinery/newscaster.dm | 4 +- .../machinery/porta_turret/portable_turret.dm | 9 +- code/game/machinery/spaceheater.dm | 2 +- .../telecomms/machine_interactions.dm | 12 +- code/game/machinery/vending.dm | 2 +- code/game/objects/effects/mines.dm | 3 +- code/game/objects/items.dm | 10 +- code/game/objects/items/bodybag.dm | 2 +- code/game/objects/items/devices/PDA/PDA.dm | 6 +- .../objects/items/devices/taperecorder.dm | 2 +- code/game/objects/items/latexballoon.dm | 6 +- code/game/objects/items/robot/robot_parts.dm | 4 +- code/game/objects/items/stacks/rods.dm | 2 +- .../game/objects/items/stacks/sheets/glass.dm | 4 +- code/game/objects/items/stacks/stack.dm | 4 +- .../objects/items/stacks/tiles/tile_types.dm | 4 +- code/game/objects/items/stacks/wrap.dm | 2 +- code/game/objects/items/toys.dm | 17 +- .../objects/items/weapons/chrono_eraser.dm | 2 +- .../objects/items/weapons/cigs_lighters.dm | 7 +- code/game/objects/items/weapons/defib.dm | 18 +- code/game/objects/items/weapons/explosives.dm | 2 +- .../objects/items/weapons/flamethrower.dm | 4 +- .../objects/items/weapons/grenades/plastic.dm | 2 +- .../items/weapons/implants/implantcase.dm | 2 +- .../items/weapons/implants/implanter.dm | 2 +- .../items/weapons/implants/implantpad.dm | 2 +- .../objects/items/weapons/melee/energy.dm | 7 +- code/game/objects/items/weapons/paint.dm | 2 +- .../objects/items/weapons/storage/boxes.dm | 3 +- .../objects/items/weapons/storage/fancy.dm | 2 +- .../objects/items/weapons/storage/firstaid.dm | 6 +- .../objects/items/weapons/storage/storage.dm | 14 +- .../objects/items/weapons/tanks/watertank.dm | 17 +- .../objects/items/weapons/teleportation.dm | 2 +- code/game/objects/items/weapons/tools.dm | 3 +- code/game/objects/items/weapons/twohanded.dm | 15 +- code/game/objects/structures.dm | 2 +- code/game/objects/structures/guncase.dm | 6 +- code/game/objects/structures/morgue.dm | 2 +- code/game/objects/structures/noticeboard.dm | 11 +- code/game/objects/structures/safe.dm | 2 +- code/game/objects/structures/tables_racks.dm | 2 +- code/game/objects/structures/target_stake.dm | 2 +- code/game/objects/structures/watercloset.dm | 6 +- code/game/turfs/open.dm | 4 +- code/game/turfs/simulated/walls.dm | 6 +- code/game/turfs/simulated/walls_reinforced.dm | 18 +- code/modules/admin/topic.dm | 18 +- code/modules/admin/verbs/onlyone.dm | 4 +- code/modules/assembly/mousetrap.dm | 6 +- code/modules/awaymissions/corpse.dm | 4 +- .../modules/awaymissions/super_secret_room.dm | 2 +- code/modules/client/verbs/suicide.dm | 2 +- code/modules/clothing/clothing.dm | 7 +- code/modules/clothing/head/misc_special.dm | 2 +- code/modules/clothing/outfits/standard.dm | 6 +- .../modules/clothing/spacesuits/chronosuit.dm | 24 +- code/modules/crafting/craft.dm | 4 +- code/modules/detectivework/evidence.dm | 6 +- code/modules/events/holiday/xmas.dm | 2 +- code/modules/events/wizard/curseditems.dm | 6 +- code/modules/flufftext/Hallucination.dm | 22 +- code/modules/food_and_drinks/pizzabox.dm | 2 +- code/modules/hydroponics/gene_modder.dm | 6 +- code/modules/hydroponics/grown/chili.dm | 2 +- code/modules/hydroponics/grown/nettle.dm | 2 +- code/modules/jobs/access.dm | 6 +- code/modules/library/lib_items.dm | 4 +- code/modules/mining/laborcamp/laborstacker.dm | 4 +- .../mining/lavaland/necropolis_chests.dm | 8 +- code/modules/mining/machine_redemption.dm | 4 +- code/modules/mining/machine_vending.dm | 4 +- code/modules/mining/mine_turfs.dm | 7 +- code/modules/mob/interactive.dm | 43 +- code/modules/mob/inventory.dm | 436 ++++++++++++------ code/modules/mob/living/bloodcrawl.dm | 2 +- .../living/carbon/alien/humanoid/humanoid.dm | 17 +- .../carbon/alien/humanoid/update_icons.dm | 33 +- code/modules/mob/living/carbon/carbon.dm | 54 ++- .../mob/living/carbon/carbon_defense.dm | 2 +- code/modules/mob/living/carbon/examine.dm | 12 +- code/modules/mob/living/carbon/human/emote.dm | 14 +- .../mob/living/carbon/human/examine.dm | 20 +- code/modules/mob/living/carbon/human/human.dm | 41 +- .../living/carbon/human/human_attackalien.dm | 2 +- .../mob/living/carbon/human/human_defense.dm | 26 +- .../mob/living/carbon/human/human_defines.dm | 2 + .../mob/living/carbon/human/human_helpers.dm | 14 +- .../mob/living/carbon/human/inventory.dm | 6 +- .../mob/living/carbon/human/species.dm | 26 +- .../mob/living/carbon/human/species_types.dm | 24 +- .../mob/living/carbon/human/update_icons.dm | 27 +- code/modules/mob/living/carbon/inventory.dm | 28 +- .../mob/living/carbon/monkey/inventory.dm | 32 +- .../mob/living/carbon/monkey/monkey.dm | 11 +- .../modules/mob/living/carbon/update_icons.dm | 73 +-- code/modules/mob/living/living.dm | 19 +- code/modules/mob/living/living_defense.dm | 3 +- code/modules/mob/living/say.dm | 15 +- .../mob/living/silicon/robot/examine.dm | 2 +- .../mob/living/silicon/robot/inventory.dm | 2 +- .../modules/mob/living/silicon/robot/robot.dm | 11 +- .../mob/living/simple_animal/friendly/dog.dm | 4 +- .../simple_animal/friendly/drone/_drone.dm | 20 +- .../friendly/drone/interaction.dm | 5 +- .../simple_animal/friendly/drone/inventory.dm | 7 +- .../friendly/drone/visuals_icons.dm | 19 +- .../living/simple_animal/guardian/guardian.dm | 26 +- .../simple_animal/guardian/types/charger.dm | 4 +- .../simple_animal/guardian/types/dextrous.dm | 22 +- .../mob/living/simple_animal/parrot.dm | 24 +- .../mob/living/simple_animal/simple_animal.dm | 47 +- code/modules/mob/mob.dm | 28 +- code/modules/mob/mob_defines.dm | 11 +- code/modules/mob/mob_helpers.dm | 9 +- code/modules/mob/mob_movement.dm | 2 +- code/modules/mob/update_icons.dm | 7 +- .../computers/item/laptop.dm | 7 +- .../modular_computers/file_system/program.dm | 2 +- .../file_system/programs/card.dm | 4 +- .../ninja/suit/n_suit_verbs/ninja_stars.dm | 8 +- code/modules/paperwork/clipboard.dm | 11 +- code/modules/paperwork/paper.dm | 4 +- code/modules/paperwork/paper_cutter.dm | 6 +- code/modules/paperwork/paperbin.dm | 6 +- code/modules/paperwork/photography.dm | 16 +- code/modules/power/lighting.dm | 2 +- code/modules/projectiles/gun.dm | 13 +- code/modules/projectiles/guns/energy.dm | 2 +- code/modules/projectiles/guns/projectile.dm | 4 +- .../guns/projectile/laser_gatling.dm | 6 +- .../chemistry/reagents/drug_reagents.dm | 8 +- .../chemistry/reagents/medicine_reagents.dm | 10 +- .../chemistry/reagents/other_reagents.dm | 6 +- .../reagents/reagent_containers/blood_pack.dm | 2 +- code/modules/spells/spell_types/charge.dm | 2 +- code/modules/spells/spell_types/lichdom.dm | 2 +- code/modules/spells/spell_types/summonitem.dm | 15 +- .../spells/spell_types/touch_attacks.dm | 11 +- code/modules/surgery/bodyparts/bodyparts.dm | 2 +- .../surgery/bodyparts/dismemberment.dm | 16 +- code/modules/surgery/bodyparts/helpers.dm | 42 +- code/modules/surgery/helpers.dm | 2 +- code/modules/surgery/implant_removal.dm | 11 +- code/modules/surgery/limb_augmentation.dm | 9 +- code/modules/surgery/organ_manipulation.dm | 2 +- code/modules/surgery/organs/augments_arms.dm | 12 +- .../surgery/organs/augments_internal.dm | 64 +-- code/modules/surgery/surgery.dm | 2 +- code/modules/telesci/bscrystal.dm | 2 +- code/modules/tgui/states/hands.dm | 2 +- code/modules/vehicles/vehicle.dm | 2 +- code/modules/zombie/items.dm | 12 +- 207 files changed, 1230 insertions(+), 1404 deletions(-) diff --git a/code/__DEFINES/clothing.dm b/code/__DEFINES/clothing.dm index f5efa04ea62..6fbb8e5d7d1 100644 --- a/code/__DEFINES/clothing.dm +++ b/code/__DEFINES/clothing.dm @@ -17,25 +17,25 @@ #define slot_back 1 #define slot_wear_mask 2 #define slot_handcuffed 3 -#define slot_l_hand 4 -#define slot_r_hand 5 -#define slot_belt 6 -#define slot_wear_id 7 -#define slot_ears 8 -#define slot_glasses 9 -#define slot_gloves 10 -#define slot_head 11 -#define slot_shoes 12 -#define slot_wear_suit 13 -#define slot_w_uniform 14 -#define slot_l_store 15 -#define slot_r_store 16 -#define slot_s_store 17 -#define slot_in_backpack 18 -#define slot_legcuffed 19 -#define slot_generic_dextrous_storage 20 +#define slot_hands 4 //wherever you provide a slot for hands you provide slot_hands AND a hand index (1 to held_items.len) + //there are various helper procs to find an appropriate index +#define slot_belt 5 +#define slot_wear_id 6 +#define slot_ears 7 +#define slot_glasses 8 +#define slot_gloves 9 +#define slot_head 10 +#define slot_shoes 11 +#define slot_wear_suit 12 +#define slot_w_uniform 13 +#define slot_l_store 14 +#define slot_r_store 15 +#define slot_s_store 16 +#define slot_in_backpack 17 +#define slot_legcuffed 18 +#define slot_generic_dextrous_storage 19 -#define slots_amt 20 // Keep this up to date! +#define slots_amt 19 // Keep this up to date! //I hate that this has to exist /proc/slotdefine2slotbit(slotdefine) //Keep this up to date with the value of SLOT BITMASKS and SLOTS (the two define sections above) diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index f7fb200c757..c859696ccb4 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -30,33 +30,32 @@ #define FRIDAY_13TH "Friday the 13th" //Human Overlays Indexes///////// -#define MUTATIONS_LAYER 26 //mutations. Tk headglows, cold resistance glow, etc -#define BODY_BEHIND_LAYER 25 //certain mutantrace features (tail when looking south) that must appear behind the body parts -#define BODYPARTS_LAYER 24 //Initially "AUGMENTS", this was repurposed to be a catch-all bodyparts flag -#define BODY_ADJ_LAYER 23 //certain mutantrace features (snout, body markings) that must appear above the body parts -#define BODY_LAYER 22 //underwear, undershirts, socks, eyes, lips(makeup) -#define FRONT_MUTATIONS_LAYER 21 //mutations that should appear above body, body_adj and bodyparts layer (e.g. laser eyes) -#define DAMAGE_LAYER 20 //damage indicators (cuts and burns) -#define UNIFORM_LAYER 19 -#define ID_LAYER 18 -#define SHOES_LAYER 17 -#define GLOVES_LAYER 16 -#define EARS_LAYER 15 -#define SUIT_LAYER 14 -#define GLASSES_LAYER 13 -#define BELT_LAYER 12 //Possible make this an overlay of somethign required to wear a belt? -#define SUIT_STORE_LAYER 11 -#define BACK_LAYER 10 -#define HAIR_LAYER 9 //TODO: make part of head layer? -#define FACEMASK_LAYER 8 -#define HEAD_LAYER 7 -#define HANDCUFF_LAYER 6 -#define LEGCUFF_LAYER 5 -#define L_HAND_LAYER 4 -#define R_HAND_LAYER 3 //Having the two hands seperate seems rather silly, merge them together? It'll allow for code to be reused on mobs with arbitarily many hands +#define MUTATIONS_LAYER 25 //mutations. Tk headglows, cold resistance glow, etc +#define BODY_BEHIND_LAYER 24 //certain mutantrace features (tail when looking south) that must appear behind the body parts +#define BODYPARTS_LAYER 23 //Initially "AUGMENTS", this was repurposed to be a catch-all bodyparts flag +#define BODY_ADJ_LAYER 22 //certain mutantrace features (snout, body markings) that must appear above the body parts +#define BODY_LAYER 21 //underwear, undershirts, socks, eyes, lips(makeup) +#define FRONT_MUTATIONS_LAYER 20 //mutations that should appear above body, body_adj and bodyparts layer (e.g. laser eyes) +#define DAMAGE_LAYER 19 //damage indicators (cuts and burns) +#define UNIFORM_LAYER 18 +#define ID_LAYER 17 +#define SHOES_LAYER 16 +#define GLOVES_LAYER 15 +#define EARS_LAYER 14 +#define SUIT_LAYER 13 +#define GLASSES_LAYER 12 +#define BELT_LAYER 11 //Possible make this an overlay of somethign required to wear a belt? +#define SUIT_STORE_LAYER 10 +#define BACK_LAYER 9 +#define HAIR_LAYER 8 //TODO: make part of head layer? +#define FACEMASK_LAYER 7 +#define HEAD_LAYER 6 +#define HANDCUFF_LAYER 5 +#define LEGCUFF_LAYER 4 +#define HANDS_LAYER 3 #define BODY_FRONT_LAYER 2 #define FIRE_LAYER 1 //If you're on fire -#define TOTAL_LAYERS 26 //KEEP THIS UP-TO-DATE OR SHIT WILL BREAK ;_; +#define TOTAL_LAYERS 25 //KEEP THIS UP-TO-DATE OR SHIT WILL BREAK ;_; //Human Overlay Index Shortcuts for alternate_worn_layer, layers //Because I *KNOW* somebody will think layer+1 means "above" @@ -82,8 +81,7 @@ #define UNDER_HEAD_LAYER HEAD_LAYER+1 #define UNDER_HANDCUFF_LAYER HANDCUFF_LAYER+1 #define UNDER_LEGCUFF_LAYER LEGCUFF_LAYER+1 -#define UNDER_L_HAND_LAYER L_HAND_LAYER+1 -#define UNDER_R_HAND_LAYER R_HAND_LAYER+1 +#define UNDER_HANDS_LAYER HANDS_LAYER+1 #define UNDER_BODY_FRONT_LAYER BODY_FRONT_LAYER+1 #define UNDER_FIRE_LAYER FIRE_LAYER+1 @@ -109,8 +107,7 @@ #define ABOVE_HEAD_LAYER HEAD_LAYER-1 #define ABOVE_HANDCUFF_LAYER HANDCUFF_LAYER-1 #define ABOVE_LEGCUFF_LAYER LEGCUFF_LAYER-1 -#define ABOVE_L_HAND_LAYER L_HAND_LAYER-1 -#define ABOVE_R_HAND_LAYER R_HAND_LAYER-1 +#define ABOVE_HANDS_LAYER HANDS_LAYER-1 #define ABOVE_BODY_FRONT_LAYER BODY_FRONT_LAYER-1 #define ABOVE_FIRE_LAYER FIRE_LAYER-1 diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index 8de02bd774c..0fcbb30ef6e 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -191,7 +191,7 @@ Proc for attack log creation, because really why not var/target_loc = target.loc - var/holding = user.get_active_hand() + var/holding = user.get_active_held_item() var/datum/progressbar/progbar if (progress) progbar = new(user, time, target) @@ -213,7 +213,7 @@ Proc for attack log creation, because really why not drifting = 0 user_loc = user.loc - if((!drifting && user.loc != user_loc) || target.loc != target_loc || user.get_active_hand() != holding || user.incapacitated() || user.lying ) + if((!drifting && user.loc != user_loc) || target.loc != target_loc || user.get_active_held_item() != holding || user.incapacitated() || user.lying ) . = 0 break if (progress) @@ -233,7 +233,7 @@ Proc for attack log creation, because really why not if(!user.Process_Spacemove(0) && user.inertia_dir) drifting = 1 - var/holding = user.get_active_hand() + var/holding = user.get_active_held_item() var/holdingnull = 1 //User's hand started out empty, check for an empty hand if(holding) @@ -270,7 +270,7 @@ Proc for attack log creation, because really why not if(!holding) . = 0 break - if(user.get_active_hand() != holding) + if(user.get_active_held_item() != holding) . = 0 break if (progress) @@ -291,7 +291,7 @@ Proc for attack log creation, because really why not for(var/atom/target in targets) originalloc[target] = target.loc - var/holding = user.get_active_hand() + var/holding = user.get_active_held_item() var/datum/progressbar/progbar if(progress) progbar = new(user, time, targets[1]) @@ -315,7 +315,7 @@ Proc for attack log creation, because really why not user_loc = user.loc for(var/atom/target in targets) - if((!drifting && user_loc != user.loc) || originalloc[target] != target.loc || user.get_active_hand() != holding || user.incapacitated() || user.lying ) + if((!drifting && user_loc != user.loc) || originalloc[target] != target.loc || user.get_active_held_item() != holding || user.incapacitated() || user.lying ) . = 0 break mainloop if(progbar) diff --git a/code/_onclick/autoclick.dm b/code/_onclick/autoclick.dm index 3fe84195b6c..1ceeb182ed7 100644 --- a/code/_onclick/autoclick.dm +++ b/code/_onclick/autoclick.dm @@ -23,7 +23,7 @@ /mob/living/carbon/CanMobAutoclick(atom/object, location, params) if(!object.IsAutoclickable()) return - var/obj/item/h = get_active_hand() + var/obj/item/h = get_active_held_item() if(h) . = h.CanItemAutoclick(object, location, params) diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index b029eb69863..dc21aa4185a 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -98,16 +98,12 @@ throw_item(A) return - var/obj/item/W = get_active_hand() + var/obj/item/W = get_active_held_item() if(W == A) W.attack_self(src) - if(hand) - update_inv_l_hand(0) - else - update_inv_r_hand(0) - return + update_inv_hands() // operate three levels deep here (item in backpack in src; item in box in backpack in src, not any deeper) if(A.ClickAccessible(src, depth=INVENTORY_DEPTH)) diff --git a/code/_onclick/cyborg.dm b/code/_onclick/cyborg.dm index a3d084afe17..b0c110cddc5 100644 --- a/code/_onclick/cyborg.dm +++ b/code/_onclick/cyborg.dm @@ -51,7 +51,7 @@ aicamera.captureimage(A, usr) return - var/obj/item/W = get_active_hand() + var/obj/item/W = get_active_held_item() // Cyborgs have no range-checking unless there is item use if(!W) diff --git a/code/_onclick/hud/_defines.dm b/code/_onclick/hud/_defines.dm index 0480bd43814..ad0ea23e9da 100644 --- a/code/_onclick/hud/_defines.dm +++ b/code/_onclick/hud/_defines.dm @@ -33,11 +33,21 @@ #define ui_id "CENTER-4:12,SOUTH:5" #define ui_belt "CENTER-3:14,SOUTH:5" #define ui_back "CENTER-2:14,SOUTH:5" -#define ui_rhand "CENTER:-16,SOUTH:5" -#define ui_lhand "CENTER: 16,SOUTH:5" -#define ui_equip "CENTER:-16,SOUTH+1:5" -#define ui_swaphand1 "CENTER:-16,SOUTH+1:5" -#define ui_swaphand2 "CENTER: 16,SOUTH+1:5" + +/proc/ui_hand_position(i) //values based on old hand ui positions (CENTER:-/+16,SOUTH:5) + var/x_off = -(!(i % 2)) + var/y_off = round((i-1) / 2) + return"CENTER+[x_off]:16,SOUTH+[y_off]:5" + +/proc/ui_equip_position(mob/M) + var/y_off = round((M.held_items.len-1) / 2) //values based on old equip ui position (CENTER: +/-16,SOUTH+1:5) + return "CENTER:-16,SOUTH+[y_off+1]:5" + +/proc/ui_swaphand_position(mob/M, which = 1) //values based on old swaphand ui positions (CENTER: +/-16,SOUTH+1:5) + var/x_off = which == 1 ? -1 : 0 + var/y_off = round((M.held_items.len-1) / 2) + return "CENTER+[x_off]:16,SOUTH+[y_off+1]:5" + #define ui_storage1 "CENTER+1:18,SOUTH:5" #define ui_storage2 "CENTER+2:20,SOUTH:5" @@ -141,3 +151,4 @@ #define ui_deityhealth "EAST-1:28,CENTER-2:13" #define ui_deitypower "EAST-1:28,CENTER-1:15" #define ui_deityfollowers "EAST-1:28,CENTER:17" + diff --git a/code/_onclick/hud/alien.dm b/code/_onclick/hud/alien.dm index 8ea573ad34a..2cd637f9653 100644 --- a/code/_onclick/hud/alien.dm +++ b/code/_onclick/hud/alien.dm @@ -39,39 +39,24 @@ ..() var/obj/screen/using - var/obj/screen/inventory/inv_box //equippable shit //hands - inv_box = new /obj/screen/inventory/hand() - inv_box.name = "right hand" - inv_box.icon = 'icons/mob/screen_alien.dmi' - inv_box.icon_state = "hand_r" - inv_box.screen_loc = ui_rhand - inv_box.slot_id = slot_r_hand - static_inventory += inv_box - - inv_box = new /obj/screen/inventory/hand() - inv_box.name = "left hand" - inv_box.icon = 'icons/mob/screen_alien.dmi' - inv_box.icon_state = "hand_l" - inv_box.screen_loc = ui_lhand - inv_box.slot_id = slot_l_hand - static_inventory += inv_box + build_hand_slots('icons/mob/screen_alien.dmi') //begin buttons using = new /obj/screen/swap_hand() using.icon = 'icons/mob/screen_alien.dmi' using.icon_state = "swap_1" - using.screen_loc = ui_swaphand1 + using.screen_loc = ui_swaphand_position(owner,1) static_inventory += using using = new /obj/screen/swap_hand() using.icon = 'icons/mob/screen_alien.dmi' using.icon_state = "swap_2" - using.screen_loc = ui_swaphand2 + using.screen_loc = ui_swaphand_position(owner,2) static_inventory += using using = new /obj/screen/act_intent/alien() @@ -136,17 +121,13 @@ return var/mob/living/carbon/alien/humanoid/H = mymob if(hud_version != HUD_STYLE_NOHUD) - if(H.r_hand) - H.r_hand.screen_loc = ui_rhand - H.client.screen += H.r_hand - if(H.l_hand) - H.l_hand.screen_loc = ui_lhand - H.client.screen += H.l_hand + for(var/obj/item/I in H.held_items) + I.screen_loc = ui_hand_position(H.get_held_index_of_item(I)) + H.client.screen += I else - if(H.r_hand) - H.r_hand.screen_loc = null - if(H.l_hand) - H.l_hand.screen_loc = null + for(var/obj/item/I in H.held_items) + I.screen_loc = null + H.client.screen -= I /mob/living/carbon/alien/humanoid/create_mob_hud() if(client && !hud_used) diff --git a/code/_onclick/hud/blob_overmind.dm b/code/_onclick/hud/blob_overmind.dm index 566132808b4..a375374ba22 100644 --- a/code/_onclick/hud/blob_overmind.dm +++ b/code/_onclick/hud/blob_overmind.dm @@ -159,11 +159,11 @@ static_inventory += using using = new /obj/screen/blob/NodeBlob() - using.screen_loc = ui_rhand + using.screen_loc = ui_hand_position(2) static_inventory += using using = new /obj/screen/blob/FactoryBlob() - using.screen_loc = ui_lhand + using.screen_loc = ui_hand_position(1) static_inventory += using using = new /obj/screen/blob/ReadaptChemical() diff --git a/code/_onclick/hud/devil.dm b/code/_onclick/hud/devil.dm index 0ddaeccd238..ec2597b1975 100644 --- a/code/_onclick/hud/devil.dm +++ b/code/_onclick/hud/devil.dm @@ -5,7 +5,6 @@ /datum/hud/devil/New(mob/owner, ui_style = 'icons/mob/screen_midnight.dmi') ..() var/obj/screen/using - var/obj/screen/inventory/inv_box using = new /obj/screen/drop() using.icon = ui_style @@ -18,27 +17,13 @@ pull_icon.screen_loc = ui_drone_pull static_inventory += pull_icon - inv_box = new /obj/screen/inventory/hand() - inv_box.name = "right hand" - inv_box.icon = ui_style - inv_box.icon_state = "hand_r" - inv_box.screen_loc = ui_rhand - inv_box.slot_id = slot_r_hand - static_inventory += inv_box - - inv_box = new /obj/screen/inventory/hand() - inv_box.name = "left hand" - inv_box.icon = ui_style - inv_box.icon_state = "hand_l" - inv_box.screen_loc = ui_lhand - inv_box.slot_id = slot_l_hand - static_inventory += inv_box + build_hand_slots(ui_style) using = new /obj/screen/inventory() using.name = "hand" using.icon = ui_style using.icon_state = "swap_1_m" - using.screen_loc = ui_swaphand1 + using.screen_loc = ui_swaphand_position(owner,1) using.layer = HUD_LAYER static_inventory += using @@ -46,7 +31,7 @@ using.name = "hand" using.icon = ui_style using.icon_state = "swap_2" - using.screen_loc = ui_swaphand2 + using.screen_loc = ui_swaphand_position(owner,2) using.layer = HUD_LAYER static_inventory += using @@ -65,17 +50,13 @@ var/mob/living/carbon/true_devil/D = mymob if(hud_version != HUD_STYLE_NOHUD) - if(D.r_hand) - D.r_hand.screen_loc = ui_rhand - D.client.screen += D.r_hand - if(D.l_hand) - D.l_hand.screen_loc = ui_lhand - D.client.screen += D.l_hand + for(var/obj/item/I in D.held_items) + I.screen_loc = ui_hand_position(D.get_held_index_of_item(I)) + D.client.screen += I else - if(D.r_hand) - D.r_hand.screen_loc = null - if(D.l_hand) - D.l_hand.screen_loc = null + for(var/obj/item/I in D.held_items) + I.screen_loc = null + D.client.screen -= I /mob/living/carbon/true_devil/create_mob_hud() if(client && !hud_used) diff --git a/code/_onclick/hud/generic_dextrous.dm b/code/_onclick/hud/generic_dextrous.dm index 8ecfed99627..509af712b90 100644 --- a/code/_onclick/hud/generic_dextrous.dm +++ b/code/_onclick/hud/generic_dextrous.dm @@ -2,7 +2,6 @@ /datum/hud/dextrous/New(mob/living/owner, ui_style = 'icons/mob/screen_midnight.dmi') ..() var/obj/screen/using - var/obj/screen/inventory/inv_box using = new /obj/screen/drop() using.icon = ui_style @@ -15,32 +14,18 @@ pull_icon.screen_loc = ui_drone_pull static_inventory += pull_icon - inv_box = new /obj/screen/inventory/hand() - inv_box.name = "right hand" - inv_box.icon = ui_style - inv_box.icon_state = "hand_r" - inv_box.screen_loc = ui_rhand - inv_box.slot_id = slot_r_hand - static_inventory += inv_box - - inv_box = new /obj/screen/inventory/hand() - inv_box.name = "left hand" - inv_box.icon = ui_style - inv_box.icon_state = "hand_l" - inv_box.screen_loc = ui_lhand - inv_box.slot_id = slot_l_hand - static_inventory += inv_box + build_hand_slots(ui_style) using = new /obj/screen/swap_hand() using.icon = ui_style using.icon_state = "swap_1_m" - using.screen_loc = ui_swaphand1 + using.screen_loc = ui_swaphand_position(owner,1) static_inventory += using using = new /obj/screen/swap_hand() using.icon = ui_style using.icon_state = "swap_2" - using.screen_loc = ui_swaphand2 + using.screen_loc = ui_swaphand_position(owner,2) static_inventory += using zone_select = new /obj/screen/zone_sel() @@ -68,14 +53,10 @@ return var/mob/living/D = mymob if(hud_version != HUD_STYLE_NOHUD) - if(D.r_hand) - D.r_hand.screen_loc = ui_rhand - D.client.screen += D.r_hand - if(D.l_hand) - D.l_hand.screen_loc = ui_lhand - D.client.screen += D.l_hand + for(var/obj/item/I in D.held_items) + I.screen_loc = ui_hand_position(D.get_held_index_of_item(I)) + D.client.screen += I else - if(D.r_hand) - D.r_hand.screen_loc = null - if(D.l_hand) - D.l_hand.screen_loc = null + for(var/obj/item/I in D.held_items) + I.screen_loc = null + D.client.screen -= I diff --git a/code/_onclick/hud/guardian.dm b/code/_onclick/hud/guardian.dm index d8b92fba713..aa50ca3712e 100644 --- a/code/_onclick/hud/guardian.dm +++ b/code/_onclick/hud/guardian.dm @@ -7,11 +7,11 @@ infodisplay += healths using = new /obj/screen/guardian/Manifest() - using.screen_loc = ui_rhand + using.screen_loc = ui_hand_position(2) static_inventory += using using = new /obj/screen/guardian/Recall() - using.screen_loc = ui_lhand + using.screen_loc = ui_hand_position(1) static_inventory += using using = new owner.toggle_button_type() diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm index d55eb8db92f..a7930dc8c2c 100644 --- a/code/_onclick/hud/hud.dm +++ b/code/_onclick/hud/hud.dm @@ -39,6 +39,7 @@ var/list/infodisplay = list() //the screen objects that display mob info (health, alien plasma, etc...) var/list/screenoverlays = list() //the screen objects used as whole screen overlays (flash, damageoverlay, etc...) var/list/inv_slots[slots_amt] // /obj/screen/inventory objects, ordered by their slot ID. + var/list/hand_slots // /obj/screen/inventory/hand objects, assoc list of "[held_index]" = object var/obj/screen/movable/action_button/hide_toggle/hide_actions_toggle var/action_buttons_hidden = 0 @@ -51,6 +52,7 @@ mymob = owner hide_actions_toggle = new hide_actions_toggle.InitialiseIcon(mymob) + hand_slots = list() /datum/hud/Destroy() if(mymob.hud_used == src) @@ -159,10 +161,10 @@ screenmob.client.screen += infodisplay //These ones are a part of 'static_inventory', 'toggleable_inventory' or 'hotkeybuttons' but we want them to stay - if(inv_slots[slot_l_hand]) - screenmob.client.screen += inv_slots[slot_l_hand] //we want the hands to be visible - if(inv_slots[slot_r_hand]) - screenmob.client.screen += inv_slots[slot_r_hand] //we want the hands to be visible + for(var/h in hand_slots) + var/obj/screen/hand = hand_slots[h] + if(hand) + screenmob.client.screen += hand if(action_intent) screenmob.client.screen += action_intent //we want the intent switcher visible action_intent.screen_loc = ui_acti_alt //move this to the alternative position, where zone_select usually is. @@ -210,3 +212,34 @@ else usr << "This mob type does not use a HUD." + +//(re)builds the hand ui slots, throwing away old ones +//not really worth jugglying existing ones so we just scrap+rebuild +//9/10 this is only called once per mob and only for 2 hands +/datum/hud/proc/build_hand_slots(ui_style = 'icons/mob/screen_midnight.dmi') + for(var/h in hand_slots) + var/obj/screen/inventory/hand/H = hand_slots[h] + if(H) + static_inventory -= H + hand_slots = list() + var/obj/screen/inventory/hand/hand_box + for(var/i in 1 to mymob.held_items.len) + hand_box = new /obj/screen/inventory/hand() + hand_box.name = mymob.get_held_index_name(i) + hand_box.icon = ui_style + hand_box.icon_state = "hand_[mymob.held_index_to_dir(i)]" + hand_box.screen_loc = ui_hand_position(i) + hand_box.held_index = i + hand_slots["[i]"] = hand_box + hand_box.hud = src + static_inventory += hand_box + hand_box.update_icon() + + var/i = 1 + for(var/obj/screen/swap_hand/SH in static_inventory) + SH.screen_loc = ui_swaphand_position(mymob,!(i % 2) ? 2: 1) + 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 diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm index 33cac0a4d28..53b7ce8a0c9 100644 --- a/code/_onclick/hud/human.dm +++ b/code/_onclick/hud/human.dm @@ -133,32 +133,18 @@ inv_box.screen_loc = ui_oclothing toggleable_inventory += inv_box - inv_box = new /obj/screen/inventory/hand() - inv_box.name = "right hand" - inv_box.icon = ui_style - inv_box.icon_state = "hand_r" - inv_box.screen_loc = ui_rhand - inv_box.slot_id = slot_r_hand - static_inventory += inv_box - - inv_box = new /obj/screen/inventory/hand() - inv_box.name = "left hand" - inv_box.icon = ui_style - inv_box.icon_state = "hand_l" - inv_box.screen_loc = ui_lhand - inv_box.slot_id = slot_l_hand - static_inventory += inv_box + build_hand_slots(ui_style) using = new /obj/screen/swap_hand() using.icon = ui_style using.icon_state = "swap_1" - using.screen_loc = ui_swaphand1 + using.screen_loc = ui_swaphand_position(owner,1) static_inventory += using using = new /obj/screen/swap_hand() using.icon = ui_style using.icon_state = "swap_2" - using.screen_loc = ui_swaphand2 + using.screen_loc = ui_swaphand_position(owner,2) static_inventory += using inv_box = new /obj/screen/inventory() @@ -227,7 +213,7 @@ using = new /obj/screen/human/equip() using.icon = ui_style - using.screen_loc = ui_equip + using.screen_loc = ui_equip_position(mymob) static_inventory += using inv_box = new /obj/screen/inventory() @@ -407,17 +393,13 @@ screenmob.client.screen -= H.r_store if(hud_version != HUD_STYLE_NOHUD) - if(H.r_hand) - H.r_hand.screen_loc = ui_rhand - screenmob.client.screen += H.r_hand - if(H.l_hand) - H.l_hand.screen_loc = ui_lhand - screenmob.client.screen += H.l_hand + for(var/obj/item/I in H.held_items) + I.screen_loc = ui_hand_position(H.get_held_index_of_item(I)) + H.client.screen += I else - if(H.r_hand) - screenmob.client.screen -= H.r_hand - if(H.l_hand) - screenmob.client.screen -= H.l_hand + for(var/obj/item/I in H.held_items) + I.screen_loc = null + H.client.screen -= I /mob/living/carbon/human/verb/toggle_hotkey_verbs() set category = "OOC" diff --git a/code/_onclick/hud/monkey.dm b/code/_onclick/hud/monkey.dm index b7d8437e02a..dd6ec4bef44 100644 --- a/code/_onclick/hud/monkey.dm +++ b/code/_onclick/hud/monkey.dm @@ -21,32 +21,18 @@ using.screen_loc = ui_drop_throw static_inventory += using - inv_box = new /obj/screen/inventory/hand() - inv_box.name = "right hand" - inv_box.icon = ui_style - inv_box.icon_state = "hand_r" - inv_box.screen_loc = ui_rhand - inv_box.slot_id = slot_r_hand - static_inventory += inv_box - - inv_box = new /obj/screen/inventory/hand() - inv_box.name = "left hand" - inv_box.icon = ui_style - inv_box.icon_state = "hand_l" - inv_box.screen_loc = ui_lhand - inv_box.slot_id = slot_l_hand - static_inventory += inv_box + build_hand_slots(ui_style) using = new /obj/screen/swap_hand() using.icon = ui_style using.icon_state = "swap_1_m" //extra wide! - using.screen_loc = ui_swaphand1 + using.screen_loc = ui_swaphand_position(owner,1) static_inventory += using using = new /obj/screen/swap_hand() using.icon = ui_style using.icon_state = "swap_2" - using.screen_loc = ui_swaphand2 + using.screen_loc = ui_swaphand_position(owner,2) static_inventory += using inv_box = new /obj/screen/inventory() @@ -142,17 +128,13 @@ M.head.screen_loc = null if(hud_version != HUD_STYLE_NOHUD) - if(M.r_hand) - M.r_hand.screen_loc = ui_rhand - M.client.screen += M.r_hand - if(M.l_hand) - M.l_hand.screen_loc = ui_lhand - M.client.screen += M.l_hand + for(var/obj/item/I in M.held_items) + I.screen_loc = ui_hand_position(M.get_held_index_of_item(I)) + M.client.screen += I else - if(M.r_hand) - M.r_hand.screen_loc = null - if(M.l_hand) - M.l_hand.screen_loc = null + for(var/obj/item/I in M.held_items) + I.screen_loc = null + M.client.screen -= I /mob/living/carbon/monkey/create_mob_hud() if(client && !hud_used) diff --git a/code/_onclick/hud/robot.dm b/code/_onclick/hud/robot.dm index f572172bb60..aaf740f479e 100644 --- a/code/_onclick/hud/robot.dm +++ b/code/_onclick/hud/robot.dm @@ -153,9 +153,9 @@ infodisplay += healths //Installed Module - mymob.hands = new /obj/screen/robot/module() - mymob.hands.screen_loc = ui_borg_module - static_inventory += mymob.hands + mymobR.hands = new /obj/screen/robot/module() + mymobR.hands.screen_loc = ui_borg_module + static_inventory += mymobR.hands //Store module_store_icon = new /obj/screen/robot/store() diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index 529a5c11ad1..cb9c698efaf 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -90,8 +90,7 @@ if (istype(usr.loc,/obj/mecha)) // stops inventory actions in a mech return 1 if(usr.attack_ui(slot_id)) - usr.update_inv_l_hand(0) - usr.update_inv_r_hand(0) + usr.update_inv_hands() return 1 /obj/screen/inventory/update_icon() @@ -108,13 +107,15 @@ var/image/active_overlay var/image/handcuff_overlay var/image/blocked_overlay + var/held_index = 0 /obj/screen/inventory/hand/update_icon() ..() + if(!active_overlay) active_overlay = image("icon"=icon, "icon_state"="hand_active") if(!handcuff_overlay) - var/state = (slot_id == slot_r_hand) ? "markus" : "gabrielle" + var/state = (!(held_index % 2)) ? "markus" : "gabrielle" handcuff_overlay = image("icon"='icons/mob/screen_gen.dmi', "icon_state"=state) if(!blocked_overlay) blocked_overlay = image("icon"='icons/mob/screen_gen.dmi', "icon_state"="blocked") @@ -126,18 +127,15 @@ var/mob/living/carbon/C = hud.mymob if(C.handcuffed) add_overlay(handcuff_overlay) - if(slot_id == slot_r_hand) - if(!C.has_right_hand()) - add_overlay(blocked_overlay) - else if(slot_id == slot_l_hand) - if(!C.has_left_hand()) + + if(held_index) + if(!C.has_hand_for_held_index(held_index)) add_overlay(blocked_overlay) - if(slot_id == slot_l_hand && hud.mymob.hand) - add_overlay(active_overlay) - else if(slot_id == slot_r_hand && !hud.mymob.hand) + if(held_index == hud.mymob.active_hand_index) add_overlay(active_overlay) + /obj/screen/inventory/hand/Click() // At this point in client Click() code we have passed the 1/10 sec check and little else // We don't even know if it's a middle click @@ -150,11 +148,7 @@ if(ismob(usr)) var/mob/M = usr - switch(name) - if("right hand", "r_hand") - M.activate_hand("r") - if("left hand", "l_hand") - M.activate_hand("l") + M.swap_hand(held_index) return 1 /obj/screen/close @@ -239,12 +233,10 @@ C << "You are not wearing an internals mask!" return - if(istype(C.l_hand, /obj/item/weapon/tank)) - C << "You are now running on internals from the [C.l_hand] on your left hand." - C.internal = C.l_hand - else if(istype(C.r_hand, /obj/item/weapon/tank)) - C << "You are now running on internals from the [C.r_hand] on your right hand." - C.internal = C.r_hand + var/obj/item/I = C.is_holding_item_of_type(/obj/item/weapon/tank) + if(I) + C << "You are now running on internals from the [I] on your [C.get_held_index_name(C.get_held_index_of_item(I))]." + C.internal = I else if(ishuman(C)) var/mob/living/carbon/human/H = C if(istype(H.s_store, /obj/item/weapon/tank)) @@ -328,7 +320,7 @@ if (istype(usr.loc,/obj/mecha)) // stops inventory actions in a mech return 1 if(master) - var/obj/item/I = usr.get_active_hand() + var/obj/item/I = usr.get_active_held_item() if(I) master.attackby(I, usr, params) return 1 diff --git a/code/_onclick/hud/swarmer.dm b/code/_onclick/hud/swarmer.dm index 85ee9c4977f..92a98e14c67 100644 --- a/code/_onclick/hud/swarmer.dm +++ b/code/_onclick/hud/swarmer.dm @@ -68,11 +68,11 @@ var/obj/screen/using using = new /obj/screen/swarmer/FabricateTrap() - using.screen_loc = ui_rhand + using.screen_loc = ui_hand_position(2) static_inventory += using using = new /obj/screen/swarmer/Barricade() - using.screen_loc = ui_lhand + using.screen_loc = ui_hand_position(1) static_inventory += using using = new /obj/screen/swarmer/Replicate() diff --git a/code/_onclick/telekinesis.dm b/code/_onclick/telekinesis.dm index 9c783dc19ef..dcd14ee9663 100644 --- a/code/_onclick/telekinesis.dm +++ b/code/_onclick/telekinesis.dm @@ -86,7 +86,7 @@ var/const/tk_maxrange = 15 //stops TK grabs being equipped anywhere but into hands /obj/item/tk_grab/equipped(mob/user, slot) - if( (slot == slot_l_hand) || (slot== slot_r_hand) ) + if(slot == slot_hands) return qdel(src) return diff --git a/code/datums/diseases/advance/symptoms/cough.dm b/code/datums/diseases/advance/symptoms/cough.dm index d8bbc5e5ae9..09dd6bf8dc0 100644 --- a/code/datums/diseases/advance/symptoms/cough.dm +++ b/code/datums/diseases/advance/symptoms/cough.dm @@ -34,7 +34,7 @@ BONUS M << "[pick("You swallow excess mucus.", "You lightly cough.")]" else M.emote("cough") - var/obj/item/I = M.get_active_hand() + var/obj/item/I = M.get_active_held_item() if(I && I.w_class == 1) M.drop_item() return \ No newline at end of file diff --git a/code/datums/diseases/wizarditis.dm b/code/datums/diseases/wizarditis.dm index bc9d70fc63c..2e6d2a52cce 100644 --- a/code/datums/diseases/wizarditis.dm +++ b/code/datums/diseases/wizarditis.dm @@ -78,12 +78,9 @@ STI KALY - blind else var/mob/living/carbon/H = affected_mob if(prob(chance)) - if(!istype(H.r_hand, /obj/item/weapon/staff)) - H.drop_r_hand() - H.put_in_r_hand( new /obj/item/weapon/staff(H) ) - return - return - + var/obj/item/weapon/staff/S = new(H) + if(!H.put_in_hands(S)) + qdel(S) /datum/disease/wizarditis/proc/teleport() diff --git a/code/datums/martial.dm b/code/datums/martial.dm index ea41a804136..0a93341a63d 100644 --- a/code/datums/martial.dm +++ b/code/datums/martial.dm @@ -333,8 +333,7 @@ else A.start_pulling(D, 1) if(A.pulling) - D.drop_r_hand() - D.drop_l_hand() + D.drop_all_held_items() D.stop_pulling() add_logs(A, D, "grabbed", addition="aggressively") A.grab_state = GRAB_AGGRESSIVE //Instant aggressive grab diff --git a/code/datums/martial/krav_maga.dm b/code/datums/martial/krav_maga.dm index 1da9d820a76..330ca40d1c5 100644 --- a/code/datums/martial/krav_maga.dm +++ b/code/datums/martial/krav_maga.dm @@ -130,16 +130,10 @@ datum/martial_art/krav_maga/grab_act(var/mob/living/carbon/human/A, var/mob/livi if(check_streak(A,D)) return 1 if(prob(60)) - if(D.hand) - if(istype(D.l_hand, /obj/item)) - var/obj/item/I = D.l_hand - D.drop_item() - A.put_in_hands(I) - else - if(istype(D.r_hand, /obj/item)) - var/obj/item/I = D.r_hand - D.drop_item() - A.put_in_hands(I) + var/obj/item/I = D.get_active_held_item() + if(I) + D.drop_item() + A.put_in_hands(I) D.visible_message("[A] has disarmed [D]!", \ "[A] has disarmed [D]!") playsound(D, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) diff --git a/code/datums/wires/wires.dm b/code/datums/wires/wires.dm index c161690b2b8..bf749e18e5f 100644 --- a/code/datums/wires/wires.dm +++ b/code/datums/wires/wires.dm @@ -310,7 +310,7 @@ var/list/wire_color_directory = list() return var/target_wire = params["wire"] var/mob/living/L = usr - var/obj/item/I = L.get_active_hand() + var/obj/item/I = L.get_active_held_item() switch(action) if("cut") if(istype(I, /obj/item/weapon/wirecutters) || IsAdminGhost(usr)) diff --git a/code/game/gamemodes/antag_spawner.dm b/code/game/gamemodes/antag_spawner.dm index a1d1a7b8551..59cbfc05095 100644 --- a/code/game/gamemodes/antag_spawner.dm +++ b/code/game/gamemodes/antag_spawner.dm @@ -84,7 +84,7 @@ if("healing") M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/charge(null)) M.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/forcewall(null)) - M.equip_to_slot_or_del(new /obj/item/weapon/gun/magic/staff/healing(M), slot_r_hand) + M.put_in_hands_or_del(new /obj/item/weapon/gun/magic/staff/healing(M)) M << "Your service has not gone unrewarded, however. Studying under [usr.real_name], you have learned livesaving survival spells. You are able to cast charge and forcewall." if("robeless") M.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/knock(null)) diff --git a/code/game/gamemodes/changeling/powers/mutations.dm b/code/game/gamemodes/changeling/powers/mutations.dm index 8bb2bf50540..08efd29bbf4 100644 --- a/code/game/gamemodes/changeling/powers/mutations.dm +++ b/code/game/gamemodes/changeling/powers/mutations.dm @@ -21,32 +21,28 @@ var/weapon_name_simple /obj/effect/proc_holder/changeling/weapon/try_to_sting(mob/user, mob/target) - if(check_weapon(user, user.r_hand, 1)) - return - if(check_weapon(user, user.l_hand, 0)) - return + for(var/obj/item/I in user.held_items) + if(check_weapon(user, I)) + return ..(user, target) -/obj/effect/proc_holder/changeling/weapon/proc/check_weapon(mob/user, obj/item/hand_item, right_hand=1) +/obj/effect/proc_holder/changeling/weapon/proc/check_weapon(mob/user, obj/item/hand_item) if(istype(hand_item, weapon_type)) playsound(user, 'sound/effects/blobattack.ogg', 30, 1) qdel(hand_item) user.visible_message("With a sickening crunch, [user] reforms their [weapon_name_simple] into an arm!", "We assimilate the [weapon_name_simple] back into our body.", "The [user.get_active_hand()] is stuck to your hand, you cannot grow a [weapon_name_simple] over it!" + user << "The [user.get_active_held_item()] is stuck to your hand, you cannot grow a [weapon_name_simple] over it!" return var/limb_regen = 0 - if(user.hand) //we regen the arm before changing it into the weapon - limb_regen = user.regenerate_limb("l_arm", 1) - else + if(user.active_hand_index % 2 == 0) //we regen the arm before changing it into the weapon limb_regen = user.regenerate_limb("r_arm", 1) + else + limb_regen = user.regenerate_limb("l_arm", 1) if(limb_regen) user.visible_message("[user]'s missing arm reforms, making a loud, grotesque sound!", "Your arm regrows, making a loud, crunchy sound and giving you great pain!", "You hear organic matter ripping and tearing!") user.emote("scream") @@ -56,8 +52,9 @@ return W /obj/effect/proc_holder/changeling/weapon/on_refund(mob/user) - check_weapon(user, user.r_hand, 1) - check_weapon(user, user.l_hand, 0) + for(var/obj/item/I in user.held_items) + check_weapon(user, I) + //Parent to space suits and armor. /obj/effect/proc_holder/changeling/suit diff --git a/code/game/gamemodes/changeling/powers/tiny_prick.dm b/code/game/gamemodes/changeling/powers/tiny_prick.dm index 5deadd09cbf..ea792abe4b3 100644 --- a/code/game/gamemodes/changeling/powers/tiny_prick.dm +++ b/code/game/gamemodes/changeling/powers/tiny_prick.dm @@ -138,7 +138,7 @@ add_logs(user, target, "stung", object="falso armblade sting") if(!target.drop_item()) - user << "The [target.get_active_hand()] is stuck to their hand, you cannot grow a false armblade over it!" + user << "The [target.get_active_held_item()] is stuck to their hand, you cannot grow a false armblade over it!" return if(ismonkey(target)) @@ -162,8 +162,7 @@ "You need to hold the slab in your active hand to recite scripture!" return recite_scripture(user) @@ -236,7 +236,7 @@ var/datum/clockwork_scripture/C = S if("[initial(C.name)] ([initial(C.descname)])" == chosen_scripture) scripture_to_recite = new C - if(!scripture_to_recite || user.get_active_hand() != src) + if(!scripture_to_recite || user.get_active_held_item() != src) return 0 tiers_of_scripture = scripture_unlock_check() if(!ratvar_awakens && !no_cost && !tiers_of_scripture[scripture_to_recite.tier]) @@ -517,7 +517,7 @@ user << "[src] is still gathering power!" return 0 var/mob/living/carbon/C = user - if(C.l_hand && C.r_hand) + if(!user.get_empty_held_indexes()) C << "You require a free hand to utilize [src]'s power!" return 0 C.visible_message("[C]'s hand is enveloped in violet flames!", "You harness [src]'s power. Direct it at a tile at any range to unleash it, or use the action button again to dispel it.") diff --git a/code/game/gamemodes/clock_cult/clock_mobs.dm b/code/game/gamemodes/clock_cult/clock_mobs.dm index 3c9f29bd46a..d8d3025e088 100644 --- a/code/game/gamemodes/clock_cult/clock_mobs.dm +++ b/code/game/gamemodes/clock_cult/clock_mobs.dm @@ -261,7 +261,7 @@ if(amount > 0) combattimer = world.time + initial(combattimer) for(var/mob/living/L in view(2, src)) - if(istype(L.l_hand, /obj/item/weapon/nullrod) || istype(L.r_hand, /obj/item/weapon/nullrod)) //hand-held holy weapons increase the damage it takes + if(L.is_holding_item_of_type(/obj/item/weapon/nullrod)) src << "The presence of a brandished holy artifact weakens your armor!" amount *= 4 //if a wielded null rod is nearby, it takes four times the health damage break diff --git a/code/game/gamemodes/clock_cult/clock_unsorted.dm b/code/game/gamemodes/clock_cult/clock_unsorted.dm index 30a8577dda5..fbc532f2ddc 100644 --- a/code/game/gamemodes/clock_cult/clock_unsorted.dm +++ b/code/game/gamemodes/clock_cult/clock_unsorted.dm @@ -61,7 +61,7 @@ return ..() /datum/action/innate/function_call/Activate() - if(owner.l_hand && owner.r_hand) + if(!owner.get_empty_held_indexes()) usr << "You need an empty to hand to call forth your spear!" return 0 owner.visible_message("A strange spear materializes in [owner]'s hands!", "You call forth your spear!") @@ -114,7 +114,7 @@ return 0 var/input_target_key = input(invoker, "Choose a target to form a rift to.", "Spatial Gateway") as null|anything in possible_targets var/atom/movable/target = possible_targets[input_target_key] - if(!src || !target || !invoker || !invoker.canUseTopic(src, BE_CLOSE) || !is_servant_of_ratvar(invoker) || (istype(src, /obj/item) && invoker.get_active_hand() != src)) + if(!src || !target || !invoker || !invoker.canUseTopic(src, BE_CLOSE) || !is_servant_of_ratvar(invoker) || (istype(src, /obj/item) && invoker.get_active_held_item() != src)) return 0 //if any of the involved things no longer exist, the invoker is stunned, too far away to use the object, or does not serve ratvar, or if the object is an item and not in the mob's active hand, fail var/istargetobelisk = istype(target, /obj/structure/clockwork/powered/clockwork_obelisk) if(istargetobelisk) diff --git a/code/game/gamemodes/cult/cult.dm b/code/game/gamemodes/cult/cult.dm index 6847906410c..2676bc21aea 100644 --- a/code/game/gamemodes/cult/cult.dm +++ b/code/game/gamemodes/cult/cult.dm @@ -139,9 +139,7 @@ var/list/slots = list( "backpack" = slot_in_backpack, "left pocket" = slot_l_store, - "right pocket" = slot_r_store, - "left hand" = slot_l_hand, - "right hand" = slot_r_hand, + "right pocket" = slot_r_store ) var/T = new item_path(mob) diff --git a/code/game/gamemodes/cult/runes.dm b/code/game/gamemodes/cult/runes.dm index 2081eaae4ad..7abb19384ef 100644 --- a/code/game/gamemodes/cult/runes.dm +++ b/code/game/gamemodes/cult/runes.dm @@ -177,7 +177,7 @@ structure_check() searches for nearby cultist structures required for the invoca /mob/proc/bible_check() //The bible, if held, might protect against certain things var/obj/item/weapon/storage/book/bible/B = locate() in src - if(B && (l_hand == B || r_hand == B)) + if(is_holding(B)) return B return 0 diff --git a/code/game/gamemodes/devil/true_devil/_true_devil.dm b/code/game/gamemodes/devil/true_devil/_true_devil.dm index a99c95801d1..8e91c964dab 100644 --- a/code/game/gamemodes/devil/true_devil/_true_devil.dm +++ b/code/game/gamemodes/devil/true_devil/_true_devil.dm @@ -51,8 +51,7 @@ /mob/living/carbon/true_devil/death(gibbed) stat = DEAD ..(gibbed) - drop_l_hand() - drop_r_hand() + drop_all_held_items() spawn (0) mind.devilinfo.beginResurrectionCheck(src) @@ -61,18 +60,12 @@ var/msg = "*---------*\nThis is \icon[src] [src]!\n" //Left hand items - if(l_hand && !(l_hand.flags&ABSTRACT)) - if(l_hand.blood_DNA) - msg += "It is holding \icon[l_hand] [l_hand.gender==PLURAL?"some":"a"] blood-stained [l_hand.name] in its left hand!\n" - else - msg += "It is holding \icon[l_hand] \a [l_hand] in its left hand.\n" - - //Right hand items - if(r_hand && !(r_hand.flags&ABSTRACT)) - if(r_hand.blood_DNA) - msg += "It is holding \icon[r_hand] [r_hand.gender==PLURAL?"some":"a"] blood-stained [r_hand.name] in its right hand!\n" - else - msg += "It is holding \icon[r_hand] \a [r_hand] in its right hand.\n" + for(var/obj/item/I in held_items) + if(!(I.flags & ABSTRACT)) + if(I.blood_DNA) + msg += "It is holding \icon[I] [I.gender==PLURAL?"some":"a"] blood-stained [I.name] in its [get_held_index_name(get_held_index_of_item(I))]!\n" + else + msg += "It is holding \icon[I] \a [I] in its [get_held_index_name(get_held_index_of_item(I))].\n" //Braindead if(!client && stat != DEAD) diff --git a/code/game/gamemodes/devil/true_devil/inventory.dm b/code/game/gamemodes/devil/true_devil/inventory.dm index 020d48c98de..ca417e09fbf 100644 --- a/code/game/gamemodes/devil/true_devil/inventory.dm +++ b/code/game/gamemodes/devil/true_devil/inventory.dm @@ -4,10 +4,12 @@ return 1 return 0 -/mob/living/carbon/true_devil/proc/update_inv_hands() +/mob/living/carbon/true_devil/update_inv_hands() //TODO LORDPIDEY: Figure out how to make the hands line up properly. the l/r_hand_image should use the down sprite when facing down, left, or right, and the up sprite when facing up. remove_overlay(DEVIL_HANDS_LAYER) var/list/hands_overlays = list() + var/obj/item/l_hand = get_item_for_held_index(1) //hardcoded 2-hands only, for now. + var/obj/item/r_hand = get_item_for_held_index(2) if(r_hand) @@ -21,7 +23,7 @@ if(client && hud_used && hud_used.hud_version != HUD_STYLE_NOHUD) r_hand.layer = ABOVE_HUD_LAYER - r_hand.screen_loc = ui_rhand + r_hand.screen_loc = ui_hand_position(get_held_index_of_item(r_hand)) client.screen |= r_hand if(l_hand) @@ -36,19 +38,12 @@ if(client && hud_used && hud_used.hud_version != HUD_STYLE_NOHUD) l_hand.layer = ABOVE_HUD_LAYER - l_hand.screen_loc = ui_lhand + l_hand.screen_loc = ui_hand_position(get_held_index_of_item(l_hand)) client.screen |= l_hand if(hands_overlays.len) devil_overlays[DEVIL_HANDS_LAYER] = hands_overlays apply_overlay(DEVIL_HANDS_LAYER) -/mob/living/carbon/true_devil/update_inv_l_hand() - update_inv_hands() - - -/mob/living/carbon/true_devil/update_inv_r_hand() - update_inv_hands() - /mob/living/carbon/true_devil/remove_overlay(cache_index) if(devil_overlays[cache_index]) overlays -= devil_overlays[cache_index] diff --git a/code/game/gamemodes/gang/gang.dm b/code/game/gamemodes/gang/gang.dm index 64f0ef08d70..241c16bf56e 100644 --- a/code/game/gamemodes/gang/gang.dm +++ b/code/game/gamemodes/gang/gang.dm @@ -115,9 +115,7 @@ var/list/gang_colors_pool = list("red","orange","yellow","green","blue","purple" var/list/slots = list ( "backpack" = slot_in_backpack, "left pocket" = slot_l_store, - "right pocket" = slot_r_store, - "left hand" = slot_l_hand, - "right hand" = slot_r_hand, + "right pocket" = slot_r_store ) . = 0 diff --git a/code/game/gamemodes/miniantags/abduction/abduction_gear.dm b/code/game/gamemodes/miniantags/abduction/abduction_gear.dm index 20f9b61d014..c2a7423ef01 100644 --- a/code/game/gamemodes/miniantags/abduction/abduction_gear.dm +++ b/code/game/gamemodes/miniantags/abduction/abduction_gear.dm @@ -59,8 +59,7 @@ M.icon = disguise.icon M.icon_state = disguise.icon_state M.overlays = disguise.overlays - M.update_inv_r_hand() - M.update_inv_l_hand() + M.update_inv_hands() /obj/item/clothing/suit/armor/abductor/vest/proc/DeactivateStealth() if(!stealth_active) diff --git a/code/game/gamemodes/miniantags/abduction/machinery/console.dm b/code/game/gamemodes/miniantags/abduction/machinery/console.dm index 55802fa7e17..2aaacb4565f 100644 --- a/code/game/gamemodes/miniantags/abduction/machinery/console.dm +++ b/code/game/gamemodes/miniantags/abduction/machinery/console.dm @@ -173,7 +173,7 @@ entry.name = target.name entry.icon = target.icon entry.icon_state = target.icon_state - entry.overlays = target.get_overlays_copy(list(L_HAND_LAYER,R_HAND_LAYER)) + entry.overlays = target.get_overlays_copy(list(HANDS_LAYER,HANDS_LAYER)) for(var/i=1,i<=disguises.len,i++) var/datum/icon_snapshot/temp = disguises[i] if(temp.name == entry.name) diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm index 1aded1d6205..0270d153573 100644 --- a/code/game/gamemodes/nuclear/nuclear.dm +++ b/code/game/gamemodes/nuclear/nuclear.dm @@ -110,7 +110,7 @@ synd_mind.current << "In your hand you will find a special item capable of triggering a greater challenge for your team. Examine it carefully and consult with your fellow operatives before activating it." var/obj/item/device/nuclear_challenge/challenge = new /obj/item/device/nuclear_challenge - synd_mind.current.equip_to_slot_or_del(challenge, slot_r_hand) + synd_mind.current.put_in_hands_or_del(challenge) var/list/foundIDs = synd_mind.current.search_contents_for(/obj/item/weapon/card/id) if(foundIDs.len) @@ -130,7 +130,7 @@ P.name = "nuclear bomb code" var/mob/living/carbon/human/H = synd_mind.current P.loc = H.loc - H.equip_to_slot_or_del(P, slot_r_hand, 0) + H.put_in_hands_or_del(P) H.update_icons() else nuke_code = "code will be provided later" diff --git a/code/game/gamemodes/nuclear/nuclearbomb.dm b/code/game/gamemodes/nuclear/nuclearbomb.dm index 88aed68a67e..98d0f963433 100644 --- a/code/game/gamemodes/nuclear/nuclearbomb.dm +++ b/code/game/gamemodes/nuclear/nuclearbomb.dm @@ -291,7 +291,7 @@ var/bomb_set . = TRUE if("insert_disk") if(!auth) - var/obj/item/I = usr.get_active_hand() + var/obj/item/I = usr.get_active_held_item() if(istype(I, /obj/item/weapon/disk/nuclear)) usr.drop_item() I.forceMove(src) diff --git a/code/game/gamemodes/revolution/revolution.dm b/code/game/gamemodes/revolution/revolution.dm index a30b1c2f281..9027a95c1ff 100644 --- a/code/game/gamemodes/revolution/revolution.dm +++ b/code/game/gamemodes/revolution/revolution.dm @@ -137,9 +137,7 @@ var/list/slots = list ( "backpack" = slot_in_backpack, "left pocket" = slot_l_store, - "right pocket" = slot_r_store, - "left hand" = slot_l_hand, - "right hand" = slot_r_hand, + "right pocket" = slot_r_store ) var/where = mob.equip_in_one_of_slots(T, slots) var/where2 = mob.equip_in_one_of_slots(C, slots) diff --git a/code/game/gamemodes/traitor/traitor.dm b/code/game/gamemodes/traitor/traitor.dm index a88b2735153..b77bc2894ad 100644 --- a/code/game/gamemodes/traitor/traitor.dm +++ b/code/game/gamemodes/traitor/traitor.dm @@ -367,9 +367,7 @@ var/list/slots = list ( "backpack" = slot_in_backpack, "left pocket" = slot_l_store, - "right pocket" = slot_r_store, - "left hand" = slot_l_hand, - "right hand" = slot_r_hand, + "right pocket" = slot_r_store ) var/where = "At your feet" diff --git a/code/game/gamemodes/wizard/artefact.dm b/code/game/gamemodes/wizard/artefact.dm index 1a41e73ef7c..6d0d742c00e 100644 --- a/code/game/gamemodes/wizard/artefact.dm +++ b/code/game/gamemodes/wizard/artefact.dm @@ -191,8 +191,8 @@ H.equip_to_slot_or_del(new hat(H), slot_head) H.equip_to_slot_or_del(new /obj/item/clothing/under/roman(H), slot_w_uniform) H.equip_to_slot_or_del(new /obj/item/clothing/shoes/roman(H), slot_shoes) - H.equip_to_slot_or_del(new /obj/item/weapon/shield/riot/roman(H), slot_l_hand) - H.equip_to_slot_or_del(new /obj/item/weapon/claymore(H), slot_r_hand) + H.put_in_hands_or_del(new /obj/item/weapon/shield/riot/roman(H)) + H.put_in_hands_or_del(new /obj/item/weapon/claymore(H)) H.equip_to_slot_or_del(new /obj/item/weapon/twohanded/spear(H), slot_back) @@ -337,15 +337,15 @@ var/global/list/multiverse = list() M.equip_to_slot_or_del(new /obj/item/device/radio/headset(M), slot_ears) M.equip_to_slot_or_del(new /obj/item/clothing/glasses/sunglasses(M), slot_glasses) M.equip_to_slot_or_del(new /obj/item/clothing/under/suit_jacket/really_black(M), slot_w_uniform) - M.equip_to_slot_or_del(sword, slot_r_hand) + M.put_in_hands_or_del(sword) if("roman") var/hat = pick(/obj/item/clothing/head/helmet/roman, /obj/item/clothing/head/helmet/roman/legionaire) M.equip_to_slot_or_del(new hat(M), slot_head) M.equip_to_slot_or_del(new /obj/item/clothing/under/roman(M), slot_w_uniform) M.equip_to_slot_or_del(new /obj/item/clothing/shoes/roman(M), slot_shoes) - M.equip_to_slot_or_del(new /obj/item/weapon/shield/riot/roman(M), slot_l_hand) - M.equip_to_slot_or_del(sword, slot_r_hand) + M.put_in_hands_or_del(new /obj/item/weapon/shield/riot/roman(M)) + M.put_in_hands_or_del(sword) if("wizard") M.equip_to_slot_or_del(new /obj/item/clothing/under/color/lightpurple(M), slot_w_uniform) @@ -353,13 +353,13 @@ var/global/list/multiverse = list() M.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal(M), slot_shoes) M.equip_to_slot_or_del(new /obj/item/device/radio/headset(M), slot_ears) M.equip_to_slot_or_del(new /obj/item/clothing/head/wizard/red(M), slot_head) - M.equip_to_slot_or_del(sword, slot_r_hand) + M.put_in_hands_or_del(sword) if("cyborg") for(var/X in M.bodyparts) var/obj/item/bodypart/affecting = X affecting.change_bodypart_status(ORGAN_ROBOTIC) M.equip_to_slot_or_del(new /obj/item/clothing/glasses/thermal/eyepatch(M), slot_glasses) - M.equip_to_slot_or_del(sword, slot_r_hand) + M.put_in_hands_or_del(sword) if("syndicate") M.equip_to_slot_or_del(new /obj/item/clothing/under/syndicate(M), slot_w_uniform) @@ -369,34 +369,34 @@ var/global/list/multiverse = list() M.equip_to_slot_or_del(new /obj/item/device/radio/headset(M), slot_ears) M.equip_to_slot_or_del(new /obj/item/clothing/suit/armor/vest(M), slot_wear_suit) M.equip_to_slot_or_del(new /obj/item/clothing/mask/gas(M),slot_wear_mask) - M.equip_to_slot_or_del(sword, slot_r_hand) + M.put_in_hands_or_del(sword) if("assistant") M.equip_to_slot_or_del(new /obj/item/clothing/under/color/grey(M), slot_w_uniform) M.equip_to_slot_or_del(new /obj/item/device/radio/headset(M), slot_ears) M.equip_to_slot_or_del(new /obj/item/clothing/shoes/sneakers/black(M), slot_shoes) - M.equip_to_slot_or_del(sword, slot_r_hand) + M.put_in_hands_or_del(sword) if("animu") M.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal(M), slot_shoes) M.equip_to_slot_or_del(new /obj/item/device/radio/headset(M), slot_ears) M.equip_to_slot_or_del(new /obj/item/clothing/head/kitty(M), slot_head) M.equip_to_slot_or_del(new /obj/item/clothing/under/schoolgirl/red(M), slot_w_uniform) - M.equip_to_slot_or_del(sword, slot_r_hand) + M.put_in_hands_or_del(sword) if("cultist") M.equip_to_slot_or_del(new /obj/item/clothing/head/culthood/alt(M), slot_head) M.equip_to_slot_or_del(new /obj/item/clothing/suit/cultrobes/alt(M), slot_wear_suit) M.equip_to_slot_or_del(new /obj/item/clothing/shoes/cult(M), slot_shoes) M.equip_to_slot_or_del(new /obj/item/device/radio/headset(M), slot_ears) - M.equip_to_slot_or_del(sword, slot_r_hand) + M.put_in_hands_or_del(sword) if("highlander") M.equip_to_slot_or_del(new /obj/item/clothing/under/kilt(M), slot_w_uniform) M.equip_to_slot_or_del(new /obj/item/device/radio/headset(M), slot_ears) M.equip_to_slot_or_del(new /obj/item/clothing/head/beret(M), slot_head) M.equip_to_slot_or_del(new /obj/item/clothing/shoes/combat(M), slot_shoes) - M.equip_to_slot_or_del(sword, slot_r_hand) + M.put_in_hands_or_del(sword) if("clown") M.equip_to_slot_or_del(new /obj/item/clothing/under/rank/clown(M), slot_w_uniform) @@ -404,7 +404,7 @@ var/global/list/multiverse = list() M.equip_to_slot_or_del(new /obj/item/clothing/shoes/clown_shoes(M), slot_shoes) M.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/clown_hat(M), slot_wear_mask) M.equip_to_slot_or_del(new /obj/item/weapon/bikehorn(M), slot_l_store) - M.equip_to_slot_or_del(sword, slot_r_hand) + M.put_in_hands_or_del(sword) if("killer") M.equip_to_slot_or_del(new /obj/item/clothing/under/overalls(M), slot_w_uniform) @@ -416,7 +416,7 @@ var/global/list/multiverse = list() M.equip_to_slot_or_del(new /obj/item/clothing/suit/apron(M), slot_wear_suit) M.equip_to_slot_or_del(new /obj/item/weapon/kitchen/knife(M), slot_l_store) M.equip_to_slot_or_del(new /obj/item/weapon/scalpel(M), slot_r_store) - M.equip_to_slot_or_del(sword, slot_r_hand) + M.put_in_hands_or_del(sword) for(var/obj/item/carried_item in M.contents) if(!istype(carried_item, /obj/item/weapon/implant)) carried_item.add_mob_blood(M) @@ -427,7 +427,7 @@ var/global/list/multiverse = list() M.equip_to_slot_or_del(new /obj/item/clothing/head/bandana(M), slot_head) M.equip_to_slot_or_del(new /obj/item/clothing/glasses/eyepatch(M), slot_glasses) M.equip_to_slot_or_del(new /obj/item/device/radio/headset(M), slot_ears) - M.equip_to_slot_or_del(sword, slot_r_hand) + M.put_in_hands_or_del(sword) if("soviet") M.equip_to_slot_or_del(new /obj/item/clothing/head/pirate/captain(M), slot_head) @@ -436,7 +436,7 @@ var/global/list/multiverse = list() M.equip_to_slot_or_del(new /obj/item/device/radio/headset(M), slot_ears) M.equip_to_slot_or_del(new /obj/item/clothing/suit/pirate/captain(M), slot_wear_suit) M.equip_to_slot_or_del(new /obj/item/clothing/under/soviet(M), slot_w_uniform) - M.equip_to_slot_or_del(sword, slot_r_hand) + M.put_in_hands_or_del(sword) if("officer") M.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/space/beret(M), slot_head) @@ -447,14 +447,14 @@ var/global/list/multiverse = list() M.equip_to_slot_or_del(new /obj/item/clothing/suit/jacket/miljacket(M), slot_wear_suit) M.equip_to_slot_or_del(new /obj/item/clothing/under/syndicate(M), slot_w_uniform) M.equip_to_slot_or_del(new /obj/item/clothing/glasses/eyepatch(M), slot_glasses) - M.equip_to_slot_or_del(sword, slot_r_hand) + M.put_in_hands_or_del(sword) if("gladiator") M.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/gladiator(M), slot_head) M.equip_to_slot_or_del(new /obj/item/clothing/under/gladiator(M), slot_w_uniform) M.equip_to_slot_or_del(new /obj/item/device/radio/headset(M), slot_ears) M.equip_to_slot_or_del(new /obj/item/clothing/shoes/sandal(M), slot_shoes) - M.equip_to_slot_or_del(sword, slot_r_hand) + M.put_in_hands_or_del(sword) else diff --git a/code/game/gamemodes/wizard/wizard.dm b/code/game/gamemodes/wizard/wizard.dm index c5d4cba9a86..82ad4e67cc8 100644 --- a/code/game/gamemodes/wizard/wizard.dm +++ b/code/game/gamemodes/wizard/wizard.dm @@ -137,7 +137,9 @@ qdel(wizard_mob.wear_suit) qdel(wizard_mob.head) qdel(wizard_mob.shoes) - qdel(wizard_mob.r_hand) + for(var/obj/item/I in wizard_mob.held_items) + wizard_mob.unEquip(I) + qdel(I) qdel(wizard_mob.r_store) qdel(wizard_mob.l_store) @@ -152,7 +154,7 @@ wizard_mob.equip_to_slot_or_del(new /obj/item/weapon/teleportation_scroll(wizard_mob), slot_r_store) var/obj/item/weapon/spellbook/spellbook = new /obj/item/weapon/spellbook(wizard_mob) spellbook.owner = wizard_mob - wizard_mob.equip_to_slot_or_del(spellbook, slot_r_hand) + wizard_mob.put_in_hands_or_del(spellbook) wizard_mob << "You will find a list of available spells in your spell book. Choose your magic arsenal carefully." wizard_mob << "The spellbook is bound to you, and others cannot use it." diff --git a/code/game/machinery/PDApainter.dm b/code/game/machinery/PDApainter.dm index 1de445383b1..fd21d4a3826 100644 --- a/code/game/machinery/PDApainter.dm +++ b/code/game/machinery/PDApainter.dm @@ -51,7 +51,7 @@ user << "There is already a PDA inside!" return else - var/obj/item/device/pda/P = user.get_active_hand() + var/obj/item/device/pda/P = user.get_active_held_item() if(istype(P)) if(!user.drop_item()) return diff --git a/code/game/machinery/computer/card.dm b/code/game/machinery/computer/card.dm index 3413b500502..ba4fbd860ee 100644 --- a/code/game/machinery/computer/card.dm +++ b/code/game/machinery/computer/card.dm @@ -315,7 +315,7 @@ var/time_last_changed_position = 0 region_access = null head_subordinates = null else - var/obj/item/I = usr.get_active_hand() + var/obj/item/I = usr.get_active_held_item() if (istype(I, /obj/item/weapon/card/id)) if(!usr.drop_item()) return @@ -329,7 +329,7 @@ var/time_last_changed_position = 0 scan.verb_pickup() scan = null else - var/obj/item/I = usr.get_active_hand() + var/obj/item/I = usr.get_active_held_item() if (istype(I, /obj/item/weapon/card/id)) if(!usr.drop_item()) return diff --git a/code/game/machinery/computer/cloning.dm b/code/game/machinery/computer/cloning.dm index 4641811b75a..0ad5c1ef21e 100644 --- a/code/game/machinery/computer/cloning.dm +++ b/code/game/machinery/computer/cloning.dm @@ -270,7 +270,7 @@ src.menu = 4 else if (src.menu == 4) - var/obj/item/weapon/card/id/C = usr.get_active_hand() + var/obj/item/weapon/card/id/C = usr.get_active_held_item() if (istype(C)||istype(C, /obj/item/device/pda)) if(src.check_access(C)) src.temp = "[src.active_record.fields["name"]] => Record deleted." diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index e55635d45e2..8713750077a 100644 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -64,7 +64,7 @@ var/const/CALL_SHUTTLE_REASON_LENGTH = 12 src.state = STATE_DEFAULT if("login") var/mob/M = usr - var/obj/item/weapon/card/id/I = M.get_active_hand() + var/obj/item/weapon/card/id/I = M.get_active_held_item() if (istype(I, /obj/item/device/pda)) var/obj/item/device/pda/pda = I I = pda.id @@ -82,7 +82,7 @@ var/const/CALL_SHUTTLE_REASON_LENGTH = 12 if("swipeidseclevel") var/mob/M = usr - var/obj/item/weapon/card/id/I = M.get_active_hand() + var/obj/item/weapon/card/id/I = M.get_active_held_item() if (istype(I, /obj/item/device/pda)) var/obj/item/device/pda/pda = I I = pda.id diff --git a/code/game/machinery/computer/gulag_teleporter.dm b/code/game/machinery/computer/gulag_teleporter.dm index 62e3bf6e75e..6f2e6b0d56b 100644 --- a/code/game/machinery/computer/gulag_teleporter.dm +++ b/code/game/machinery/computer/gulag_teleporter.dm @@ -91,14 +91,14 @@ beacon = findbeacon() if("handle_id") if(id) - if(!usr.get_active_hand()) + if(!usr.get_active_held_item()) usr.put_in_hands(id) id = null else id.forceMove(get_turf(src)) id = null else - var/obj/item/I = usr.get_active_hand() + var/obj/item/I = usr.get_active_held_item() if(istype(I, /obj/item/weapon/card/id/prisoner)) if(!usr.drop_item()) return diff --git a/code/game/machinery/computer/medical.dm b/code/game/machinery/computer/medical.dm index 9b816e672f2..62c7230851b 100644 --- a/code/game/machinery/computer/medical.dm +++ b/code/game/machinery/computer/medical.dm @@ -212,13 +212,13 @@ src.temp = null if(href_list["scan"]) if(src.scan) - if(istype(usr,/mob/living/carbon/human) && !usr.get_active_hand()) + if(istype(usr,/mob/living/carbon/human) && !usr.get_active_held_item()) usr.put_in_hands(scan) else scan.loc = get_turf(src) src.scan = null else - var/obj/item/I = usr.get_active_hand() + var/obj/item/I = usr.get_active_held_item() if(istype(I, /obj/item/weapon/card/id)) if(!usr.drop_item()) return diff --git a/code/game/machinery/computer/prisoner.dm b/code/game/machinery/computer/prisoner.dm index 8a837a5af5a..8502e90f4f5 100644 --- a/code/game/machinery/computer/prisoner.dm +++ b/code/game/machinery/computer/prisoner.dm @@ -93,7 +93,7 @@ if(href_list["id"]) if(href_list["id"] =="insert" && !inserted_id) - var/obj/item/weapon/card/id/prisoner/I = usr.get_active_hand() + var/obj/item/weapon/card/id/prisoner/I = usr.get_active_held_item() if(istype(I)) if(!usr.drop_item()) return diff --git a/code/game/machinery/computer/security.dm b/code/game/machinery/computer/security.dm index eaebcd0ac80..d1b5a3e5baa 100644 --- a/code/game/machinery/computer/security.dm +++ b/code/game/machinery/computer/security.dm @@ -295,13 +295,13 @@ What a mess.*/ if("Confirm Identity") if(scan) - if(istype(usr,/mob/living/carbon/human) && !usr.get_active_hand()) + if(istype(usr,/mob/living/carbon/human) && !usr.get_active_held_item()) usr.put_in_hands(scan) else scan.loc = get_turf(src) scan = null else - var/obj/item/I = usr.get_active_hand() + var/obj/item/I = usr.get_active_held_item() if(istype(I, /obj/item/weapon/card/id)) if(!usr.drop_item()) return @@ -740,8 +740,8 @@ What a mess.*/ if(selection) P = new() P.photocreate(selection.fields["icon"], selection.fields["img"], selection.fields["desc"]) - else if(istype(user.get_active_hand(), /obj/item/weapon/photo)) - P = user.get_active_hand() + else if(istype(user.get_active_held_item(), /obj/item/weapon/photo)) + P = user.get_active_held_item() return P /obj/machinery/computer/secure_data/emp_act(severity) diff --git a/code/game/machinery/computer/telecrystalconsoles.dm b/code/game/machinery/computer/telecrystalconsoles.dm index dd535921ff4..abba2eb90ce 100644 --- a/code/game/machinery/computer/telecrystalconsoles.dm +++ b/code/game/machinery/computer/telecrystalconsoles.dm @@ -34,7 +34,7 @@ var/list/possible_uplinker_IDs = list("Alfa","Bravo","Charlie","Delta","Echo","F user << "The [src] already has an uplink in it." return if(O.hidden_uplink) - var/obj/item/I = user.get_active_hand() + var/obj/item/I = user.get_active_held_item() if(!user.drop_item()) return uplinkholder = I diff --git a/code/game/machinery/gulag_item_reclaimer.dm b/code/game/machinery/gulag_item_reclaimer.dm index 47dbfd4e80b..cedab21e73e 100644 --- a/code/game/machinery/gulag_item_reclaimer.dm +++ b/code/game/machinery/gulag_item_reclaimer.dm @@ -81,14 +81,14 @@ switch(action) if("handle_id") if(inserted_id) - if(!usr.get_active_hand()) + if(!usr.get_active_held_item()) usr.put_in_hands(inserted_id) inserted_id = null else inserted_id.forceMove(get_turf(src)) inserted_id = null else - var/obj/item/I = usr.get_active_hand() + var/obj/item/I = usr.get_active_held_item() if(istype(I, /obj/item/weapon/card/id/prisoner)) if(!usr.drop_item()) return diff --git a/code/game/machinery/newscaster.dm b/code/game/machinery/newscaster.dm index 359893bdbb6..bf6a43b8d6c 100644 --- a/code/game/machinery/newscaster.dm +++ b/code/game/machinery/newscaster.dm @@ -791,8 +791,8 @@ var/list/obj/machinery/newscaster/allCasters = list() else qdel(photo) photo = null - if(istype(user.get_active_hand(), /obj/item/weapon/photo)) - photo = user.get_active_hand() + if(istype(user.get_active_held_item(), /obj/item/weapon/photo)) + photo = user.get_active_held_item() if(!user.drop_item()) return photo.loc = src diff --git a/code/game/machinery/porta_turret/portable_turret.dm b/code/game/machinery/porta_turret/portable_turret.dm index c76ef4b40ef..e482fa45c3f 100644 --- a/code/game/machinery/porta_turret/portable_turret.dm +++ b/code/game/machinery/porta_turret/portable_turret.dm @@ -548,10 +548,7 @@ if(allowed(perp) && !lasercolor) //if the perp has security access, return 0 return 0 - if((istype(perp.l_hand, /obj/item/weapon/gun) && !istype(perp.l_hand, /obj/item/weapon/gun/projectile/revolver/doublebarrel)) || istype(perp.l_hand, /obj/item/weapon/melee/baton)) - threatcount += 4 - - if((istype(perp.r_hand, /obj/item/weapon/gun) && !istype(perp.r_hand, /obj/item/weapon/gun/projectile/revolver/doublebarrel)) || istype(perp.r_hand, /obj/item/weapon/melee/baton)) + if(perp.is_holding_item_of_type(/obj/item/weapon/gun) || perp.is_holding_item_of_type(/obj/item/weapon/melee/baton)) threatcount += 4 if(istype(perp.belt, /obj/item/weapon/gun) || istype(perp.belt, /obj/item/weapon/melee/baton)) @@ -561,7 +558,7 @@ threatcount = 0 //But does not target anyone else if(istype(perp.wear_suit, /obj/item/clothing/suit/redtag)) threatcount += 4 - if(istype(perp.r_hand,/obj/item/weapon/gun/energy/laser/redtag) || istype(perp.l_hand,/obj/item/weapon/gun/energy/laser/redtag)) + if(perp.is_holding_item_of_type(/obj/item/weapon/gun/energy/laser/redtag)) threatcount += 4 if(istype(perp.belt, /obj/item/weapon/gun/energy/laser/redtag)) threatcount += 2 @@ -570,7 +567,7 @@ threatcount = 0 if(istype(perp.wear_suit, /obj/item/clothing/suit/bluetag)) threatcount += 4 - if((istype(perp.r_hand,/obj/item/weapon/gun/energy/laser/bluetag)) || (istype(perp.l_hand,/obj/item/weapon/gun/energy/laser/bluetag))) + if(perp.is_holding_item_of_type(/obj/item/weapon/gun/energy/laser/bluetag)) threatcount += 4 if(istype(perp.belt, /obj/item/weapon/gun/energy/laser/bluetag)) threatcount += 2 diff --git a/code/game/machinery/spaceheater.dm b/code/game/machinery/spaceheater.dm index 4c930c8326a..4f2ab34d4cb 100644 --- a/code/game/machinery/spaceheater.dm +++ b/code/game/machinery/spaceheater.dm @@ -147,7 +147,7 @@ return else // insert cell - var/obj/item/weapon/stock_parts/cell/C = usr.get_active_hand() + var/obj/item/weapon/stock_parts/cell/C = usr.get_active_held_item() if(istype(C)) if(!user.drop_item()) return diff --git a/code/game/machinery/telecomms/machine_interactions.dm b/code/game/machinery/telecomms/machine_interactions.dm index fcc819ba72a..90986ffcdff 100644 --- a/code/game/machinery/telecomms/machine_interactions.dm +++ b/code/game/machinery/telecomms/machine_interactions.dm @@ -44,7 +44,7 @@ // You need a multitool to use this, or be silicon if(!issilicon(user)) // istype returns false if the value is null - if(!istype(user.get_active_hand(), /obj/item/device/multitool)) + if(!istype(user.get_active_held_item(), /obj/item/device/multitool)) return if(stat & (BROKEN|NOPOWER)) @@ -133,14 +133,14 @@ var/obj/item/device/multitool/P = null // Let's double check - if(!issilicon(user) && istype(user.get_active_hand(), /obj/item/device/multitool)) - P = user.get_active_hand() + if(!issilicon(user) && istype(user.get_active_held_item(), /obj/item/device/multitool)) + P = user.get_active_held_item() else if(isAI(user)) var/mob/living/silicon/ai/U = user P = U.aiMulti else if(isrobot(user) && in_range(user, src)) - if(istype(user.get_active_hand(), /obj/item/device/multitool)) - P = user.get_active_hand() + if(istype(user.get_active_held_item(), /obj/item/device/multitool)) + P = user.get_active_held_item() return P // Additional Options for certain machines. Use this when you want to add an option to a specific machine. @@ -209,7 +209,7 @@ return if(!issilicon(usr)) - if(!istype(usr.get_active_hand(), /obj/item/device/multitool)) + if(!istype(usr.get_active_held_item(), /obj/item/device/multitool)) return var/obj/item/device/multitool/P = get_multitool(usr) diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm index cbe9df81329..95e8c2d397c 100644 --- a/code/game/machinery/vending.dm +++ b/code/game/machinery/vending.dm @@ -426,7 +426,7 @@ return coin.loc = loc - if(!usr.get_active_hand()) + if(!usr.get_active_held_item()) usr.put_in_hands(coin) usr << "You remove [coin] from [src]." coin = null diff --git a/code/game/objects/effects/mines.dm b/code/game/objects/effects/mines.dm index 9c69cce7fbe..eef512c6f04 100644 --- a/code/game/objects/effects/mines.dm +++ b/code/game/objects/effects/mines.dm @@ -130,8 +130,7 @@ var/obj/item/weapon/twohanded/required/chainsaw/doomslayer/chainsaw = new(victim.loc) chainsaw.flags |= NODROP - victim.drop_r_hand() - victim.drop_l_hand() + victim.drop_all_held_items() victim.put_in_hands(chainsaw) chainsaw.attack_self(victim) chainsaw.wield(victim) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 13e9444175c..a4b4e625832 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -229,7 +229,7 @@ var/global/image/fire_overlay = image("icon" = 'icons/effects/fire.dmi', "icon_s user << "You put out the fire on [src]." else user << "You burn your hand on [src]!" - var/obj/item/bodypart/affecting = H.get_bodypart("[user.hand ? "l" : "r" ]_arm") + 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() @@ -367,7 +367,7 @@ obj/item/proc/item_action_slot_check(slot, mob/user) if(usr.incapacitated() || !Adjacent(usr) || usr.lying) return - if(usr.get_active_hand() == null) // Let me know if this has any problems -Yota + if(usr.get_active_held_item() == null) // Let me know if this has any problems -Yota usr.UnarmedAttack(src) //This proc is executed when someone clicks the on-screen UI button. @@ -545,11 +545,7 @@ obj/item/proc/item_action_slot_check(slot, mob/user) if(ismob(location)) var/mob/M = location var/success = FALSE - if(src == M.get_item_by_slot(slot_l_hand)) - success = TRUE - else if(src == M.get_item_by_slot(slot_r_hand)) - success = TRUE - else if(src == M.get_item_by_slot(slot_wear_mask)) + if(src == M.get_item_by_slot(slot_wear_mask)) success = TRUE if(success) location = get_turf(M) diff --git a/code/game/objects/items/bodybag.dm b/code/game/objects/items/bodybag.dm index 3edc3ea2f25..4a8412696f8 100644 --- a/code/game/objects/items/bodybag.dm +++ b/code/game/objects/items/bodybag.dm @@ -41,7 +41,7 @@ /obj/structure/closet/body_bag/attackby(obj/item/I, mob/user, params) if (istype(I, /obj/item/weapon/pen) || istype(I, /obj/item/toy/crayon)) var/t = stripped_input(user, "What would you like the label to be?", name, null, 53) - if(user.get_active_hand() != I) + if(user.get_active_held_item() != I) return if(!in_range(src, user) && loc != user) return diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index a1ded3061aa..b7ce1e4a737 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -708,7 +708,7 @@ var/global/list/obj/item/device/pda/PDAs = list() if(O) if (istype(loc, /mob)) var/mob/M = loc - if(M.get_active_hand() == null) + if(M.get_active_held_item() == null) M.put_in_hands(O) usr << "You remove \the [O] from \the [src]." return @@ -721,14 +721,14 @@ var/global/list/obj/item/device/pda/PDAs = list() if (id) remove_id() else - var/obj/item/I = user.get_active_hand() + var/obj/item/I = user.get_active_held_item() if (istype(I, /obj/item/weapon/card/id)) if(!user.unEquip(I)) return 0 I.loc = src id = I else - var/obj/item/weapon/card/I = user.get_active_hand() + var/obj/item/weapon/card/I = user.get_active_held_item() if (istype(I, /obj/item/weapon/card/id) && I:registered_name) if(!user.unEquip(I)) return 0 diff --git a/code/game/objects/items/devices/taperecorder.dm b/code/game/objects/items/devices/taperecorder.dm index 2c61dff29a3..605caa32cd0 100644 --- a/code/game/objects/items/devices/taperecorder.dm +++ b/code/game/objects/items/devices/taperecorder.dm @@ -54,7 +54,7 @@ /obj/item/device/taperecorder/attack_hand(mob/user) if(loc == user) if(mytape) - if(user.l_hand != src && user.r_hand != src) + if(!user.is_holding(src)) ..() return eject(user) diff --git a/code/game/objects/items/latexballoon.dm b/code/game/objects/items/latexballoon.dm index 3950e17d5fa..5eba01086ed 100644 --- a/code/game/objects/items/latexballoon.dm +++ b/code/game/objects/items/latexballoon.dm @@ -16,8 +16,7 @@ return icon_state = "latexballon_blow" item_state = "latexballon" - user.update_inv_r_hand() - user.update_inv_l_hand() + user.update_inv_hands() user << "You blow up [src] with [tank]." air_contents = tank.remove_air_volume(3) @@ -29,8 +28,7 @@ item_state = "lgloves" if(istype(src.loc, /mob/living)) var/mob/living/user = src.loc - user.update_inv_r_hand() - user.update_inv_l_hand() + user.update_inv_hands() loc.assume_air(air_contents) /obj/item/latexballon/ex_act(severity, target) diff --git a/code/game/objects/items/robot/robot_parts.dm b/code/game/objects/items/robot/robot_parts.dm index b29313d8374..d133a66b612 100644 --- a/code/game/objects/items/robot/robot_parts.dm +++ b/code/game/objects/items/robot/robot_parts.dm @@ -107,7 +107,7 @@ var/obj/item/weapon/ed209_assembly/B = new /obj/item/weapon/ed209_assembly B.loc = get_turf(src) user << "You arm the robot frame." - if (user.get_inactive_hand()==src) + if (user.get_inactive_held_item()==src) user.unEquip(src) user.put_in_inactive_hand(B) qdel(src) @@ -300,7 +300,7 @@ return var/mob/living/living_user = usr - var/obj/item/item_in_hand = living_user.get_active_hand() + var/obj/item/item_in_hand = living_user.get_active_held_item() if(!istype(item_in_hand, /obj/item/device/multitool)) living_user << "You need a multitool!" return diff --git a/code/game/objects/items/stacks/rods.dm b/code/game/objects/items/stacks/rods.dm index b88420836fd..15c576c6335 100644 --- a/code/game/objects/items/stacks/rods.dm +++ b/code/game/objects/items/stacks/rods.dm @@ -49,7 +49,7 @@ var/global/list/datum/stack_recipe/rod_recipes = list ( \ "You hear welding.") var/obj/item/stack/rods/R = src src = null - var/replace = (user.get_inactive_hand()==R) + var/replace = (user.get_inactive_held_item()==R) R.use(2) if (!R && replace) user.put_in_hands(new_item) diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm index 8a7f6b89919..1fd3e766c62 100644 --- a/code/game/objects/items/stacks/sheets/glass.dm +++ b/code/game/objects/items/stacks/sheets/glass.dm @@ -46,7 +46,7 @@ RG.add_fingerprint(user) var/obj/item/stack/sheet/glass/G = src src = null - var/replace = (user.get_inactive_hand()==G) + var/replace = (user.get_inactive_held_item()==G) V.use(1) G.use(1) if (!G && replace) @@ -316,7 +316,7 @@ 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.hand ? "l_" : "r_") + "arm" + 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) diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index 32c6709676d..9f742a68855 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -111,7 +111,7 @@ /obj/item/stack/Topic(href, href_list) ..() - if (usr.restrained() || usr.stat || (usr.get_active_hand() != src && usr.get_inactive_hand() != src)) + if (usr.restrained() || usr.stat || !usr.is_holding(src)) return if (href_list["make"]) if (src.get_amount() < 1) qdel(src) //Never should happen @@ -222,7 +222,7 @@ return ..() /obj/item/stack/attack_hand(mob/user) - if (user.get_inactive_hand() == src) + if (user.get_inactive_held_item() == src) if(zero_amount()) return change_stack(user,1) diff --git a/code/game/objects/items/stacks/tiles/tile_types.dm b/code/game/objects/items/stacks/tiles/tile_types.dm index 8d8b89760fe..b44b5a9a7cc 100644 --- a/code/game/objects/items/stacks/tiles/tile_types.dm +++ b/code/game/objects/items/stacks/tiles/tile_types.dm @@ -51,7 +51,7 @@ "You hear welding.") var/obj/item/stack/rods/R = src src = null - var/replace = (user.get_inactive_hand()==R) + var/replace = (user.get_inactive_held_item()==R) R.use(4) if (!R && replace) user.put_in_hands(new_item) @@ -64,7 +64,7 @@ "You hear welding.") var/obj/item/stack/rods/R = src src = null - var/replace = (user.get_inactive_hand()==R) + var/replace = (user.get_inactive_held_item()==R) R.use(4) if (!R && replace) user.put_in_hands(new_item) diff --git a/code/game/objects/items/stacks/wrap.dm b/code/game/objects/items/stacks/wrap.dm index 010498a77d8..dbb750e3018 100644 --- a/code/game/objects/items/stacks/wrap.dm +++ b/code/game/objects/items/stacks/wrap.dm @@ -47,7 +47,7 @@ var/obj/item/I = target if(istype(I, /obj/item/smallDelivery)) return - if(user.r_hand == I || user.l_hand == I) + if(user.is_holding(I)) if(!user.unEquip(I)) return else if(!isturf(I.loc)) diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index c81e8596a99..e2924db1ac9 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -260,12 +260,7 @@ if(active) icon_state = "swordrainbow" - // Updating overlays, copied from welder code. - // I tried calling attack_self twice, which looked cool, except it somehow didn't update the overlays!! - if(user.r_hand == src) - user.update_inv_r_hand(0) - else if(user.l_hand == src) - user.update_inv_l_hand(0) + user.update_inv_hands() else user << "It's already fabulous!" else @@ -777,11 +772,7 @@ var/obj/screen/inventory/hand/H = over_object if(!remove_item_from_storage(M)) M.unEquip(src) - switch(H.slot_id) - if(slot_r_hand) - M.put_in_r_hand(src) - if(slot_l_hand) - M.put_in_l_hand(src) + M.put_in_hand(src, H.held_index) usr << "You pick up the deck." else @@ -822,7 +813,7 @@ var/mob/living/carbon/human/cardUser = usr var/O = src if(href_list["pick"]) - if (cardUser.get_item_by_slot(slot_l_hand) == src || cardUser.get_item_by_slot(slot_r_hand) == src) + if (cardUser.is_holding(src)) var/choice = href_list["pick"] var/obj/item/toy/cards/singlecard/C = new/obj/item/toy/cards/singlecard(cardUser.loc) src.currenthand -= choice @@ -899,7 +890,7 @@ /obj/item/toy/cards/singlecard/examine(mob/user) if(ishuman(user)) var/mob/living/carbon/human/cardUser = user - if(cardUser.get_item_by_slot(slot_l_hand) == src || cardUser.get_item_by_slot(slot_r_hand) == src) + if(cardUser.is_holding(src)) cardUser.visible_message("[cardUser] checks \his card.", "The card reads: [src.cardname]") else cardUser << "You need to have the card in your hand to check it!" diff --git a/code/game/objects/items/weapons/chrono_eraser.dm b/code/game/objects/items/weapons/chrono_eraser.dm index fa1e6f26631..3ef008add20 100644 --- a/code/game/objects/items/weapons/chrono_eraser.dm +++ b/code/game/objects/items/weapons/chrono_eraser.dm @@ -126,7 +126,7 @@ var/obj/item/weapon/gun/energy/chrono_gun/gun = null /obj/item/projectile/energy/chrono_beam/fire() - gun = firer.get_active_hand() + gun = firer.get_active_held_item() if(istype(gun)) return ..() else diff --git a/code/game/objects/items/weapons/cigs_lighters.dm b/code/game/objects/items/weapons/cigs_lighters.dm index 992ebfbcf4f..461d4cc2a33 100644 --- a/code/game/objects/items/weapons/cigs_lighters.dm +++ b/code/game/objects/items/weapons/cigs_lighters.dm @@ -193,8 +193,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM if(ismob(loc)) var/mob/M = loc M.update_inv_wear_mask() - M.update_inv_l_hand() - M.update_inv_r_hand() + M.update_inv_hands() /obj/item/clothing/mask/cigarette/proc/handle_reagents() @@ -472,7 +471,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM icon_state = lit ? "[icon_state]_on" : "[initial(icon_state)]" /obj/item/weapon/lighter/attack_self(mob/living/user) - if(user.r_hand == src || user.l_hand == src) + if(user.is_holding(src)) if(!lit) lit = 1 update_icon() @@ -486,7 +485,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM if(prob(75)) user.visible_message("After a few attempts, [user] manages to light [src].", "After a few attempts, you manage to light [src].") else - var/hitzone = user.r_hand == src ? "r_hand" : "l_hand" + var/hitzone = user.held_index_to_dir(user.active_hand_index) == "r" ? "r_hand" : "l_hand" user.apply_damage(5, BURN, hitzone) user.visible_message("After a few attempts, [user] manages to light [src] - they however burn their finger in the process.", "You burn yourself while lighting the lighter!") diff --git a/code/game/objects/items/weapons/defib.dm b/code/game/objects/items/weapons/defib.dm index 7ef5fffb1dd..07550fb00f8 100644 --- a/code/game/objects/items/weapons/defib.dm +++ b/code/game/objects/items/weapons/defib.dm @@ -94,20 +94,10 @@ var/mob/M = src.loc if(istype(over_object, /obj/screen/inventory/hand)) var/obj/screen/inventory/hand/H = over_object + if(!M.unEquip(src)) + return + M.put_in_hand(src, H.held_index) - switch(H.slot_id) - if(slot_r_hand) - if(M.r_hand) - return - if(!M.unEquip(src)) - return - M.put_in_r_hand(src) - if(slot_l_hand) - if(M.l_hand) - return - if(!M.unEquip(src)) - return - M.put_in_l_hand(src) /obj/item/weapon/defibrillator/attackby(obj/item/weapon/W, mob/user, params) if(W == paddles) @@ -334,7 +324,7 @@ if(!req_defib) return ..() if(user) - var/obj/item/weapon/twohanded/offhand/O = user.get_inactive_hand() + var/obj/item/weapon/twohanded/offhand/O = user.get_inactive_held_item() if(istype(O)) O.unwield() user << "The paddles snap back into the main unit." diff --git a/code/game/objects/items/weapons/explosives.dm b/code/game/objects/items/weapons/explosives.dm index 57a33afa574..d329b466cf3 100644 --- a/code/game/objects/items/weapons/explosives.dm +++ b/code/game/objects/items/weapons/explosives.dm @@ -60,7 +60,7 @@ /obj/item/weapon/c4/attack_self(mob/user) var/newtime = input(usr, "Please set the timer.", "Timer", 10) as num - if(user.get_active_hand() == src) + if(user.get_active_held_item() == src) newtime = Clamp(newtime, 10, 60000) timer = newtime user << "Timer set for [timer] seconds." diff --git a/code/game/objects/items/weapons/flamethrower.dm b/code/game/objects/items/weapons/flamethrower.dm index 9efc0a78ed1..9dbfce86b95 100644 --- a/code/game/objects/items/weapons/flamethrower.dm +++ b/code/game/objects/items/weapons/flamethrower.dm @@ -39,7 +39,7 @@ var/turf/location = loc if(istype(location, /mob/)) var/mob/M = location - if(M.l_hand == src || M.r_hand == src) + if(M.is_holding(src)) location = M.loc if(isturf(location)) //start a fire if possible location.hotspot_expose(700, 2) @@ -62,7 +62,7 @@ /obj/item/weapon/flamethrower/afterattack(atom/target, mob/user, flag) if(flag) return // too close // Make sure our user is still holding us - if(user && user.get_active_hand() == src) + if(user && user.get_active_held_item() == src) var/turf/target_turf = get_turf(target) if(target_turf) var/turflist = getline(user, target_turf) diff --git a/code/game/objects/items/weapons/grenades/plastic.dm b/code/game/objects/items/weapons/grenades/plastic.dm index 3af83500b67..4ec3541ce2f 100644 --- a/code/game/objects/items/weapons/grenades/plastic.dm +++ b/code/game/objects/items/weapons/grenades/plastic.dm @@ -60,7 +60,7 @@ nadeassembly.attack_self(user) return var/newtime = input(usr, "Please set the timer.", "Timer", 10) as num - if(user.get_active_hand() == src) + if(user.get_active_held_item() == src) newtime = Clamp(newtime, 10, 60000) det_time = newtime user << "Timer set for [det_time] seconds." diff --git a/code/game/objects/items/weapons/implants/implantcase.dm b/code/game/objects/items/weapons/implants/implantcase.dm index e7426b2184d..eca8a792f41 100644 --- a/code/game/objects/items/weapons/implants/implantcase.dm +++ b/code/game/objects/items/weapons/implants/implantcase.dm @@ -26,7 +26,7 @@ /obj/item/weapon/implantcase/attackby(obj/item/weapon/W, mob/user, params) if(istype(W, /obj/item/weapon/pen)) var/t = stripped_input(user, "What would you like the label to be?", name, null) - if(user.get_active_hand() != W) + if(user.get_active_held_item() != W) return if(!in_range(src, user) && loc != user) return diff --git a/code/game/objects/items/weapons/implants/implanter.dm b/code/game/objects/items/weapons/implants/implanter.dm index d94709d2a46..f35bc2929dd 100644 --- a/code/game/objects/items/weapons/implants/implanter.dm +++ b/code/game/objects/items/weapons/implants/implanter.dm @@ -42,7 +42,7 @@ /obj/item/weapon/implanter/attackby(obj/item/weapon/W, mob/user, params) if(istype(W, /obj/item/weapon/pen)) var/t = stripped_input(user, "What would you like the label to be?", name, null) - if(user.get_active_hand() != W) + if(user.get_active_held_item() != W) return if(!in_range(src, user) && loc != user) return diff --git a/code/game/objects/items/weapons/implants/implantpad.dm b/code/game/objects/items/weapons/implants/implantpad.dm index 04287893b4f..5b11165fe2d 100644 --- a/code/game/objects/items/weapons/implants/implantpad.dm +++ b/code/game/objects/items/weapons/implants/implantpad.dm @@ -20,7 +20,7 @@ /obj/item/weapon/implantpad/attack_hand(mob/user) - if(case && (user.l_hand == src || user.r_hand == src)) + if(case && user.is_holding(src)) user.put_in_active_hand(case) case.add_fingerprint(user) diff --git a/code/game/objects/items/weapons/melee/energy.dm b/code/game/objects/items/weapons/melee/energy.dm index 0cc98cd62a3..106d91fdd73 100644 --- a/code/game/objects/items/weapons/melee/energy.dm +++ b/code/game/objects/items/weapons/melee/energy.dm @@ -202,12 +202,7 @@ if(active) icon_state = "swordrainbow" - // Updating overlays, copied from welder code. - // I tried calling attack_self twice, which looked cool, except it somehow didn't update the overlays!! - if(user.r_hand == src) - user.update_inv_r_hand(0) - else if(user.l_hand == src) - user.update_inv_l_hand(0) + user.update_inv_hands() else user << "It's already fabulous!" else diff --git a/code/game/objects/items/weapons/paint.dm b/code/game/objects/items/weapons/paint.dm index a62d5d5603f..bab00418b8c 100644 --- a/code/game/objects/items/weapons/paint.dm +++ b/code/game/objects/items/weapons/paint.dm @@ -57,7 +57,7 @@ /obj/item/weapon/paint/anycolor/attack_self(mob/user) var/t1 = input(user, "Please select a color:", "Locking Computer", null) in list( "red", "blue", "green", "yellow", "violet", "black", "white") - if ((user.get_active_hand() != src || user.stat || user.restrained())) + if ((user.get_active_held_item() != src || user.stat || user.restrained())) return switch(t1) if("red") diff --git a/code/game/objects/items/weapons/storage/boxes.dm b/code/game/objects/items/weapons/storage/boxes.dm index 0e6eb3470e7..47306dd27eb 100644 --- a/code/game/objects/items/weapons/storage/boxes.dm +++ b/code/game/objects/items/weapons/storage/boxes.dm @@ -47,8 +47,7 @@ var/obj/item/I = new foldable(get_turf(src)) user.drop_item() user.put_in_hands(I) - user.update_inv_l_hand() - user.update_inv_r_hand() + user.update_inv_hands() qdel(src) /obj/item/weapon/storage/box/attackby(obj/item/W, mob/user, params) diff --git a/code/game/objects/items/weapons/storage/fancy.dm b/code/game/objects/items/weapons/storage/fancy.dm index bce4035beb7..fd8d6395ec5 100644 --- a/code/game/objects/items/weapons/storage/fancy.dm +++ b/code/game/objects/items/weapons/storage/fancy.dm @@ -133,7 +133,7 @@ name = "\improper [name] packet" /obj/item/weapon/storage/fancy/cigarettes/AltClick(mob/user) - if(user.get_active_hand()) + if(user.get_active_held_item()) return for(var/obj/item/weapon/lighter/lighter in src) remove_from_storage(lighter, user.loc) diff --git a/code/game/objects/items/weapons/storage/firstaid.dm b/code/game/objects/items/weapons/storage/firstaid.dm index 582216e817d..1003d6aa62c 100644 --- a/code/game/objects/items/weapons/storage/firstaid.dm +++ b/code/game/objects/items/weapons/storage/firstaid.dm @@ -142,11 +142,7 @@ var/obj/screen/inventory/hand/H = over_object if(!M.unEquip(src)) return - switch(H.slot_id) - if(slot_r_hand) - M.put_in_r_hand(src) - if(slot_l_hand) - M.put_in_l_hand(src) + M.put_in_hand(src,H.held_index) src.add_fingerprint(usr) return if(over_object == usr && in_range(src, usr) || usr.contents.Find(src)) diff --git a/code/game/objects/items/weapons/storage/storage.dm b/code/game/objects/items/weapons/storage/storage.dm index 73869507264..c5a9427244e 100644 --- a/code/game/objects/items/weapons/storage/storage.dm +++ b/code/game/objects/items/weapons/storage/storage.dm @@ -61,11 +61,7 @@ var/obj/screen/inventory/hand/H = over_object if(!M.unEquip(src)) return - switch(H.slot_id) - if(slot_r_hand) - M.put_in_r_hand(src) - if(slot_l_hand) - M.put_in_l_hand(src) + M.put_in_hand(src,H.held_index) add_fingerprint(usr) @@ -75,7 +71,7 @@ var/obj/item/I = O if(iscarbon(user) || isdrone(user)) var/mob/living/L = user - if(!L.incapacitated() && I == L.get_active_hand()) + if(!L.incapacitated() && I == L.get_active_held_item()) if(can_be_inserted(I, 0)) handle_item_insertion(I, 0 , L) @@ -439,11 +435,11 @@ if(ishuman(user)) var/mob/living/carbon/human/H = user - if(H.l_store == src && !H.get_active_hand()) //Prevents opening if it's in a pocket. + if(H.l_store == src && !H.get_active_held_item()) //Prevents opening if it's in a pocket. H.put_in_hands(src) H.l_store = null return - if(H.r_store == src && !H.get_active_hand()) + if(H.r_store == src && !H.get_active_held_item()) H.put_in_hands(src) H.r_store = null return @@ -542,7 +538,7 @@ /obj/item/weapon/storage/attack_self(mob/user) //Clicking on itself will empty it, if it has the verb to do that. - if(user.get_active_hand() == src) + if(user.get_active_held_item() == src) if(verbs.Find(/obj/item/weapon/storage/verb/quick_empty)) quick_empty() diff --git a/code/game/objects/items/weapons/tanks/watertank.dm b/code/game/objects/items/weapons/tanks/watertank.dm index 49cb244c150..86404905456 100644 --- a/code/game/objects/items/weapons/tanks/watertank.dm +++ b/code/game/objects/items/weapons/tanks/watertank.dm @@ -83,19 +83,10 @@ var/mob/M = src.loc if(istype(M) && istype(over_object, /obj/screen/inventory/hand)) var/obj/screen/inventory/hand/H = over_object - switch(H.slot_id) - if(slot_r_hand) - if(M.r_hand) - return - if(!M.unEquip(src)) - return - M.put_in_r_hand(src) - if(slot_l_hand) - if(M.l_hand) - return - if(!M.unEquip(src)) - return - M.put_in_l_hand(src) + if(!M.unEquip(src)) + return + M.put_in_hand(src, H.held_index) + /obj/item/weapon/watertank/attackby(obj/item/W, mob/user, params) if(W == noz) diff --git a/code/game/objects/items/weapons/teleportation.dm b/code/game/objects/items/weapons/teleportation.dm index 010e07df9a7..b0b0e8ac781 100644 --- a/code/game/objects/items/weapons/teleportation.dm +++ b/code/game/objects/items/weapons/teleportation.dm @@ -165,7 +165,7 @@ Frequency: if(turfs.len) L["None (Dangerous)"] = pick(turfs) var/t1 = input(user, "Please select a teleporter to lock in on.", "Hand Teleporter") in L - if (user.get_active_hand() != src || user.incapacitated()) + if (user.get_active_held_item() != src || user.incapacitated()) return if(active_portals >= 3) user.show_message("\The [src] is recharging!") diff --git a/code/game/objects/items/weapons/tools.dm b/code/game/objects/items/weapons/tools.dm index d57c948c746..906af763df6 100644 --- a/code/game/objects/items/weapons/tools.dm +++ b/code/game/objects/items/weapons/tools.dm @@ -363,8 +363,7 @@ //mob icon update if(ismob(loc)) var/mob/M = loc - M.update_inv_r_hand(0) - M.update_inv_l_hand(0) + M.update_inv_hands(0) return 0 return 1 diff --git a/code/game/objects/items/weapons/twohanded.dm b/code/game/objects/items/weapons/twohanded.dm index 544613b54ea..b7b71cf6266 100644 --- a/code/game/objects/items/weapons/twohanded.dm +++ b/code/game/objects/items/weapons/twohanded.dm @@ -49,7 +49,7 @@ user << "You are now carrying the [name] with one hand." if(unwieldsound) playsound(loc, unwieldsound, 50, 1) - var/obj/item/weapon/twohanded/offhand/O = user.get_inactive_hand() + var/obj/item/weapon/twohanded/offhand/O = user.get_inactive_held_item() if(O && istype(O)) O.unwield() return @@ -60,7 +60,7 @@ if(istype(user,/mob/living/carbon/monkey) ) user << "It's too heavy for you to wield fully." return - if(user.get_inactive_hand()) + if(user.get_inactive_held_item()) user << "You need your other hand to be empty!" return if(user.get_num_arms() < 2) @@ -87,7 +87,7 @@ ..() //handles unwielding a twohanded weapon when dropped as well as clearing up the offhand if(user) - var/obj/item/weapon/twohanded/O = user.get_inactive_hand() + var/obj/item/weapon/twohanded/O = user.get_inactive_held_item() if(istype(O)) O.unwield(user) return unwield(user) @@ -135,7 +135,7 @@ return ..() /obj/item/weapon/twohanded/required/attack_hand(mob/user)//Can't even pick it up without both hands empty - var/obj/item/weapon/twohanded/required/H = user.get_inactive_hand() + var/obj/item/weapon/twohanded/required/H = user.get_inactive_held_item() if(get_dist(src,user) > 1) return 0 if(H != null) @@ -147,7 +147,7 @@ /obj/item/weapon/twohanded/required/equipped(mob/user, slot) ..() - if(slot == slot_l_hand || slot == slot_r_hand) + if(slot == slot_hands) wield(user) else unwield(user) @@ -431,9 +431,8 @@ else hitsound = "swing_hit" - if(src == user.get_active_hand()) //update inhands - user.update_inv_l_hand() - user.update_inv_r_hand() + if(src == user.get_active_held_item()) //update inhands + user.update_inv_hands() for(var/X in actions) var/datum/action/A = X A.UpdateButtonIcon() diff --git a/code/game/objects/structures.dm b/code/game/objects/structures.dm index 2c9ebb0f9ba..c2904d8e37b 100644 --- a/code/game/objects/structures.dm +++ b/code/game/objects/structures.dm @@ -64,7 +64,7 @@ if(user.canmove) climb_structure(user) return - if ((!( istype(O, /obj/item/weapon) ) || user.get_active_hand() != O)) + if ((!( istype(O, /obj/item/weapon) ) || user.get_active_held_item() != O)) return if(isrobot(user)) return diff --git a/code/game/objects/structures/guncase.dm b/code/game/objects/structures/guncase.dm index 598c5562e03..abaebce5de3 100644 --- a/code/game/objects/structures/guncase.dm +++ b/code/game/objects/structures/guncase.dm @@ -80,10 +80,8 @@ if(!usr.canUseTopic(src)) return if(ishuman(usr)) - if(!usr.get_active_hand()) - usr.put_in_hands(O) - else - O.loc = get_turf(src) + if(!usr.put_in_hands(O)) + O.forceMove(get_turf(src)) update_icon() /obj/structure/guncase/shotgun diff --git a/code/game/objects/structures/morgue.dm b/code/game/objects/structures/morgue.dm index 7a7b200ab39..c16ae3f1401 100644 --- a/code/game/objects/structures/morgue.dm +++ b/code/game/objects/structures/morgue.dm @@ -66,7 +66,7 @@ add_fingerprint(user) if(istype(P, /obj/item/weapon/pen)) var/t = stripped_input(user, "What would you like the label to be?", text("[]", name), null) - if (user.get_active_hand() != P) + if (user.get_active_held_item() != P) return if ((!in_range(src, usr) && src.loc != user)) return diff --git a/code/game/objects/structures/noticeboard.dm b/code/game/objects/structures/noticeboard.dm index 8a7ce0ad0dd..411ea3ec003 100644 --- a/code/game/objects/structures/noticeboard.dm +++ b/code/game/objects/structures/noticeboard.dm @@ -60,15 +60,12 @@ var/obj/item/P = locate(href_list["write"]) if((P && P.loc == src)) //ifthe paper's on the board - if(istype(usr.r_hand, /obj/item/weapon/pen)) //and you're holding a pen + var/obj/item/I = usr.is_holding_item_of_type(/obj/item/weapon/pen) + if(I) //check hand for pen add_fingerprint(usr) - P.attackby(usr.r_hand, usr) //then do ittttt + P.attackby(I, usr) else - if(istype(usr.l_hand, /obj/item/weapon/pen)) //check other hand for pen - add_fingerprint(usr) - P.attackby(usr.l_hand, usr) - else - usr << "You'll need something to write with!" + usr << "You'll need something to write with!" if(href_list["read"]) var/obj/item/weapon/paper/P = locate(href_list["read"]) diff --git a/code/game/objects/structures/safe.dm b/code/game/objects/structures/safe.dm index 8cd1b6b101d..5b1acebb898 100644 --- a/code/game/objects/structures/safe.dm +++ b/code/game/objects/structures/safe.dm @@ -91,7 +91,7 @@ FLOOR SAFES var/mob/living/carbon/human/user = usr var/canhear = 0 - if(istype(user.l_hand, /obj/item/clothing/tie/stethoscope) || istype(user.r_hand, /obj/item/clothing/tie/stethoscope)) + if(user.is_holding_item_of_type(/obj/item/clothing/tie/stethoscope)) canhear = 1 if(href_list["open"]) diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index d1ff3fbe443..ed406cc22aa 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -484,7 +484,7 @@ . = . || mover.checkpass(PASSTABLE) /obj/structure/rack/MouseDrop_T(obj/O, mob/user) - if ((!( istype(O, /obj/item/weapon) ) || user.get_active_hand() != O)) + if ((!( istype(O, /obj/item/weapon) ) || user.get_active_held_item() != O)) return if(!user.drop_item()) return diff --git a/code/game/objects/structures/target_stake.dm b/code/game/objects/structures/target_stake.dm index 0a0d96eac20..8814ec13fb6 100644 --- a/code/game/objects/structures/target_stake.dm +++ b/code/game/objects/structures/target_stake.dm @@ -41,7 +41,7 @@ pinned_target.nullPinnedLoc() nullPinnedTarget() if(ishuman(user)) - if(!user.get_active_hand()) + if(!user.get_active_held_item()) user.put_in_hands(pinned_target) user << "You take the target out of the stake." else diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm index c65cd051b5d..269bae4878b 100644 --- a/code/game/objects/structures/watercloset.dm +++ b/code/game/objects/structures/watercloset.dm @@ -251,10 +251,8 @@ var/mob/living/carbon/M = L . = 1 check_heat(M) - if(M.r_hand) - M.r_hand.clean_blood() - if(M.l_hand) - M.l_hand.clean_blood() + for(var/obj/item/I in M.held_items) + I.clean_blood() if(M.back) if(M.back.clean_blood()) M.update_inv_back(0) diff --git a/code/game/turfs/open.dm b/code/game/turfs/open.dm index 07d70bfc4b7..6d164565ac9 100644 --- a/code/game/turfs/open.dm +++ b/code/game/turfs/open.dm @@ -100,8 +100,8 @@ if(!(lube&SLIDE_ICE)) playsound(C.loc, 'sound/misc/slip.ogg', 50, 1, -3) - C.accident(C.l_hand) - C.accident(C.r_hand) + for(var/obj/item/I in C.held_items) + C.accident(I) var/olddir = C.dir if(!(lube&SLIDE_ICE)) diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm index 9b5f0026e1a..e1da895de41 100644 --- a/code/game/turfs/simulated/walls.dm +++ b/code/game/turfs/simulated/walls.dm @@ -182,7 +182,7 @@ if(do_after(user, slicing_duration/W.toolspeed, target = src)) if( !istype(src, /turf/closed/wall) || !user || !WT || !WT.isOn() || !T ) return 1 - if( user.loc == T && user.get_active_hand() == WT ) + if( user.loc == T && user.get_active_held_item() == WT ) user << "You remove the outer plating." dismantle_wall() return 1 @@ -192,7 +192,7 @@ if(do_after(user, slicing_duration*0.6, target = src)) // plasma cutter is faster than welding tool if( !istype(src, /turf/closed/wall) || !user || !W || !T ) return 1 - if( user.loc == T && user.get_active_hand() == W ) + if( user.loc == T && user.get_active_held_item() == W ) user << "You remove the outer plating." dismantle_wall() visible_message("The wall was sliced apart by [user]!", "You hear metal being sliced apart.") @@ -205,7 +205,7 @@ var/obj/item/weapon/pickaxe/drill/jackhammer/D = W if( !istype(src, /turf/closed/wall) || !user || !W || !T ) return 1 - if( user.loc == T && user.get_active_hand() == W ) + if( user.loc == T && user.get_active_held_item() == W ) D.playDigSound() dismantle_wall() visible_message("[user] smashes through the [name] with the [W.name]!", "You hear the grinding of metal.") diff --git a/code/game/turfs/simulated/walls_reinforced.dm b/code/game/turfs/simulated/walls_reinforced.dm index 0212e8f32d2..cfcaf0159c8 100644 --- a/code/game/turfs/simulated/walls_reinforced.dm +++ b/code/game/turfs/simulated/walls_reinforced.dm @@ -38,7 +38,7 @@ if(do_after(user, 50, target = src)) if( !istype(src, /turf/closed/wall/r_wall) || !user || !W || !T ) return 1 - if( user.loc == T && user.get_active_hand() == W ) + if( user.loc == T && user.get_active_held_item() == W ) D.playDigSound() visible_message("[user] smashes through the [name] with the [D.name]!", "You hear the grinding of metal.") dismantle_wall() @@ -80,7 +80,7 @@ if( !istype(src, /turf/closed/wall/r_wall) || !user || !W || !T ) return 1 - if( d_state == 1 && user.loc == T && user.get_active_hand() == W ) + if( d_state == 1 && user.loc == T && user.get_active_held_item() == W ) src.d_state = 2 update_icon() user << "You remove the support lines." @@ -111,7 +111,7 @@ if( !istype(src, /turf/closed/wall/r_wall) || !user || !WT || !WT.isOn() || !T ) return 0 - if( d_state == 2 && user.loc == T && user.get_active_hand() == WT ) + if( d_state == 2 && user.loc == T && user.get_active_held_item() == WT ) src.d_state = 3 update_icon() user << "You press firmly on the cover, dislodging it." @@ -126,7 +126,7 @@ if( !istype(src, /turf/closed/wall/r_wall) || !user || !W || !T ) return 1 - if( d_state == 2 && user.loc == T && user.get_active_hand() == W ) + if( d_state == 2 && user.loc == T && user.get_active_held_item() == W ) src.d_state = 3 update_icon() user << "You press firmly on the cover, dislodging it." @@ -142,7 +142,7 @@ if( !istype(src, /turf/closed/wall/r_wall) || !user || !W || !T ) return 1 - if( d_state == 3 && user.loc == T && user.get_active_hand() == W ) + if( d_state == 3 && user.loc == T && user.get_active_held_item() == W ) src.d_state = 4 update_icon() user << "You pry off the cover." @@ -158,7 +158,7 @@ if( !istype(src, /turf/closed/wall/r_wall) || !user || !W || !T ) return 1 - if( d_state == 4 && user.loc == T && user.get_active_hand() == W ) + if( d_state == 4 && user.loc == T && user.get_active_held_item() == W ) src.d_state = 5 update_icon() user << "You remove the bolts anchoring the support rods." @@ -176,7 +176,7 @@ if( !istype(src, /turf/closed/wall/r_wall) || !user || !WT || !WT.isOn() || !T ) return 1 - if( d_state == 5 && user.loc == T && user.get_active_hand() == WT ) + if( d_state == 5 && user.loc == T && user.get_active_held_item() == WT ) src.d_state = 6 update_icon() user << "You slice through the support rods." @@ -191,7 +191,7 @@ if( !istype(src, /turf/closed/wall/r_wall) || !user || !W || !T ) return 1 - if( d_state == 5 && user.loc == T && user.get_active_hand() == W ) + if( d_state == 5 && user.loc == T && user.get_active_held_item() == W ) src.d_state = 6 update_icon() user << "You slice through the support rods." @@ -207,7 +207,7 @@ if( !istype(src, /turf/closed/wall/r_wall) || !user || !W || !T ) return 1 - if( user.loc == T && user.get_active_hand() == W ) + if( user.loc == T && user.get_active_held_item() == W ) user << "You pry off the outer sheath." dismantle_wall() return 1 diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 0f88f315ee3..f81cebf3259 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1735,17 +1735,15 @@ usr << "This can only be used on instances of type /mob/living/carbon/human." return - H.equip_to_slot_or_del( new /obj/item/weapon/reagent_containers/food/snacks/cookie(H), slot_l_hand ) - if(!(istype(H.l_hand,/obj/item/weapon/reagent_containers/food/snacks/cookie))) - H.equip_to_slot_or_del( new /obj/item/weapon/reagent_containers/food/snacks/cookie(H), slot_r_hand ) - if(!(istype(H.r_hand,/obj/item/weapon/reagent_containers/food/snacks/cookie))) - log_admin("[key_name(H)] has their hands full, so they did not receive their cookie, spawned by [key_name(src.owner)].") - message_admins("[key_name(H)] has their hands full, so they did not receive their cookie, spawned by [key_name(src.owner)].") - return - else - H.update_inv_r_hand()//To ensure the icon appears in the HUD + var/obj/item/weapon/reagent_containers/food/snacks/cookie/cookie = new(H) + if(H.put_in_hands(cookie)) + H.update_inv_hands() else - H.update_inv_l_hand() + qdel(cookie) + log_admin("[key_name(H)] has their hands full, so they did not receive their cookie, spawned by [key_name(src.owner)].") + message_admins("[key_name(H)] has their hands full, so they did not receive their cookie, spawned by [key_name(src.owner)].") + return + log_admin("[key_name(H)] got their cookie, spawned by [key_name(src.owner)].") message_admins("[key_name(H)] got their cookie, spawned by [key_name(src.owner)].") feedback_inc("admin_cookies_spawned",1) diff --git a/code/modules/admin/verbs/onlyone.dm b/code/modules/admin/verbs/onlyone.dm index bddc973b359..affb6b57bc9 100644 --- a/code/modules/admin/verbs/onlyone.dm +++ b/code/modules/admin/verbs/onlyone.dm @@ -76,11 +76,11 @@ var/obj/item/slot_item_ID = H.get_item_by_slot(slot_wear_id) qdel(slot_item_ID) - var/obj/item/slot_item_hand = H.get_item_by_slot(slot_r_hand) + var/obj/item/slot_item_hand = H.get_item_for_held_index(2) H.unEquip(slot_item_hand) var /obj/item/weapon/multisword/multi = new(H) - H.equip_to_slot_or_del(multi, slot_r_hand) + H.put_in_hands_or_del(multi) var/obj/item/weapon/card/id/W = new(H) W.icon_state = "centcom" diff --git a/code/modules/assembly/mousetrap.dm b/code/modules/assembly/mousetrap.dm index fb643f482bc..30adb230404 100644 --- a/code/modules/assembly/mousetrap.dm +++ b/code/modules/assembly/mousetrap.dm @@ -78,7 +78,7 @@ else if(((user.getBrainLoss() >= 60) || user.disabilities & CLUMSY) && prob(50)) var/which_hand = "l_hand" - if(!user.hand) + if(!(user.active_hand_index % 2)) which_hand = "r_hand" triggered(user, which_hand) user.visible_message("[user] accidentally sets off [src], breaking their fingers.", \ @@ -94,7 +94,7 @@ if(armed) if(((user.getBrainLoss() >= 60) || user.disabilities & CLUMSY) && prob(50)) var/which_hand = "l_hand" - if(!user.hand) + if(!(user.active_hand_index % 2)) which_hand = "r_hand" triggered(user, which_hand) user.visible_message("[user] accidentally sets off [src], breaking their fingers.", \ @@ -124,7 +124,7 @@ if(armed) finder.visible_message("[finder] accidentally sets off [src], breaking their fingers.", \ "You accidentally trigger [src]!") - triggered(finder, finder.hand ? "l_hand" : "r_hand") + triggered(finder, (finder.active_hand_index % 2 == 0) ? "r_hand" : "l_hand") return 1 //end the search! return 0 diff --git a/code/modules/awaymissions/corpse.dm b/code/modules/awaymissions/corpse.dm index ab8058af8a3..a2eef743256 100644 --- a/code/modules/awaymissions/corpse.dm +++ b/code/modules/awaymissions/corpse.dm @@ -154,9 +154,9 @@ if(back) H.equip_to_slot_or_del(new back(H), slot_back) if(l_hand) - H.equip_to_slot_or_del(new l_hand(H), slot_l_hand) + H.put_in_hands_or_del(new l_hand(H)) if(r_hand) - H.equip_to_slot_or_del(new r_hand(H), slot_r_hand) + H.put_in_hands_or_del(new r_hand(H)) if(has_id) var/obj/item/weapon/card/id/W = new(H) if(id_icon) diff --git a/code/modules/awaymissions/super_secret_room.dm b/code/modules/awaymissions/super_secret_room.dm index 2e0c60acf3c..2e4e1101163 100644 --- a/code/modules/awaymissions/super_secret_room.dm +++ b/code/modules/awaymissions/super_secret_room.dm @@ -105,7 +105,7 @@ /obj/item/rupee/Crossed(mob/M) if(M.put_in_hands(src)) - if(src != M.get_active_hand()) + if(src != M.get_active_held_item()) M.swap_hand() equip_to_best_slot(M) ..() diff --git a/code/modules/client/verbs/suicide.dm b/code/modules/client/verbs/suicide.dm index 413590b6db8..cb6120efe3d 100644 --- a/code/modules/client/verbs/suicide.dm +++ b/code/modules/client/verbs/suicide.dm @@ -10,7 +10,7 @@ if(confirm == "Yes") suiciding = 1 log_game("[key_name(src)] (job: [job ? "[job]" : "None"]) commited suicide at [get_area(src)].") - var/obj/item/held_item = get_active_hand() + var/obj/item/held_item = get_active_held_item() if(held_item) var/damagetype = held_item.suicide_act(src) if(damagetype) diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index a26dfacd4fb..55721e470d2 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -44,12 +44,7 @@ var/obj/screen/inventory/hand/H = over_object if(!M.unEquip(src)) return - switch(H.slot_id) - if(slot_r_hand) - M.put_in_r_hand(src) - if(slot_l_hand) - M.put_in_l_hand(src) - + M.put_in_hand(src, H.held_index) add_fingerprint(usr) /obj/item/clothing/throw_at(atom/target, range, speed, mob/thrower, spin) diff --git a/code/modules/clothing/head/misc_special.dm b/code/modules/clothing/head/misc_special.dm index 340a2e174e9..e2dfe0f6cb8 100644 --- a/code/modules/clothing/head/misc_special.dm +++ b/code/modules/clothing/head/misc_special.dm @@ -60,7 +60,7 @@ var/turf/location = src.loc if(istype(location, /mob/)) var/mob/living/carbon/human/M = location - if(M.l_hand == src || M.r_hand == src || M.head == src) + if(M.is_holding(src) || M.head == src) location = M.loc if (istype(location, /turf)) diff --git a/code/modules/clothing/outfits/standard.dm b/code/modules/clothing/outfits/standard.dm index 1cd4a500a97..84b7de07b84 100644 --- a/code/modules/clothing/outfits/standard.dm +++ b/code/modules/clothing/outfits/standard.dm @@ -52,7 +52,7 @@ if(visualsOnly) return - var/obj/item/weapon/reagent_containers/glass/bucket/bucket = H.l_hand + var/obj/item/weapon/reagent_containers/glass/bucket/bucket = H.get_item_for_held_index(1) bucket.reagents.add_reagent("water",70) /datum/outfit/laser_tag @@ -159,10 +159,10 @@ return //Could use a type - var/obj/item/weapon/storage/secure/briefcase/sec_briefcase = H.l_hand + var/obj/item/weapon/storage/secure/briefcase/sec_briefcase = H.get_item_for_held_index(1) for(var/obj/item/briefcase_item in sec_briefcase) qdel(briefcase_item) - for(var/i=3, i>0, i--) + for(var/i = 3 to 0 step -1) sec_briefcase.handle_item_insertion(new /obj/item/stack/spacecash/c1000,1) sec_briefcase.handle_item_insertion(new /obj/item/weapon/gun/energy/kinetic_accelerator/crossbow,1) sec_briefcase.handle_item_insertion(new /obj/item/weapon/gun/projectile/revolver/mateba,1) diff --git a/code/modules/clothing/spacesuits/chronosuit.dm b/code/modules/clothing/spacesuits/chronosuit.dm index 6506f8239c4..48154a4ae46 100644 --- a/code/modules/clothing/spacesuits/chronosuit.dm +++ b/code/modules/clothing/spacesuits/chronosuit.dm @@ -25,7 +25,7 @@ actions_types = list(/datum/action/item_action/toggle) armor = list(melee = 60, bullet = 60, laser = 60, energy = 60, bomb = 30, bio = 90, rad = 90) var/list/chronosafe_items = list(/obj/item/weapon/chrono_eraser, /obj/item/weapon/gun/energy/chrono_gun) - var/hands_nodrop_states + var/list/hands_nodrop = list() var/obj/item/clothing/head/helmet/space/chronos/helmet = null var/obj/effect/chronos_cam/camera = null var/image/phase_underlay = null @@ -92,10 +92,9 @@ user.notransform = 0 user.anchored = 0 teleporting = 0 - if(user.l_hand && !(hands_nodrop_states & 1)) - user.l_hand.flags &= ~NODROP - if(user.r_hand && !(hands_nodrop_states & 2)) - user.r_hand.flags &= ~NODROP + for(var/obj/item/I in user.held_items) + if(I in hands_nodrop) + I.flags &= ~NODROP if(phase_underlay && !qdeleted(phase_underlay)) user.underlays -= phase_underlay qdel(phase_underlay) @@ -119,7 +118,7 @@ teleport_now.UpdateButtonIcon() - var/list/nonsafe_slots = list(slot_belt, slot_back, slot_l_hand, slot_r_hand) + var/list/nonsafe_slots = list(slot_belt, slot_back) for(var/slot in nonsafe_slots) var/obj/item/slot_item = user.get_item_by_slot(slot) if(slot_item && !(slot_item.type in chronosafe_items) && user.unEquip(slot_item)) @@ -129,14 +128,11 @@ phase_underlay = create_phase_underlay(user) - hands_nodrop_states = 0 - if(user.l_hand) - hands_nodrop_states |= (user.l_hand.flags & NODROP) ? 1 : 0 - user.l_hand.flags |= NODROP - if(user.r_hand) - hands_nodrop_states |= (user.r_hand.flags & NODROP) ? 2 : 0 - user.r_hand.flags |= NODROP - + hands_nodrop = list() + for(var/obj/item/I in user.held_items) + if(!(I.flags & NODROP)) + hands_nodrop += I + I.flags |= NODROP user.animate_movement = NO_STEPS user.changeNext_move(8 + phase_in_ds) user.notransform = 1 diff --git a/code/modules/crafting/craft.dm b/code/modules/crafting/craft.dm index 70f45474c5f..1e1ed209bf0 100644 --- a/code/modules/crafting/craft.dm +++ b/code/modules/crafting/craft.dm @@ -60,8 +60,8 @@ /datum/personal_crafting/proc/get_environment(mob/user) . = list() - . += user.r_hand - . += user.l_hand + for(var/obj/item/I in user.held_items) + . += I if(!istype(user.loc, /turf)) return var/list/L = block(get_step(user, SOUTHWEST), get_step(user, NORTHEAST)) diff --git a/code/modules/detectivework/evidence.dm b/code/modules/detectivework/evidence.dm index 706048c6985..8d6709abe84 100644 --- a/code/modules/detectivework/evidence.dm +++ b/code/modules/detectivework/evidence.dm @@ -39,10 +39,8 @@ if(istype(I.loc,/obj/item/weapon/storage)) //in a container. var/obj/item/weapon/storage/U = I.loc U.remove_from_storage(I, src) - else if(user.l_hand == I) //in a hand - user.drop_l_hand() - else if(user.r_hand == I) //in a hand - user.drop_r_hand() + if(user.is_holding(I)) + user.unEquip(I) else return diff --git a/code/modules/events/holiday/xmas.dm b/code/modules/events/holiday/xmas.dm index 7c2d638ed9d..ec21c483973 100644 --- a/code/modules/events/holiday/xmas.dm +++ b/code/modules/events/holiday/xmas.dm @@ -47,7 +47,7 @@ var/cracked = 0 /obj/item/weapon/toy/xmas_cracker/attack(mob/target, mob/user) - if( !cracked && istype(target,/mob/living/carbon/human) && (target.stat == CONSCIOUS) && !target.get_active_hand() ) + if( !cracked && istype(target,/mob/living/carbon/human) && (target.stat == CONSCIOUS) && !target.get_active_held_item() ) target.visible_message("[user] and [target] pop \an [src]! *pop*", "You pull \an [src] with [target]! *pop*", "You hear a pop.") var/obj/item/weapon/paper/Joke = new /obj/item/weapon/paper(user.loc) Joke.name = "[pick("awful","terrible","unfunny")] joke" diff --git a/code/modules/events/wizard/curseditems.dm b/code/modules/events/wizard/curseditems.dm index 300ecc83c69..5d0bc33b168 100644 --- a/code/modules/events/wizard/curseditems.dm +++ b/code/modules/events/wizard/curseditems.dm @@ -11,7 +11,7 @@ /datum/round_event/wizard/cursed_items/start() var/item_set = pick("wizardmimic", "swords", "bigfatdoobie", "boxing", "voicemodulators", "catgirls2015") - var/list/wearslots = list(slot_wear_suit, slot_shoes, slot_head, slot_wear_mask, slot_r_hand, slot_gloves, slot_ears) + var/list/wearslots = list(slot_wear_suit, slot_shoes, slot_head, slot_wear_mask, slot_gloves, slot_ears) var/list/loadout = list() var/ruins_spaceworthiness var/ruins_wizard_loadout @@ -44,8 +44,8 @@ continue if(item_set == "catgirls2015") //Wizard code means never having to say you're sorry H.gender = FEMALE - var/list/slots = list(H.wear_suit, H.shoes, H.head, H.wear_mask, H.r_hand, H.gloves, H.ears) //add new slots as needed to back - for(var/i = 1, i <= loadout.len, i++) + var/list/slots = list(H.wear_suit, H.shoes, H.head, H.wear_mask, H.gloves, H.ears) //add new slots as needed to back + for(var/i in 1 to loadout.len) if(loadout[i]) var/obj/item/J = loadout[i] var/obj/item/I = new J //dumb but required because of byond throwing a fit anytime new gets too close to a list diff --git a/code/modules/flufftext/Hallucination.dm b/code/modules/flufftext/Hallucination.dm index ad237db5be9..7e34d6a1b3a 100644 --- a/code/modules/flufftext/Hallucination.dm +++ b/code/modules/flufftext/Hallucination.dm @@ -324,14 +324,10 @@ Gunshots/explosions/opening doors/less rare audio (done) return var/obj/effect/fake_attacker/F = new/obj/effect/fake_attacker(get_turf(target),target) - if(clone.l_hand) - if(!(locate(clone.l_hand) in non_fakeattack_weapons)) - clone_weapon = clone.l_hand.name - F.weap = clone.l_hand - else if (clone.r_hand) - if(!(locate(clone.r_hand) in non_fakeattack_weapons)) - clone_weapon = clone.r_hand.name - F.weap = clone.r_hand + for(var/obj/item/I in clone.held_items) + if(!(locate(I) in non_fakeattack_weapons)) + clone_weapon = I.name + F.weap = I F.name = clone.name F.my_target = target @@ -619,9 +615,13 @@ var/list/non_fakeattack_weapons = list(/obj/item/weapon/gun/projectile, /obj/ite //src << "Traitor Items" if(!halitem) halitem = new - var/list/slots_free = list(ui_lhand,ui_rhand) - if(l_hand) slots_free -= ui_lhand - if(r_hand) slots_free -= ui_rhand + var/obj/item/l_hand = get_item_for_held_index(1) + var/obj/item/r_hand = get_item_for_held_index(2) + var/l = ui_hand_position(get_held_index_of_item(l_hand)) + var/r = ui_hand_position(get_held_index_of_item(r_hand)) + var/list/slots_free = list(l,r) + if(l_hand) slots_free -= l + if(r_hand) slots_free -= r if(istype(src,/mob/living/carbon/human)) var/mob/living/carbon/human/H = src if(!H.belt) slots_free += ui_belt diff --git a/code/modules/food_and_drinks/pizzabox.dm b/code/modules/food_and_drinks/pizzabox.dm index cc29cb25b70..0d4a99a91b0 100644 --- a/code/modules/food_and_drinks/pizzabox.dm +++ b/code/modules/food_and_drinks/pizzabox.dm @@ -84,7 +84,7 @@ update_icon() /obj/item/pizzabox/attack_hand(mob/user) - if(user.get_inactive_hand() != src) + if(user.get_inactive_held_item() != src) ..() return if(open) diff --git a/code/modules/hydroponics/gene_modder.dm b/code/modules/hydroponics/gene_modder.dm index f5bd17e0ed0..4787f2829b0 100644 --- a/code/modules/hydroponics/gene_modder.dm +++ b/code/modules/hydroponics/gene_modder.dm @@ -234,7 +234,7 @@ update_genes() update_icon() else - var/obj/item/I = usr.get_active_hand() + var/obj/item/I = usr.get_active_held_item() if (istype(I, /obj/item/seeds)) if(!usr.drop_item()) return @@ -248,7 +248,7 @@ disk = null update_genes() else - var/obj/item/I = usr.get_active_hand() + var/obj/item/I = usr.get_active_held_item() if(istype(I, /obj/item/weapon/disk/plantgene)) if(!usr.drop_item()) return @@ -396,7 +396,7 @@ ..() if(istype(W, /obj/item/weapon/pen)) var/t = stripped_input(user, "What would you like the label to be?", name, null) - if(user.get_active_hand() != W) + if(user.get_active_held_item() != W) return if(!in_range(src, user) && loc != user) return diff --git a/code/modules/hydroponics/grown/chili.dm b/code/modules/hydroponics/grown/chili.dm index 4e641c4e8cd..be9ef5838ac 100644 --- a/code/modules/hydroponics/grown/chili.dm +++ b/code/modules/hydroponics/grown/chili.dm @@ -83,7 +83,7 @@ /obj/item/weapon/reagent_containers/food/snacks/grown/ghost_chili/process() if(held_mob && src.loc == held_mob) - if( (held_mob.l_hand == src) || (held_mob.r_hand == src)) + if(held_mob.is_holding(src)) if(hasvar(held_mob,"gloves") && held_mob:gloves) return held_mob.bodytemperature += 15 * TEMPERATURE_DAMAGE_COEFFICIENT diff --git a/code/modules/hydroponics/grown/nettle.dm b/code/modules/hydroponics/grown/nettle.dm index dac4b76aa3e..0dd97c68a36 100644 --- a/code/modules/hydroponics/grown/nettle.dm +++ b/code/modules/hydroponics/grown/nettle.dm @@ -55,7 +55,7 @@ var/mob/living/carbon/human/H = C if(H.gloves) return 0 - var/organ = ((H.hand ? "l_":"r_") + "arm") + 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) diff --git a/code/modules/jobs/access.dm b/code/modules/jobs/access.dm index 4b6a96add86..0b15123b142 100644 --- a/code/modules/jobs/access.dm +++ b/code/modules/jobs/access.dm @@ -115,16 +115,16 @@ else if(istype(M, /mob/living/carbon/human)) var/mob/living/carbon/human/H = M //if they are holding or wearing a card that has access, that works - if(check_access(H.get_active_hand()) || src.check_access(H.wear_id)) + if(check_access(H.get_active_held_item()) || src.check_access(H.wear_id)) return 1 else if(istype(M, /mob/living/carbon/monkey) || istype(M, /mob/living/carbon/alien/humanoid)) var/mob/living/carbon/george = M //they can only hold things :( - if(check_access(george.get_active_hand())) + if(check_access(george.get_active_held_item())) return 1 else if(isanimal(M)) var/mob/living/simple_animal/A = M - if(check_access(A.get_active_hand()) || check_access(A.access_card)) + if(check_access(A.get_active_held_item()) || check_access(A.access_card)) return 1 return 0 diff --git a/code/modules/library/lib_items.dm b/code/modules/library/lib_items.dm index c5d9add72cc..43ca9d51012 100644 --- a/code/modules/library/lib_items.dm +++ b/code/modules/library/lib_items.dm @@ -102,7 +102,7 @@ if(!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr)) return if(ishuman(user)) - if(!user.get_active_hand()) + if(!user.get_active_held_item()) user.put_in_hands(choice) else choice.loc = get_turf(src) @@ -264,7 +264,7 @@ B.name = src.name B.title = src.title B.icon_state = src.icon_state - if(user.l_hand == src || user.r_hand == src) + if(user.is_holding(src)) qdel(src) user.put_in_hands(B) return diff --git a/code/modules/mining/laborcamp/laborstacker.dm b/code/modules/mining/laborcamp/laborstacker.dm index 58e13865f94..6c328b8cd64 100644 --- a/code/modules/mining/laborcamp/laborstacker.dm +++ b/code/modules/mining/laborcamp/laborstacker.dm @@ -74,14 +74,14 @@ switch(action) if("handle_id") if(inserted_id) - if(!usr.get_active_hand()) + if(!usr.get_active_held_item()) usr.put_in_hands(inserted_id) inserted_id = null else inserted_id.forceMove(get_turf(src)) inserted_id = null else - var/obj/item/I = usr.get_active_hand() + var/obj/item/I = usr.get_active_held_item() if(istype(I, /obj/item/weapon/card/id/prisoner)) if(!usr.drop_item()) return diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm index abcc8e7521b..68a3ca84760 100644 --- a/code/modules/mining/lavaland/necropolis_chests.dm +++ b/code/modules/mining/lavaland/necropolis_chests.dm @@ -338,11 +338,7 @@ var/obj/screen/inventory/hand/H = over_object if(!M.unEquip(src)) return - switch(H.slot_id) - if(slot_r_hand) - M.put_in_r_hand(src) - if(slot_l_hand) - M.put_in_l_hand(src) + M.put_in_hand(src, H.held_index) add_fingerprint(usr) @@ -734,6 +730,6 @@ if(H == L) continue H << "You have an overwhelming desire to kill [L]. They have been marked red! Go kill them!" - H.equip_to_slot_or_del(new /obj/item/weapon/kitchen/knife/butcher(H), slot_l_hand) + H.put_in_hands_or_del(new /obj/item/weapon/kitchen/knife/butcher(H)) qdel(src) diff --git a/code/modules/mining/machine_redemption.dm b/code/modules/mining/machine_redemption.dm index 0d067eeb2b1..d298e3c146a 100644 --- a/code/modules/mining/machine_redemption.dm +++ b/code/modules/mining/machine_redemption.dm @@ -101,7 +101,7 @@ if (!powered()) return if(istype(W,/obj/item/weapon/card/id)) - var/obj/item/weapon/card/id/I = user.get_active_hand() + var/obj/item/weapon/card/id/I = user.get_active_held_item() if(istype(I) && !istype(inserted_id)) if(!user.drop_item()) return @@ -208,7 +208,7 @@ else usr << "Required access not found." else if(href_list["choice"] == "insert") - var/obj/item/weapon/card/id/I = usr.get_active_hand() + var/obj/item/weapon/card/id/I = usr.get_active_held_item() if(istype(I)) if(!usr.drop_item()) return diff --git a/code/modules/mining/machine_vending.dm b/code/modules/mining/machine_vending.dm index a3984de77d4..fdb907cac4b 100644 --- a/code/modules/mining/machine_vending.dm +++ b/code/modules/mining/machine_vending.dm @@ -121,7 +121,7 @@ inserted_id.verb_pickup() inserted_id = null else if(href_list["choice"] == "insert") - var/obj/item/weapon/card/id/I = usr.get_active_hand() + var/obj/item/weapon/card/id/I = usr.get_active_held_item() if(istype(I)) if(!usr.drop_item()) return @@ -149,7 +149,7 @@ RedeemVoucher(I, user) return if(istype(I,/obj/item/weapon/card/id)) - var/obj/item/weapon/card/id/C = usr.get_active_hand() + var/obj/item/weapon/card/id/C = usr.get_active_held_item() if(istype(C) && !istype(inserted_id)) if(!usr.drop_item()) return diff --git a/code/modules/mining/mine_turfs.dm b/code/modules/mining/mine_turfs.dm index f18a329581a..bf40e0b4564 100644 --- a/code/modules/mining/mine_turfs.dm +++ b/code/modules/mining/mine_turfs.dm @@ -436,10 +436,9 @@ ..() if(istype(AM,/mob/living/carbon/human)) var/mob/living/carbon/human/H = AM - if((istype(H.l_hand,/obj/item/weapon/pickaxe)) && (!H.hand)) - src.attackby(H.l_hand,H) - else if((istype(H.r_hand,/obj/item/weapon/pickaxe)) && H.hand) - src.attackby(H.r_hand,H) + var/obj/item/I = H.is_holding_item_of_type(/obj/item/weapon/pickaxe) + if(I) + attackby(I,H) return else if(istype(AM,/mob/living/silicon/robot)) var/mob/living/silicon/robot/R = AM diff --git a/code/modules/mob/interactive.dm b/code/modules/mob/interactive.dm index a6910a62eac..ab0aa56e1c0 100644 --- a/code/modules/mob/interactive.dm +++ b/code/modules/mob/interactive.dm @@ -299,8 +299,6 @@ BP.change_bodypart_status(ORGAN_ROBOTIC) update_icons() update_damage_overlays(0) - - hand = 0 functions = list("nearbyscan","combat","shitcurity","chatter") // stop customize adding multiple copies of a function //job specific favours switch(myjob.title) @@ -491,28 +489,35 @@ if(other_hand) if(other_hand.loc != src) other_hand = null - if(hand) - if(!l_hand) + + var/obj/item/L = get_item_for_held_index(1) //just going to hardcode SNPCs to 2 hands, for now. + var/obj/item/R = get_item_for_held_index(2) //they're just VERY assume-y about 2 hands. + if(active_hand_index == 1) + if(!L) main_hand = null - if(r_hand) + if(R) swap_hands() else - if(!r_hand) + if(!R) main_hand = null - if(l_hand) + if(L) swap_hands() + /mob/living/carbon/human/interactive/proc/swap_hands() - hand = !hand - var/obj/item/T = other_hand - main_hand = other_hand - other_hand = T + var/oindex = active_hand_index + if(active_hand_index == 1) + active_hand_index = 2 + else + active_hand_index = 1 + main_hand = get_active_held_item() + other_hand = get_item_for_held_index(oindex) update_hands = 1 /mob/living/carbon/human/interactive/proc/take_to_slot(obj/item/G, var/hands=0) - var/list/slots = list ("left pocket" = slot_l_store,"right pocket" = slot_r_store,"left hand" = slot_l_hand,"right hand" = slot_r_hand) + var/list/slots = list ("left pocket" = slot_l_store,"right pocket" = slot_r_store,"left hand" = slot_hands,"right hand" = slot_hands) if(hands) - slots = list ("left hand" = slot_l_hand,"right hand" = slot_r_hand) + slots = list ("left hand" = slot_hands,"right hand" = slot_hands) G.loc = src if(G.force && G.force > best_force) best_force = G.force @@ -520,7 +525,7 @@ update_hands = 1 /mob/living/carbon/human/interactive/proc/insert_into_backpack() - var/list/slots = list ("left pocket" = slot_l_store,"right pocket" = slot_r_store,"left hand" = slot_l_hand,"right hand" = slot_r_hand) + var/list/slots = list ("left pocket" = slot_l_store,"right pocket" = slot_r_store,"left hand" = slot_hands,"right hand" = slot_hands) var/obj/item/I = get_item_by_slot(pick(slots)) var/obj/item/weapon/storage/BP = get_item_by_slot(slot_back) if(back && BP && I) @@ -604,14 +609,16 @@ D.open() if(update_hands) + var/obj/item/l_hand = get_item_for_held_index(1) + var/obj/item/r_hand = get_item_for_held_index(2) if(l_hand || r_hand) if(l_hand) - hand = 1 + active_hand_index = 1 main_hand = l_hand if(r_hand) other_hand = r_hand else if(r_hand) - hand = 0 + active_hand_index = 2 main_hand = r_hand if(l_hand) //this technically shouldnt occur, but its a redundancy other_hand = l_hand @@ -659,12 +666,12 @@ if(istype(TARGET, /obj/item/weapon)) var/obj/item/weapon/W = TARGET if(W.force >= best_force || prob((FUZZY_CHANCE_LOW+FUZZY_CHANCE_HIGH)/2)) - if(!l_hand || !r_hand) + if(!get_item_for_held_index(1) || !get_item_for_held_index(2)) put_in_hands(W) else insert_into_backpack() else - if(!l_hand || !r_hand) + if(!get_item_for_held_index(1) || !get_item_for_held_index(2)) put_in_hands(TARGET) else insert_into_backpack() diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm index 1268581a38b..8e3cb40fbf4 100644 --- a/code/modules/mob/inventory.dm +++ b/code/modules/mob/inventory.dm @@ -1,178 +1,291 @@ -//These procs handle putting s tuff in your hand. It's probably best to use these rather than setting l_hand = ...etc +//These procs handle putting s tuff in your hands //as they handle all relevant stuff like adding it to the player's screen and updating their overlays. -//Returns the thing in our active hand -/mob/proc/get_active_hand() - if(hand) - return l_hand - else - return r_hand +//Returns the thing we're currently holding +/mob/proc/get_active_held_item() + return get_item_for_held_index(active_hand_index) -//Returns the thing in our inactive hand -/mob/proc/get_inactive_hand() - if(hand) - return r_hand +//Finds the opposite limb for the active one (eg: upper left arm will find the item in upper right arm) +//So we're treating each "pair" of limbs as a team, so "both" refers to them +/mob/proc/get_inactive_held_item() + return get_item_for_held_index(get_inactive_hand_index()) + + +//Finds the opposite index for the active one (eg: upper left arm will find the item in upper right arm) +//So we're treating each "pair" of limbs as a team, so "both" refers to them +/mob/proc/get_inactive_hand_index() + var/other_hand = 0 + if(!(active_hand_index % 2)) + other_hand = active_hand_index-1 //finding the matching "left" limb else - return l_hand + other_hand = active_hand_index+1 //finding the matching "right" limb + if(other_hand < 0 || other_hand > held_items.len) + other_hand = 0 + return other_hand + + +/mob/proc/get_item_for_held_index(i) + if(i > 0 && i <= held_items.len) + return held_items[i] + return FALSE + + +//Odd = left. Even = right +/mob/proc/held_index_to_dir(i) + if(!(i % 2)) + return "r" + return "l" + + +//Check we have an organ for this hand slot (Dismemberment), Only relevant for humans +/mob/proc/has_hand_for_held_index(i) + return TRUE + + +//Check we have an organ for our active hand slot (Dismemberment),Only relevant for humans +/mob/proc/has_active_hand() + return has_hand_for_held_index(active_hand_index) + + +//Finds the first available (null) index OR all available (null) indexes in held_items based on a side. +//Lefts: 1, 3, 5, 7... +//Rights:2, 4, 6, 8... +/mob/proc/get_empty_held_index_for_side(side = "left", all = FALSE) + var/start = 0 + var/static/list/lefts = list("l" = TRUE,"L" = TRUE,"LEFT" = TRUE,"left" = TRUE) + var/static/list/rights = list("r" = TRUE,"R" = TRUE,"RIGHT" = TRUE,"right" = TRUE) //"to remain silent" + if(lefts[side]) + start = 1 + else if(rights[side]) + start = 2 + if(!start) + return FALSE + var/list/empty_indexes + for(var/i in start to held_items.len step 2) + if(!held_items[i]) + if(!all) + return i + if(!empty_indexes) + empty_indexes = list() + empty_indexes += i + return empty_indexes + + +//Same as the above, but returns the first or ALL held *ITEMS* for the side +/mob/proc/get_held_items_for_side(side = "left", all = FALSE) + var/start = 0 + var/static/list/lefts = list("l" = TRUE,"L" = TRUE,"LEFT" = TRUE,"left" = TRUE) + var/static/list/rights = list("r" = TRUE,"R" = TRUE,"RIGHT" = TRUE,"right" = TRUE) //"to remain silent" + if(lefts[side]) + start = 1 + else if(rights[side]) + start = 2 + if(!start) + return FALSE + var/list/holding_items + for(var/i in start to held_items.len step 2) + var/obj/item/I = held_items[i] + if(I) + if(!all) + return I + if(!holding_items) + holding_items = list() + holding_items += I + return holding_items + + +/mob/proc/get_empty_held_indexes() + var/list/L + for(var/i in 1 to held_items.len) + if(!held_items[i]) + if(!L) + L = list() + L += i + return L + +/mob/proc/get_held_index_of_item(obj/item/I) + return held_items.Find(I) + + +//Sad that this will cause some overhead, but the alias seems necessary +//*I* may be happy with a million and one references to "indexes" but others won't be +/mob/proc/is_holding(obj/item/I) + return get_held_index_of_item(I) + + +//Checks if we're holding an item of type: typepath +/mob/proc/is_holding_item_of_type(typepath) + for(var/obj/item/I in held_items) + if(istype(I, typepath)) + return I + return FALSE + + +//To appropriately fluff things like "they are holding [I] in their [get_held_index_name(get_held_index_of_item(I))]" +//Can be overriden to pass off the fluff to something else (eg: science allowing people to add extra robotic limbs, and having this proc react to that +// with say "they are holding [I] in their Nanotrasen Brand Utility Arm - Right Edition" or w/e +/mob/proc/get_held_index_name(i) + var/list/hand = list() + if(i > 2) + hand += "upper " + var/num = 0 + if(!(i % 2)) + num = i-2 + hand += "right hand" + else + num = i-1 + hand += "left hand" + num -= (num*0.5) + if(num > 1) //"upper left hand #1" seems weird, but "upper left hand #2" is A-ok + hand += " #[num]" + return hand.Join() + //Returns if a certain item can be equipped to a certain slot. // Currently invalid for two-handed items - call obj/item/mob_can_equip() instead. /mob/proc/can_equip(obj/item/I, slot, disable_warning = 0) - return 0 - -//Puts the item into your l_hand if possible and calls all necessary triggers/updates. returns 1 on success. -/mob/proc/put_in_l_hand(obj/item/W) - if(!put_in_hand_check(W)) - return 0 - if(!has_left_hand()) - return 0 - if(!l_hand) - W.loc = src //TODO: move to equipped? - l_hand = W - W.layer = ABOVE_HUD_LAYER //TODO: move to equipped? - W.equipped(src,slot_l_hand) - if(W.pulledby) - W.pulledby.stop_pulling() - update_inv_l_hand() - W.pixel_x = initial(W.pixel_x) - W.pixel_y = initial(W.pixel_y) - return 1 - return 0 + return FALSE -//Puts the item into your r_hand if possible and calls all necessary triggers/updates. returns 1 on success. -/mob/proc/put_in_r_hand(obj/item/W) - if(!put_in_hand_check(W)) - return 0 - if(!has_right_hand()) - return 0 - if(!r_hand) - W.loc = src - r_hand = W - W.layer = ABOVE_HUD_LAYER - W.equipped(src,slot_r_hand) - if(W.pulledby) - W.pulledby.stop_pulling() - update_inv_r_hand() - W.pixel_x = initial(W.pixel_x) - W.pixel_y = initial(W.pixel_y) - return 1 - return 0 - -/mob/proc/put_in_hand_check(obj/item/W) - if(lying && !(W.flags&ABSTRACT)) - return 0 - if(!istype(W)) - return 0 - return 1 - -//Puts the item into our active hand if possible. returns 1 on success. -/mob/proc/put_in_active_hand(obj/item/W) - if(hand) - return put_in_l_hand(W) - else - return put_in_r_hand(W) +/mob/proc/put_in_hand(obj/item/I, hand_index) + if(!put_in_hand_check(I)) + return FALSE + if(!has_hand_for_held_index(hand_index)) + return FALSE + var/obj/item/curr = held_items[hand_index] + if(!curr) + I.loc = src + held_items[hand_index] = I + I.layer = ABOVE_HUD_LAYER + I.equipped(src, slot_hands) + if(I.pulledby) + I.pulledby.stop_pulling() + update_inv_hands() + I.pixel_x = initial(I.pixel_x) + I.pixel_y = initial(I.pixel_y) + return hand_index || TRUE + return FALSE -//Puts the item into our inactive hand if possible. returns 1 on success. -/mob/proc/put_in_inactive_hand(obj/item/W) - if(hand) - return put_in_r_hand(W) - else - return put_in_l_hand(W) +//Puts the item into the first available left hand if possible and calls all necessary triggers/updates. returns 1 on success. +/mob/proc/put_in_l_hand(obj/item/I) + return put_in_hand(I, get_empty_held_index_for_side("l")) -//Puts the item our active hand if possible. Failing that it tries our inactive hand. Returns 1 on success. -//If both fail it drops it on the floor and returns 0. +//Puts the item into the first available right hand if possible and calls all necessary triggers/updates. returns 1 on success. +/mob/proc/put_in_r_hand(obj/item/I) + return put_in_hand(I, get_empty_held_index_for_side("r")) + + +/mob/proc/put_in_hand_check(obj/item/I) + if(lying && !(I.flags&ABSTRACT)) + return FALSE + if(!istype(I)) + return FALSE + return TRUE + + +//Puts the item into our active hand if possible. returns TRUE on success. +/mob/proc/put_in_active_hand(obj/item/I) + return put_in_hand(I, active_hand_index) + + +//Puts the item into our inactive hand if possible, returns TRUE on success +/mob/proc/put_in_inactive_hand(obj/item/I) + return put_in_hand(I, get_inactive_hand_index()) + + +//Puts the item our active hand if possible. Failing that it tries our inactive hand. Returns TRUE on success. +//If both fail it drops it on the floor and returns FALSE. //This is probably the main one you need to know :) -/mob/proc/put_in_hands(obj/item/W) - if(!W) - return 0 - if(put_in_active_hand(W)) - return 1 - else if(put_in_inactive_hand(W)) - return 1 - else - W.loc = get_turf(src) - W.layer = initial(W.layer) - W.dropped(src) - return 0 +/mob/proc/put_in_hands(obj/item/I, del_on_fail = FALSE) + if(!I) + return FALSE + var/hand = get_empty_held_index_for_side("l") + if(!hand) + hand = get_empty_held_index_for_side("r") + if(hand) + if(put_in_hand(I, hand)) + return TRUE + if(del_on_fail) + qdel(I) + return FALSE + I.forceMove(get_turf(src)) + I.layer = initial(I.layer) + I.dropped(src) + return FALSE + + +/mob/proc/put_in_hands_or_del(obj/item/I) + return put_in_hands(I, TRUE) /mob/proc/drop_item_v() //this is dumb. if(stat == CONSCIOUS && isturf(loc)) return drop_item() - return 0 + return FALSE -//Drops the item in our left hand -/mob/proc/drop_l_hand() - if(!loc || !loc.allow_drop()) - return - return unEquip(l_hand) //All needed checks are in unEquip - - -//Drops the item in our right hand +/* +/mob/proc/drop_l_hand() //pending re-implementation /mob/proc/drop_r_hand() +*/ +/mob/proc/drop_all_held_items() if(!loc || !loc.allow_drop()) return - return unEquip(r_hand) - + for(var/obj/item/I in held_items) + unEquip(I) //Drops the item in our active hand. /mob/proc/drop_item() - if(hand) - return drop_l_hand() - else - return drop_r_hand() + if(!loc || !loc.allow_drop()) + return + var/obj/item/held = get_active_held_item() + return unEquip(held) //Here lie drop_from_inventory and before_item_take, already forgotten and not missed. - /mob/proc/canUnEquip(obj/item/I, force) if(!I) - return 1 + return TRUE if((I.flags & NODROP) && !force) - return 0 - return 1 + return FALSE + return TRUE /mob/proc/unEquip(obj/item/I, force) //Force overrides NODROP for things like wizarditis and admin undress. if(!I) //If there's nothing to drop, the drop is automatically succesfull. If(unEquip) should generally be used to check for NODROP. - return 1 + return TRUE if((I.flags & NODROP) && !force) - return 0 - - if(I == r_hand) - r_hand = null - update_inv_r_hand() - else if(I == l_hand) - l_hand = null - update_inv_l_hand() + return FALSE + var/hand_index = get_held_index_of_item(I) + if(hand_index) + held_items[hand_index] = null + update_inv_hands() if(I) if(client) client.screen -= I - I.loc = loc + I.layer = initial(I.layer) + I.forceMove(loc) I.dropped(src) - if(I) - I.layer = initial(I.layer) - return 1 + return TRUE //Attemps to remove an object on a mob. Will not move it to another area or such, just removes from the mob. -/mob/proc/remove_from_mob(var/obj/O) - unEquip(O) - O.screen_loc = null - return 1 +/mob/proc/remove_from_mob(var/obj/item/I) + unEquip(I) + I.screen_loc = null + return TRUE //Outdated but still in use apparently. This should at least be a human proc. +//Daily reminder to murder this - Remie. /mob/proc/get_equipped_items() - var/list/items = new/list() + var/list/items = list() if(hasvar(src,"back")) if(src:back) @@ -204,48 +317,34 @@ if(hasvar(src,"wear_suit")) if(src:wear_suit) items += src:wear_suit -/* if(hasvar(src,"w_radio")) - if(src:w_radio) - items += src:w_radio commenting this out since headsets go on your ears now PLEASE DON'T BE MAD KEELIN */ if(hasvar(src,"w_uniform")) if(src:w_uniform) items += src:w_uniform - -/* if(hasvar(src,"l_hand")) - if(src:l_hand) - items += src:l_hand - if(hasvar(src,"r_hand")) - if(src:r_hand) - items += src:r_hand*/ - return items /obj/item/proc/equip_to_best_slot(var/mob/M) - if(src != M.get_active_hand()) + if(src != M.get_active_held_item()) M << "You are not holding anything to equip!" - return 0 + return FALSE if(M.equip_to_appropriate_slot(src)) - if(M.hand) - M.update_inv_l_hand() - else - M.update_inv_r_hand() - return 1 + M.update_inv_hands() + return TRUE if(M.s_active && M.s_active.can_be_inserted(src,1)) //if storage active insert there M.s_active.handle_item_insertion(src) - return 1 + return TRUE - var/obj/item/weapon/storage/S = M.get_inactive_hand() + var/obj/item/weapon/storage/S = M.get_inactive_held_item() if(istype(S) && S.can_be_inserted(src,1)) //see if we have box in other hand S.handle_item_insertion(src) - return 1 + return TRUE S = M.get_item_by_slot(slot_belt) if(istype(S) && S.can_be_inserted(src,1)) //else we put in belt S.handle_item_insertion(src) - return 1 + return TRUE S = M.get_item_by_slot(slot_generic_dextrous_storage) //else we put in whatever is in drone storage if(istype(S) && S.can_be_inserted(src,1)) @@ -255,17 +354,17 @@ if(istype(S) && S.can_be_inserted(src,1)) S.handle_item_insertion(src) playsound(src.loc, "rustle", 50, 1, -5) - return 1 + return TRUE M << "You are unable to equip that!" - return 0 + return FALSE /mob/verb/quick_equip() set name = "quick-equip" set hidden = 1 - var/obj/item/I = get_active_hand() + var/obj/item/I = get_active_held_item() if (I) I.equip_to_best_slot(src) @@ -274,4 +373,47 @@ return slot_back /mob/proc/getBeltSlot() - return slot_belt \ No newline at end of file + return slot_belt + + + +//Inventory.dm is -kind of- an ok place for this I guess + +//This is NOT for dismemberment, as the user still technically has 2 "hands" +//This is for multi-handed mobs, such as a human with a third limb installed +//This is a very rare proc to call (besides admin fuckery) so +//any cost it has isn't a worry +/mob/proc/change_number_of_hands(amt) + if(amt < held_items.len) + for(var/i in held_items.len to amt step -1) + unEquip(held_items[i]) + held_items.len = amt + + if(hud_used) + var/style + if(client && client.prefs) + style = ui_style2icon(client.prefs.UI_style) + hud_used.build_hand_slots(style) + + +/mob/living/carbon/human/change_number_of_hands(amt) + var/old_limbs = held_items.len + if(amt < old_limbs) + for(var/i in hand_organs.len to amt step -1) + var/obj/item/bodypart/BP = hand_organs[i] + BP.dismember() + hand_organs[i] = null + hand_organs.len = amt + else if(amt > old_limbs) + hand_organs.len = amt + for(var/i in old_limbs+1 to amt) + var/path = /obj/item/bodypart/l_arm + if(!(i % 2)) + path = /obj/item/bodypart/r_arm + + var/obj/item/bodypart/BP = new path () + BP.owner = src + BP.held_index = i + bodyparts += BP + hand_organs[i] = BP + ..() //Don't redraw hands until we have organs for them diff --git a/code/modules/mob/living/bloodcrawl.dm b/code/modules/mob/living/bloodcrawl.dm index 69e85dfb9ab..fd09b35a440 100644 --- a/code/modules/mob/living/bloodcrawl.dm +++ b/code/modules/mob/living/bloodcrawl.dm @@ -27,7 +27,7 @@ /mob/living/proc/phaseout(obj/effect/decal/cleanable/B) if(iscarbon(src)) var/mob/living/carbon/C = src - if(C.l_hand || C.r_hand) + for(var/obj/item/I in C.held_items) //TODO make it toggleable to either forcedrop the items, or deny //entry when holding them // literally only an option for carbons though diff --git a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm index 1dfe38aaf9d..89acb9ab91c 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm @@ -90,13 +90,15 @@ /mob/living/carbon/alien/humanoid/show_inv(mob/user) user.set_machine(src) - var/dat = {" + var/list/dat = list() + dat += {"
[name] -
-
Left Hand: [l_hand ? l_hand : "Nothing"] -
Right Hand: [r_hand ? r_hand : "Nothing"] -
Empty Pouches"} +
"} + for(var/i in 1 to held_items.len) + var/obj/item/I = get_item_for_held_index(i) + dat += "
[get_held_index_name(i)]:[(I && !(I.flags & ABSTRACT)) ? I : "Empty"]" + dat += "
Empty Pouches" if(handcuffed) dat += "
Handcuffed" @@ -107,7 +109,7 @@

Close "} - user << browse(dat, "window=mob\ref[src];size=325x500") + user << browse(dat.Join(), "window=mob\ref[src];size=325x500") onclose(user, "mob\ref[src]") @@ -155,8 +157,7 @@ return 0.8 /mob/living/carbon/alien/humanoid/alien_evolve(mob/living/carbon/alien/humanoid/new_xeno) - drop_l_hand() - drop_r_hand() + drop_all_held_items() for(var/atom/movable/A in stomach_contents) stomach_contents.Remove(A) new_xeno.stomach_contents.Add(A) diff --git a/code/modules/mob/living/carbon/alien/humanoid/update_icons.dm b/code/modules/mob/living/carbon/alien/humanoid/update_icons.dm index b4e3dc16c8f..9e8475a4e6c 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/update_icons.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/update_icons.dm @@ -68,27 +68,26 @@ apply_overlay(HANDCUFF_LAYER) //Royals have bigger sprites, so inhand things must be handled differently. -/mob/living/carbon/alien/humanoid/royal/update_inv_r_hand() +/mob/living/carbon/alien/humanoid/royal/update_inv_hands() ..() - remove_overlay(R_HAND_LAYER) - if(r_hand) - var/itm_state = r_hand.item_state - if(!itm_state) - itm_state = r_hand.icon_state + remove_overlay(HANDS_LAYER) + var/list/hands = list() - var/image/I = image("icon" = alt_inhands_file , "icon_state"="[itm_state][caste]_r", "layer"=-R_HAND_LAYER) - overlays_standing[R_HAND_LAYER] = I - - apply_overlay(R_HAND_LAYER) - -/mob/living/carbon/alien/humanoid/royal/update_inv_l_hand() - ..() - remove_overlay(L_HAND_LAYER) + var/obj/item/l_hand = get_item_for_held_index(1) if(l_hand) var/itm_state = l_hand.item_state if(!itm_state) itm_state = l_hand.icon_state + var/image/I = image("icon" = alt_inhands_file , "icon_state"="[itm_state][caste]_l", "layer"=-HANDS_LAYER) + hands += I - var/image/I = image("icon" = alt_inhands_file , "icon_state"="[itm_state][caste]_l", "layer"=-L_HAND_LAYER) - overlays_standing[L_HAND_LAYER] = I - apply_overlay(L_HAND_LAYER) \ No newline at end of file + var/obj/item/r_hand = get_item_for_held_index(2) + if(r_hand) + var/itm_state = r_hand.item_state + if(!itm_state) + itm_state = r_hand.icon_state + var/image/I = image("icon" = alt_inhands_file , "icon_state"="[itm_state][caste]_r", "layer"=-HANDS_LAYER) + hands += I + + overlays_standing[HANDS_LAYER] = hands + apply_overlay(HANDS_LAYER) \ 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 9d30f85a661..001fe2d50ce 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -25,7 +25,7 @@ audible_message("You hear something rumbling inside [src]'s stomach...", \ "You hear something rumbling.", 4,\ "Something is rumbling inside your stomach!") - var/obj/item/I = user.get_active_hand() + 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)) @@ -79,38 +79,41 @@ return shock_damage -/mob/living/carbon/swap_hand() - var/obj/item/item_in_hand = src.get_active_hand() +/mob/living/carbon/swap_hand(held_index) + if(!held_index) + held_index = (held_index % held_items.len)+1 + + var/obj/item/item_in_hand = src.get_active_held_item() if(item_in_hand) //this segment checks if the item in your hand is twohanded. if(istype(item_in_hand,/obj/item/weapon/twohanded)) if(item_in_hand:wielded == 1) usr << "Your other hand is too busy holding the [item_in_hand.name]" return - src.hand = !( src.hand ) - if(hud_used && hud_used.inv_slots[slot_l_hand] && hud_used.inv_slots[slot_r_hand]) + var/oindex = active_hand_index + active_hand_index = held_index + if(hud_used) var/obj/screen/inventory/hand/H - H = hud_used.inv_slots[slot_l_hand] - H.update_icon() - H = hud_used.inv_slots[slot_r_hand] - H.update_icon() - /*if (!( src.hand )) - src.hands.setDir(NORTH) - else - src.hands.setDir(SOUTH)*/ - return + H = hud_used.hand_slots["[oindex]"] + if(H) + H.update_icon() + H = hud_used.hand_slots["[held_index]"] + if(H) + H.update_icon() -/mob/living/carbon/activate_hand(selhand) //0 or "r" or "right" for right hand; 1 or "l" or "left" for left hand. + +/mob/living/carbon/activate_hand(selhand) //l/r OR 1-held_items.len + if(!selhand) + selhand = (selhand % held_items.len)+1 if(istext(selhand)) selhand = lowertext(selhand) - if(selhand == "right" || selhand == "r") - selhand = 0 + selhand = 2 if(selhand == "left" || selhand == "l") selhand = 1 - if(selhand != src.hand) - swap_hand() + if(selhand != active_hand_index) + swap_hand(selhand) else mode() // Activate held item @@ -215,7 +218,7 @@ return var/atom/movable/thrown_thing - var/obj/item/I = src.get_active_hand() + var/obj/item/I = src.get_active_held_item() if(!I) if(pulling && isliving(pulling) && grab_state >= GRAB_AGGRESSIVE) @@ -253,9 +256,11 @@ [name]

Head: [(head && !(head.flags&ABSTRACT)) ? head : "Nothing"] -
Mask: [(wear_mask && !(wear_mask.flags&ABSTRACT)) ? wear_mask : "Nothing"] -
Left Hand: [(l_hand && !(l_hand.flags&ABSTRACT)) ? l_hand : "Nothing"] -
Right Hand: [(r_hand && !(r_hand.flags&ABSTRACT)) ? r_hand : "Nothing"]"} +
Mask: [(wear_mask && !(wear_mask.flags&ABSTRACT)) ? wear_mask : "Nothing"]"} + + for(var/i in 1 to held_items.len) + var/obj/item/I = get_item_for_held_index(i) + dat += "
[get_held_index_name(i)]:[(I && !(I.flags & ABSTRACT)) ? I : "Nothing"]" dat += "
Back: [back ? back : "Nothing"]" @@ -733,8 +738,7 @@ //called when we get cuffed/uncuffed /mob/living/carbon/proc/update_handcuffed() if(handcuffed) - drop_r_hand() - drop_l_hand() + drop_all_held_items() stop_pulling() throw_alert("handcuffed", /obj/screen/alert/restrained/handcuffed, new_master = src.handcuffed) else diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index 09153d8cd93..6a82174e41e 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -1,6 +1,6 @@ /mob/living/carbon/hitby(atom/movable/AM, skipcatch, hitpush = 1, blocked = 0) if(!skipcatch) //ugly, but easy - if(in_throw_mode && !get_active_hand()) //empty active hand and we're in throw mode + if(in_throw_mode && !get_active_held_item()) //empty active hand and we're in throw mode if(canmove && !restrained()) if(istype(AM, /obj/item)) var/obj/item/I = AM diff --git a/code/modules/mob/living/carbon/examine.dm b/code/modules/mob/living/carbon/examine.dm index 6842d856b03..1be55c38a12 100644 --- a/code/modules/mob/living/carbon/examine.dm +++ b/code/modules/mob/living/carbon/examine.dm @@ -7,10 +7,14 @@ msg += "It has \icon[src.head] \a [src.head] on its head. \n" if (wear_mask) msg += "It has \icon[src.wear_mask] \a [src.wear_mask] on its face.\n" - if (l_hand) - msg += "It has \icon[src.l_hand] \a [src.l_hand] in its left hand.\n" - if (r_hand) - msg += "It has \icon[src.r_hand] \a [src.r_hand] in its right hand.\n" + + for(var/obj/item/I in held_items) + if(!(I.flags & ABSTRACT)) + if(I.blood_DNA) + msg += "It has \icon[I] [I.gender==PLURAL?"some":"a"] blood-stained [I.name] in its [get_held_index_name(get_held_index_of_item(I))]!\n" + else + msg += "It has \icon[I] \a [I] in its [get_held_index_name(get_held_index_of_item(I))].\n" + if (back) msg += "It has \icon[src.back] \a [src.back] on its back.\n" if (stat == DEAD) diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm index 6d67ed7ad7c..91b85c8a40a 100644 --- a/code/modules/mob/living/carbon/human/emote.dm +++ b/code/modules/mob/living/carbon/human/emote.dm @@ -178,7 +178,7 @@ if ("handshake") m_type = 1 - if (!src.restrained() && !src.r_hand) + if (!src.restrained() && get_empty_held_indexes()) var/mob/M = null if (param) for (var/mob/A in view(1, src)) @@ -188,7 +188,7 @@ if (M == src) M = null if (M) - if (M.canmove && !M.r_hand && !M.restrained()) + if (M.canmove && M.get_empty_held_indexes() && !M.restrained()) message = "[src] shakes hands with [M]." else message = "[src] holds out \his hand to [M]." @@ -298,12 +298,16 @@ if ("signal","signals") if (!src.restrained()) + var/maximum_fingers = 10 + var/full_hands + for(var/obj/item/I in held_items) + full_hands++ + maximum_fingers = (held_items.len-full_hands)*5 var/t1 = round(text2num(param)) if (isnum(t1)) - if (t1 <= 5 && (!src.r_hand || !src.l_hand)) - message = "[src] raises [t1] finger\s." - else if (t1 <= 10 && (!src.r_hand && !src.l_hand)) + if (t1 <= maximum_fingers) message = "[src] raises [t1] finger\s." + m_type = 1 if ("sneeze","sneezes") diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index 4f153b8ad86..6aae26c14c5 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -73,19 +73,13 @@ else msg += "[t_He] [t_has] \icon[back] \a [back] on [t_his] back.\n" - //left hand - if(l_hand && !(l_hand.flags&ABSTRACT)) - if(l_hand.blood_DNA) - msg += "[t_He] [t_is] holding \icon[l_hand] [l_hand.gender==PLURAL?"some":"a"] blood-stained [l_hand.name] in [t_his] left hand!\n" - else - msg += "[t_He] [t_is] holding \icon[l_hand] \a [l_hand] in [t_his] left hand.\n" - - //right hand - if(r_hand && !(r_hand.flags&ABSTRACT)) - if(r_hand.blood_DNA) - msg += "[t_He] [t_is] holding \icon[r_hand] [r_hand.gender==PLURAL?"some":"a"] blood-stained [r_hand.name] in [t_his] right hand!\n" - else - msg += "[t_He] [t_is] holding \icon[r_hand] \a [r_hand] in [t_his] right hand.\n" + //Hands + for(var/obj/item/I in held_items) + if(!(I.flags & ABSTRACT)) + if(I.blood_DNA) + msg += "[t_He] [t_is] holding \icon[I] [I.gender==PLURAL?"some":"a"] blood-stained [I.name] in [t_his] [get_held_index_name(get_held_index_of_item(I))]!\n" + else + msg += "[t_He] [t_is] holding \icon[I] \a [I] in [t_his] [get_held_index_name(get_held_index_of_item(I))].\n" //gloves if(gloves && !(slot_gloves in obscured)) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 41f2caab2dc..baf119af757 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -18,8 +18,15 @@ verbs += /mob/living/proc/lay_down //initialize limbs first - 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) + 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_organs += l_arm + hand_organs += r_arm for(var/X in bodyparts) var/obj/item/bodypart/O = X O.owner = src @@ -193,7 +200,7 @@ ..() /mob/living/carbon/human/attack_ui(slot) - if(!get_bodypart(hand ? "l_arm" : "r_arm")) + if(!has_hand_for_held_index(active_hand_index)) return 0 return ..() @@ -201,11 +208,13 @@ user.set_machine(src) var/has_breathable_mask = istype(wear_mask, /obj/item/clothing/mask) var/list/obscured = check_obscured_slots() + var/list/dat = list() - var/dat = {" - - - "} + dat += "
Left Hand:[(l_hand && !(l_hand.flags&ABSTRACT)) ? l_hand : "Empty"]
Right Hand:[(r_hand && !(r_hand.flags&ABSTRACT)) ? r_hand : "Empty"]
 
" + for(var/i in 1 to held_items.len) + var/obj/item/I = get_item_for_held_index(i) + dat += "" + dat += "" dat += "
[get_held_index_name(i)]:[(I && !(I.flags & ABSTRACT)) ? I : "Empty"]
 
Back:[(back && !(back.flags&ABSTRACT)) ? back : "Empty"]" if(has_breathable_mask && istype(back, /obj/item/weapon/tank)) @@ -279,7 +288,7 @@ "} var/datum/browser/popup = new(user, "mob\ref[src]", "[src]", 440, 510) - popup.set_content(dat) + popup.set_content(dat.Join()) popup.open() // called when something steps onto a human @@ -354,7 +363,7 @@ var/pocket_side = href_list["pockets"] var/pocket_id = (pocket_side == "right" ? slot_r_store : slot_l_store) var/obj/item/pocket_item = (pocket_id == slot_r_store ? r_store : l_store) - var/obj/item/place_item = usr.get_active_hand() // Item to place in the pocket, if it's empty + var/obj/item/place_item = usr.get_active_held_item() // Item to place in the pocket, if it's empty var/delay_denominator = 1 if(pocket_item && !(pocket_item.flags&ABSTRACT)) @@ -653,7 +662,7 @@ if(lasercolor == "b")//Lasertag turrets target the opposing team, how great is that? -Sieve if(istype(wear_suit, /obj/item/clothing/suit/redtag)) threatcount += 4 - if((istype(r_hand,/obj/item/weapon/gun/energy/laser/redtag)) || (istype(l_hand,/obj/item/weapon/gun/energy/laser/redtag))) + if(is_holding_item_of_type(/obj/item/weapon/gun/energy/laser/redtag)) threatcount += 4 if(istype(belt, /obj/item/weapon/gun/energy/laser/redtag)) threatcount += 2 @@ -661,7 +670,7 @@ if(lasercolor == "r") if(istype(wear_suit, /obj/item/clothing/suit/bluetag)) threatcount += 4 - if((istype(r_hand,/obj/item/weapon/gun/energy/laser/bluetag)) || (istype(l_hand,/obj/item/weapon/gun/energy/laser/bluetag))) + if(is_holding_item_of_type(/obj/item/weapon/gun/energy/laser/bluetag)) threatcount += 4 if(istype(belt, /obj/item/weapon/gun/energy/laser/bluetag)) threatcount += 2 @@ -676,10 +685,9 @@ //Check for weapons if(judgebot.weaponscheck) if(!idcard || !(access_weapons in idcard.access)) - if(judgebot.check_for_weapons(l_hand)) - threatcount += 4 - if(judgebot.check_for_weapons(r_hand)) - threatcount += 4 + for(var/obj/item/I in held_items) + if(judgebot.check_for_weapons(I)) + threatcount += 4 if(judgebot.check_for_weapons(belt)) threatcount += 2 @@ -739,8 +747,7 @@ /mob/living/carbon/human/singularity_pull(S, current_size) if(current_size >= STAGE_THREE) - var/list/handlist = list(l_hand, r_hand) - for(var/obj/item/hand in handlist) + for(var/obj/item/hand in held_items) if(prob(current_size * 5) && hand.w_class >= ((11-current_size)/2) && unEquip(hand)) step_towards(hand, src) src << "\The [S] pulls \the [hand] from your grip!" diff --git a/code/modules/mob/living/carbon/human/human_attackalien.dm b/code/modules/mob/living/carbon/human/human_attackalien.dm index 9ab3c8decc9..b407a2881a9 100644 --- a/code/modules/mob/living/carbon/human/human_attackalien.dm +++ b/code/modules/mob/living/carbon/human/human_attackalien.dm @@ -26,7 +26,7 @@ updatehealth() if(M.a_intent == "disarm") //Always drop item in hand, if no item, get stunned instead. - if(get_active_hand() && drop_item()) + if(get_active_held_item() && drop_item()) playsound(loc, 'sound/weapons/slash.ogg', 25, 1, -1) visible_message("[M] disarmed [src]!", \ "[M] disarmed [src]!") diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index edf30eb4b84..f19d0567565 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -72,25 +72,19 @@ if(wear_suit) if(wear_suit.IsReflect(def_zone) == 1) return 1 - if(l_hand) - if(l_hand.IsReflect(def_zone) == 1) - return 1 - if(r_hand) - if(r_hand.IsReflect(def_zone) == 1) + for(var/obj/item/I in held_items) + if(I.IsReflect(def_zone) == 1) return 1 return 0 /mob/living/carbon/human/proc/check_shields(damage = 0, attack_text = "the attack", atom/movable/AM, attack_type = MELEE_ATTACK, armour_penetration = 0) var/block_chance_modifier = round(damage / -3) - if(l_hand && !istype(l_hand, /obj/item/clothing)) - var/final_block_chance = l_hand.block_chance - (Clamp((armour_penetration-l_hand.armour_penetration)/2,0,100)) + block_chance_modifier //So armour piercing blades can still be parried by other blades, for example - if(l_hand.hit_reaction(src, attack_text, final_block_chance, damage, attack_type)) - return 1 - if(r_hand && !istype(r_hand, /obj/item/clothing)) - var/final_block_chance = r_hand.block_chance - (Clamp((armour_penetration-r_hand.armour_penetration)/2,0,100)) + block_chance_modifier //Need to reset the var so it doesn't carry over modifications between attempts - if(r_hand.hit_reaction(src, attack_text, final_block_chance, damage, attack_type)) - return 1 + for(var/obj/item/I in held_items) + if(!istype(I, /obj/item/clothing)) + var/final_block_chance = I.block_chance - (Clamp((armour_penetration-I.armour_penetration)/2,0,100)) + block_chance_modifier //So armour piercing blades can still be parried by other blades, for example + if(I.hit_reaction(src, attack_text, final_block_chance, damage, attack_type)) + return 1 if(wear_suit) var/final_block_chance = wear_suit.block_chance - (Clamp((armour_penetration-wear_suit.armour_penetration)/2,0,100)) + block_chance_modifier if(wear_suit.hit_reaction(src, attack_text, final_block_chance, damage, attack_type)) @@ -262,10 +256,8 @@ inventory_items_to_kill += back if(belt) inventory_items_to_kill += belt - if(r_hand) - inventory_items_to_kill += r_hand - if(l_hand) - inventory_items_to_kill += l_hand + + inventory_items_to_kill += held_items for(var/obj/item/I in inventory_items_to_kill) I.acid_act(acidpwr, acid_volume_left) diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index ada7a5cceaf..b2dee2df5e8 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -53,3 +53,5 @@ 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_organs = 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 4b25bca1238..69863d41b9b 100644 --- a/code/modules/mob/living/carbon/human/human_helpers.dm +++ b/code/modules/mob/living/carbon/human/human_helpers.dm @@ -101,13 +101,15 @@ return 1 /mob/living/carbon/human/abiotic(full_body = 0) - if(full_body && ((l_hand && !( src.l_hand.flags&NODROP )) || (r_hand && !( src.r_hand.flags&NODROP )) || (back && !(back.flags&NODROP)) || (wear_mask && !(wear_mask.flags&NODROP)) || (head && !(head.flags&NODROP)) || (shoes && !(shoes.flags&NODROP)) || (w_uniform && !(w_uniform.flags&NODROP)) || (wear_suit && !(wear_suit.flags&NODROP)) || (glasses && !(glasses.flags&NODROP)) || (ears && !(ears.flags&NODROP)) || (gloves && !(gloves.flags&NODROP)) ) ) - return 1 + var/abiotic_hands = FALSE + for(var/obj/item/I in held_items) + if(!(I.flags & NODROP)) + abiotic_hands = TRUE + break + if(full_body && abiotic_hands && ((back && !(back.flags&NODROP)) || (wear_mask && !(wear_mask.flags&NODROP)) || (head && !(head.flags&NODROP)) || (shoes && !(shoes.flags&NODROP)) || (w_uniform && !(w_uniform.flags&NODROP)) || (wear_suit && !(wear_suit.flags&NODROP)) || (glasses && !(glasses.flags&NODROP)) || (ears && !(ears.flags&NODROP)) || (gloves && !(gloves.flags&NODROP)) ) ) + return TRUE + return abiotic_hands - if( (src.l_hand && !(src.l_hand.flags&NODROP)) || (src.r_hand && !(src.r_hand.flags&NODROP)) ) - return 1 - - return 0 /mob/living/carbon/human/IsAdvancedToolUser() return 1//Humans can use guns and such diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm index 7fbb7e01a83..cf9504df710 100644 --- a/code/modules/mob/living/carbon/human/inventory.dm +++ b/code/modules/mob/living/carbon/human/inventory.dm @@ -22,10 +22,6 @@ return handcuffed if(slot_legcuffed) return legcuffed - if(slot_l_hand) - return l_hand - if(slot_r_hand) - return r_hand if(slot_belt) return belt if(slot_wear_id) @@ -113,7 +109,7 @@ //Item is handled and in slot, valid to call callback, for this proc should always be true if(!not_handled) I.equipped(src, slot) - + return not_handled //For future deeper overrides /mob/living/carbon/human/unEquip(obj/item/I) diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index b4ee5a8844d..32d34cbaf95 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -494,24 +494,14 @@ if(!I.species_exception || !is_type_in_list(src, I.species_exception)) return 0 - var/R = H.has_right_hand() - var/L = H.has_left_hand() var/num_arms = H.get_num_arms() var/num_legs = H.get_num_legs() switch(slot) - if(slot_l_hand) - if(H.l_hand) - return 0 - if(!L) - return 0 - return 1 - if(slot_r_hand) - if(H.r_hand) - return 0 - if(!R) - return 0 - return 1 + if(slot_hands) + if(H.get_empty_held_indexes()) + return TRUE + return FALSE if(slot_wear_mask) if(H.wear_mask) return 0 @@ -881,11 +871,9 @@ . += H.shoes.slowdown if(H.back) . += H.back.slowdown - if(H.l_hand && (H.l_hand.flags & HANDSLOW)) - . += H.l_hand.slowdown - if(H.r_hand && (H.r_hand.flags & HANDSLOW)) - . += H.r_hand.slowdown - + for(var/obj/item/I in H.held_items) + if(I.flags & HANDSLOW) + . += I.slowdown if((H.disabilities & FAT)) . += 1.5 if(H.bodytemperature < BODYTEMP_COLD_DAMAGE_LIMIT) diff --git a/code/modules/mob/living/carbon/human/species_types.dm b/code/modules/mob/living/carbon/human/species_types.dm index 6f7beec0e7d..9677c1b0bfc 100644 --- a/code/modules/mob/living/carbon/human/species_types.dm +++ b/code/modules/mob/living/carbon/human/species_types.dm @@ -676,10 +676,9 @@ . = ..() // Drop items in hands // If you're a zombie lucky enough to have a NODROP item, then it stays. - if(C.unEquip(C.l_hand)) - C.put_in_l_hand(new /obj/item/zombie_hand(C)) - if(C.unEquip(C.r_hand)) - C.put_in_r_hand(new /obj/item/zombie_hand(C)) + for(var/obj/item/I in C.held_items) + C.unEquip(I) + C.put_in_hands(new /obj/item/zombie_hand(C)) // Next, deal with the source of this zombie corruption var/obj/item/organ/body_egg/zombie_infection/infection @@ -689,13 +688,10 @@ /datum/species/zombie/infectious/on_species_loss(mob/living/carbon/C) . = ..() - var/obj/item/zombie_hand/left = C.l_hand - var/obj/item/zombie_hand/right = C.r_hand - // Deletion of the hands is handled in the items dropped() - if(istype(left)) - C.unEquip(left, TRUE) - if(istype(right)) - C.unEquip(right, TRUE) + for(var/obj/item/I in C.held_items) + if(istype(I, /obj/item/zombie_hand)) + C.unEquip(I, TRUE) + // Your skin falls off /datum/species/krokodil_addict @@ -757,7 +753,7 @@ var/global/image/plasmaman_on_fire = image("icon"='icons/mob/OnFire.dmi', "icon_ /datum/species/plasmaman/before_equip_job(datum/job/J, mob/living/carbon/human/H, visualsOnly = FALSE) var/datum/outfit/plasmaman/O = new /datum/outfit/plasmaman H.equipOutfit(O, visualsOnly) - H.internal = H.r_hand + H.internal = H.get_item_for_held_index(2) H.update_internals_hud_icon(1) return 0 @@ -1016,8 +1012,8 @@ SYNDICATE BLACK OPS playsound(H.loc, 'sound/misc/slip.ogg', 50, 1, -3) - H.accident(H.l_hand) - H.accident(H.r_hand) + for(var/obj/item/I in H.held_items) + H.accident(I) var/olddir = H.dir diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 98e5d5d82b6..d2bb7c4b0c2 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -392,8 +392,7 @@ There are several things that need to be remembered: overlays_standing[SUIT_LAYER] = standing if(istype(wear_suit, /obj/item/clothing/suit/straight_jacket)) - drop_l_hand() - drop_r_hand() + drop_all_held_items() update_hair() update_mutant_bodyparts() @@ -548,14 +547,38 @@ generate/load female uniform sprites matching all previously decided variables standing = center_image(standing, isinhands ? inhand_x_dimension : worn_x_dimension, isinhands ? inhand_y_dimension : worn_y_dimension) + //Handle held offsets + var/mob/M = loc + if(istype(M)) + var/list/L = get_held_offsets() + if(L) + standing.pixel_x += L["x"] //+= because of center()ing + standing.pixel_y += L["y"] + standing.alpha = alpha standing.color = color return standing +/obj/item/proc/get_held_offsets() + var/list/L + if(ismob(loc)) + var/mob/M = loc + L = M.get_item_offsets_for_index(M.get_held_index_of_item(src)) + return L +//Can't think of a better way to do this, sadly +/mob/proc/get_item_offsets_for_index(i) + switch(i) + if(3) //odd = left hands + return list("x" = 0, "y" = 16) + if(4) //even = right hands + return list("x" = 0, "y" = 16) + else //No offsets or Unwritten number of hands + return list("x" = 0, "y" = 0) + diff --git a/code/modules/mob/living/carbon/inventory.dm b/code/modules/mob/living/carbon/inventory.dm index 3eb8b085a0f..c4589e1125b 100644 --- a/code/modules/mob/living/carbon/inventory.dm +++ b/code/modules/mob/living/carbon/inventory.dm @@ -1,4 +1,4 @@ -/mob/living/carbon/get_item_by_slot(slot_id) +/mob/living/carbon/get_item_by_slot(slot_id, hand_index) switch(slot_id) if(slot_back) return back @@ -10,10 +10,6 @@ return handcuffed if(slot_legcuffed) return legcuffed - if(slot_l_hand) - return l_hand - if(slot_r_hand) - return r_hand return null @@ -24,10 +20,9 @@ if(!istype(I)) return - if(I == l_hand) - l_hand = null - else if(I == r_hand) - r_hand = null + var/index = get_held_index_of_item(I) + if(index) + held_items[index] = null if(I.pulledby) I.pulledby.stop_pulling() @@ -59,25 +54,22 @@ if(slot_legcuffed) legcuffed = I update_inv_legcuffed() - if(slot_l_hand) - l_hand = I - update_inv_l_hand() - if(slot_r_hand) - r_hand = I - update_inv_r_hand() + if(slot_hands) + put_in_hands(I) + update_inv_hands() if(slot_in_backpack) - if(I == get_active_hand()) + if(I == get_active_held_item()) unEquip(I) I.loc = back else not_handled = TRUE - + //Item has been handled at this point and equipped callback can be safely called //We cannot call it for items that have not been handled as they are not yet correctly //in a slot (handled further down inheritance chain, probably living/carbon/human/equip_to_slot if(!not_handled) I.equipped(src, slot) - + return not_handled /mob/living/carbon/unEquip(obj/item/I) diff --git a/code/modules/mob/living/carbon/monkey/inventory.dm b/code/modules/mob/living/carbon/monkey/inventory.dm index 0d7378a729c..a66f14c1c36 100644 --- a/code/modules/mob/living/carbon/monkey/inventory.dm +++ b/code/modules/mob/living/carbon/monkey/inventory.dm @@ -1,32 +1,28 @@ /mob/living/carbon/monkey/can_equip(obj/item/I, slot, disable_warning = 0) switch(slot) - if(slot_l_hand) - if(l_hand) - return 0 - return 1 - if(slot_r_hand) - if(r_hand) - return 0 - return 1 + if(slot_hands) + if(get_empty_held_indexes()) + return TRUE + return FALSE if(slot_wear_mask) if(wear_mask) - return 0 + return FALSE if( !(I.slot_flags & SLOT_MASK) ) - return 0 - return 1 + return FALSE + return TRUE if(slot_head) if(head) - return 0 + return FALSE if( !(I.slot_flags & SLOT_HEAD) ) - return 0 - return 1 + return FALSE + return TRUE if(slot_back) if(back) - return 0 + return FALSE if( !(I.slot_flags & SLOT_BACK) ) - return 0 - return 1 - return 0 //Unsupported slot + return FALSE + return TRUE + return FALSE //Unsupported slot diff --git a/code/modules/mob/living/carbon/monkey/monkey.dm b/code/modules/mob/living/carbon/monkey/monkey.dm index 344fcf1c7f7..6ae41f3c859 100644 --- a/code/modules/mob/living/carbon/monkey/monkey.dm +++ b/code/modules/mob/living/carbon/monkey/monkey.dm @@ -249,21 +249,20 @@ //Lasertag bullshit if(lasercolor) if(lasercolor == "b")//Lasertag turrets target the opposing team, how great is that? -Sieve - if((istype(r_hand,/obj/item/weapon/gun/energy/laser/redtag)) || (istype(l_hand,/obj/item/weapon/gun/energy/laser/redtag))) + if(is_holding_item_of_type(/obj/item/weapon/gun/energy/laser/redtag)) threatcount += 4 if(lasercolor == "r") - if((istype(r_hand,/obj/item/weapon/gun/energy/laser/bluetag)) || (istype(l_hand,/obj/item/weapon/gun/energy/laser/bluetag))) + if(is_holding_item_of_type(/obj/item/weapon/gun/energy/laser/bluetag)) threatcount += 4 return threatcount //Check for weapons if(judgebot.weaponscheck) - if(judgebot.check_for_weapons(l_hand)) - threatcount += 4 - if(judgebot.check_for_weapons(r_hand)) - threatcount += 4 + for(var/obj/item/I in held_items) + if(judgebot.check_for_weapons(I)) + threatcount += 4 //mindshield implants imply trustworthyness if(isloyal(src)) diff --git a/code/modules/mob/living/carbon/update_icons.dm b/code/modules/mob/living/carbon/update_icons.dm index a89af54cd5d..05f410fafe2 100644 --- a/code/modules/mob/living/carbon/update_icons.dm +++ b/code/modules/mob/living/carbon/update_icons.dm @@ -40,64 +40,43 @@ overlays -= overlays_standing[cache_index] overlays_standing[cache_index] = null -/mob/living/carbon/update_inv_r_hand() - remove_overlay(R_HAND_LAYER) - if (handcuffed) - drop_r_hand() - return - if(r_hand) - if(client && hud_used && hud_used.hud_version != HUD_STYLE_NOHUD) - r_hand.screen_loc = ui_rhand - client.screen += r_hand - if(observers && observers.len) - for(var/M in observers) - var/mob/dead/observe = M - if(observe.client && observe.client.eye == src) - observe.client.screen += r_hand - else - observers -= observe - if(!observers.len) - observers = null - break - - var/t_state = r_hand.item_state - if(!t_state) - t_state = r_hand.icon_state - - var/image/standing = r_hand.build_worn_icon(state = t_state, default_layer = R_HAND_LAYER, default_icon_file = r_hand.righthand_file, isinhands = TRUE) - overlays_standing[R_HAND_LAYER] = standing - - apply_overlay(R_HAND_LAYER) - -/mob/living/carbon/update_inv_l_hand() - remove_overlay(L_HAND_LAYER) +/mob/living/carbon/update_inv_hands() + remove_overlay(HANDS_LAYER) if(handcuffed) - drop_l_hand() + drop_all_held_items() return - if(l_hand) + + var/list/hands = list() + for(var/obj/item/I in held_items) if(client && hud_used && hud_used.hud_version != HUD_STYLE_NOHUD) - l_hand.screen_loc = ui_lhand - client.screen += l_hand + I.screen_loc = ui_hand_position(get_held_index_of_item(I)) + client.screen += I if(observers && observers.len) for(var/M in observers) var/mob/dead/observe = M if(observe.client && observe.client.eye == src) - observe.client.screen += l_hand + observe.client.screen += I else observers -= observe if(!observers.len) observers = null break - var/t_state = l_hand.item_state + var/t_state = I.item_state if(!t_state) - t_state = l_hand.icon_state + t_state = I.icon_state - var/image/standing = l_hand.build_worn_icon(state = t_state, default_layer = L_HAND_LAYER, default_icon_file = l_hand.lefthand_file, isinhands = TRUE) - overlays_standing[L_HAND_LAYER] = standing + var/icon_file = I.lefthand_file + if(get_held_index_of_item(I) % 2 == 0) + icon_file = I.righthand_file + + var/image/standing = I.build_worn_icon(state = t_state, default_layer = HANDS_LAYER, default_icon_file = icon_file, isinhands = TRUE) + hands += standing + + overlays_standing[HANDS_LAYER] = hands + apply_overlay(HANDS_LAYER) - apply_overlay(L_HAND_LAYER) /mob/living/carbon/update_fire(var/fire_icon = "Generic_mob_burning") remove_overlay(FIRE_LAYER) @@ -109,8 +88,7 @@ /mob/living/carbon/regenerate_icons() if(notransform) return 1 - update_inv_r_hand() - update_inv_l_hand() + update_inv_hands() update_inv_handcuffed() update_inv_legcuffed() update_fire() @@ -154,11 +132,10 @@ //update whether handcuffs appears on our hud. /mob/living/carbon/proc/update_hud_handcuffed() if(hud_used) - var/obj/screen/inventory/R = hud_used.inv_slots[slot_r_hand] - var/obj/screen/inventory/L = hud_used.inv_slots[slot_l_hand] - if(R && L) - R.update_icon() - L.update_icon() + for(var/hand in hud_used.hand_slots) + var/obj/screen/inventory/hand/H = hud_used.hand_slots[hand] + if(H) + H.update_icon() //update whether our head item appears on our hud. /mob/living/carbon/proc/update_hud_head(obj/item/I) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 2ac3753795c..daf09118c9d 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -149,10 +149,10 @@ if(!(M.status_flags & CANPUSH)) return 1 //anti-riot equipment is also anti-push - if(M.r_hand && (prob(M.r_hand.block_chance * 2)) && !istype(M.r_hand, /obj/item/clothing)) - return 1 - if(M.l_hand && (prob(M.l_hand.block_chance * 2)) && !istype(M.l_hand, /obj/item/clothing)) - return 1 + for(var/obj/item/I in M.held_items) + if(!istype(M, /obj/item/clothing)) + if(prob(I.block_chance*2)) + return 1 //Called when we bump onto an obj /mob/living/proc/ObjBump(obj/O) @@ -790,7 +790,7 @@ // The src mob is trying to place an item on someone // Override if a certain mob should be behave differently when placing items (can't, for example) /mob/living/stripPanelEquip(obj/item/what, mob/who, where) - what = src.get_active_hand() + what = src.get_active_held_item() if(what && (what.flags & NODROP)) src << "You can't put \the [what.name] on [who], it's stuck to your hand!" return @@ -869,11 +869,10 @@ // What icon do we use for the attack? var/image/I - if(hand && l_hand) // Attacked with item in left hand. - I = image(l_hand.icon, A, l_hand.icon_state, A.layer + 0.1) - else if(!hand && r_hand) // Attacked with item in right hand. - I = image(r_hand.icon, A, r_hand.icon_state, A.layer + 0.1) - else // Attacked with a fist? + var/obj/item/held_item = get_active_held_item() + if(held_item) + I = image(held_item.icon, A, held_item.icon_state, A.layer + 0.1) + else return // Who can see the attack? diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index c61e41458f1..c7543c03ede 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -216,8 +216,7 @@ add_logs(user, src, "grabbed", addition="aggressively") visible_message("[user] has grabbed [src] aggressively!", \ "[user] has grabbed [src] aggressively!") - drop_r_hand() - drop_l_hand() + drop_all_held_items() stop_pulling() if(GRAB_NECK) visible_message("[user] has grabbed [src] by the neck!",\ diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index 7b4793a4cca..75ed1c827d7 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -266,14 +266,15 @@ var/list/crit_allowed_modes = list(MODE_WHISPER,MODE_CHANGELING,MODE_ALIEN) /mob/living/proc/radio(message, message_mode, list/spans) switch(message_mode) if(MODE_R_HAND) - if (r_hand) - r_hand.talk_into(src, message, , spans) - return ITALICS | REDUCE_RANGE - + for(var/obj/item/r_hand in get_held_items_for_side("r", all = TRUE)) + if (r_hand) + r_hand.talk_into(src, message, , spans) + return ITALICS | REDUCE_RANGE if(MODE_L_HAND) - if (l_hand) - l_hand.talk_into(src, message, , spans) - return ITALICS | REDUCE_RANGE + for(var/obj/item/l_hand in get_held_items_for_side("l", all = TRUE)) + if (l_hand) + l_hand.talk_into(src, message, , spans) + return ITALICS | REDUCE_RANGE if(MODE_INTERCOM) for (var/obj/item/device/radio/intercom/I in view(1, null)) diff --git a/code/modules/mob/living/silicon/robot/examine.dm b/code/modules/mob/living/silicon/robot/examine.dm index 81e0365ba06..e4233a06e8d 100644 --- a/code/modules/mob/living/silicon/robot/examine.dm +++ b/code/modules/mob/living/silicon/robot/examine.dm @@ -3,7 +3,7 @@ if(desc) msg += "[desc]\n" - var/obj/act_module = get_active_hand() + var/obj/act_module = get_active_held_item() if(act_module) msg += "It is holding \icon[act_module] \a [act_module].\n" msg += "" diff --git a/code/modules/mob/living/silicon/robot/inventory.dm b/code/modules/mob/living/silicon/robot/inventory.dm index 55276e7807b..71aaaf15df1 100644 --- a/code/modules/mob/living/silicon/robot/inventory.dm +++ b/code/modules/mob/living/silicon/robot/inventory.dm @@ -2,7 +2,7 @@ //as they handle all relevant stuff like adding it to the player's screen and such //Returns the thing in our active hand (whatever is in our active module-slot, in this case) -/mob/living/silicon/robot/get_active_hand() +/mob/living/silicon/robot/get_active_held_item() return module_active diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 810cca481f8..63fd0413051 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -24,6 +24,7 @@ var/obj/screen/inv3 = null var/obj/screen/lamp_button = null var/obj/screen/thruster_button = null + var/obj/screen/hands = null var/shown_robot_modules = 0 //Used to determine whether they have the module menu shown or not var/obj/screen/robot_modules_background @@ -715,7 +716,7 @@ if (M.a_intent =="disarm") if(!(lying)) M.do_attack_animation(src) - if(get_active_hand()) + if(get_active_held_item()) uneq_active() visible_message("[M] disarmed [src]!", \ "[M] has disabled [src]'s active module!") @@ -777,13 +778,13 @@ if(istype(M, /mob/living/carbon/human)) var/mob/living/carbon/human/H = M //if they are holding or wearing a card that has access, that works - if(check_access(H.get_active_hand()) || check_access(H.wear_id)) + if(check_access(H.get_active_held_item()) || check_access(H.wear_id)) return 1 else if(istype(M, /mob/living/carbon/monkey)) var/mob/living/carbon/monkey/george = M //they can only hold things :( - if(istype(george.get_active_hand(), /obj/item)) - return check_access(george.get_active_hand()) + if(istype(george.get_active_held_item(), /obj/item)) + return check_access(george.get_active_held_item()) return 0 /mob/living/silicon/robot/proc/check_access(obj/item/weapon/card/id/I) @@ -1033,7 +1034,7 @@ if(incapacitated()) return - var/obj/item/W = get_active_hand() + var/obj/item/W = get_active_held_item() if(W) W.attack_self(src) diff --git a/code/modules/mob/living/simple_animal/friendly/dog.dm b/code/modules/mob/living/simple_animal/friendly/dog.dm index 0c40e06055e..40bda94fb41 100644 --- a/code/modules/mob/living/simple_animal/friendly/dog.dm +++ b/code/modules/mob/living/simple_animal/friendly/dog.dm @@ -147,14 +147,14 @@ switch(add_to) if("head") - place_on_head(usr.get_active_hand(),usr) + place_on_head(usr.get_active_held_item(),usr) if("back") if(inventory_back) usr << "It's already wearing something!" return else - var/obj/item/item_to_add = usr.get_active_hand() + var/obj/item/item_to_add = usr.get_active_held_item() if(!item_to_add) usr.visible_message("[usr] pets [src].","You rest your hand on [src]'s back for a moment.") 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 3a0ff80b5db..ee5f1893324 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm @@ -144,19 +144,13 @@ /mob/living/simple_animal/drone/examine(mob/user) var/msg = "*---------*\nThis is \icon[src] \a [src]!\n" - //Left hand items - if(l_hand && !(l_hand.flags&ABSTRACT)) - if(l_hand.blood_DNA) - msg += "It is holding \icon[l_hand] [l_hand.gender==PLURAL?"some":"a"] blood-stained [l_hand.name] in its left hand!\n" - else - msg += "It is holding \icon[l_hand] \a [l_hand] in its left hand.\n" - - //Right hand items - if(r_hand && !(r_hand.flags&ABSTRACT)) - if(r_hand.blood_DNA) - msg += "It is holding \icon[r_hand] [r_hand.gender==PLURAL?"some":"a"] blood-stained [r_hand.name] in its right hand!\n" - else - msg += "It is holding \icon[r_hand] \a [r_hand] in its right hand.\n" + //Hands + for(var/obj/item/I in held_items) + if(!(I.flags & ABSTRACT)) + if(I.blood_DNA) + msg += "It has \icon[I] [I.gender==PLURAL?"some":"a"] blood-stained [I.name] in its [get_held_index_name(get_held_index_of_item(I))]!\n" + else + msg += "It has \icon[I] \a [I] in its [get_held_index_name(get_held_index_of_item(I))].\n" //Internal storage if(internal_storage && !(internal_storage.flags&ABSTRACT)) 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 fba7b98f181..b95e845d563 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm @@ -64,7 +64,7 @@ if(stat == DEAD || status_flags & GODMODE) ..() return - if(user.get_active_hand()) + if(user.get_active_held_item()) user << "Your hands are full!" return visible_message("[user] starts picking up [src].", \ @@ -77,8 +77,7 @@ user << "[src] is buckled to [buckled] and cannot be picked up!" return user << "You pick [src] up." - drop_l_hand() - drop_r_hand() + drop_all_held_items() var/obj/item/clothing/head/drone_holder/DH = new /obj/item/clothing/head/drone_holder(src) DH.updateVisualAppearence(src) DH.drone = src diff --git a/code/modules/mob/living/simple_animal/friendly/drone/inventory.dm b/code/modules/mob/living/simple_animal/friendly/drone/inventory.dm index 5fc07a58efe..44838adbe88 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/inventory.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/inventory.dm @@ -49,10 +49,9 @@ if(!istype(I)) return - if(I == l_hand) - l_hand = null - else if(I == r_hand) - r_hand = null + var/index = get_held_index_of_item(I) + if(index) + held_items[index] = null update_inv_hands() if(I.pulledby) diff --git a/code/modules/mob/living/simple_animal/friendly/drone/visuals_icons.dm b/code/modules/mob/living/simple_animal/friendly/drone/visuals_icons.dm index 6ebc4d8066c..ca5456e625c 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/visuals_icons.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/visuals_icons.dm @@ -18,10 +18,13 @@ drone_overlays[cache_index] = null -/mob/living/simple_animal/drone/proc/update_inv_hands() +/mob/living/simple_animal/drone/update_inv_hands() remove_overlay(DRONE_HANDS_LAYER) var/list/hands_overlays = list() + var/obj/item/l_hand = get_item_for_held_index(1) + var/obj/item/r_hand = get_item_for_held_index(2) + var/y_shift = getItemPixelShiftY() if(r_hand) @@ -38,7 +41,7 @@ if(client && hud_used && hud_used.hud_version != HUD_STYLE_NOHUD) r_hand.layer = ABOVE_HUD_LAYER - r_hand.screen_loc = ui_rhand + r_hand.screen_loc = ui_hand_position(get_held_index_of_item(r_hand)) client.screen |= r_hand if(l_hand) @@ -55,7 +58,7 @@ if(client && hud_used && hud_used.hud_version != HUD_STYLE_NOHUD) l_hand.layer = ABOVE_HUD_LAYER - l_hand.screen_loc = ui_lhand + l_hand.screen_loc = ui_hand_position(get_held_index_of_item(l_hand)) client.screen |= l_hand @@ -87,16 +90,6 @@ apply_overlay(DRONE_HEAD_LAYER) - -//These procs serve as redirection so that the drone updates as expected when other things call these procs -/mob/living/simple_animal/drone/update_inv_l_hand() - update_inv_hands() - - -/mob/living/simple_animal/drone/update_inv_r_hand() - update_inv_hands() - - /mob/living/simple_animal/drone/update_inv_wear_mask() update_inv_head() diff --git a/code/modules/mob/living/simple_animal/guardian/guardian.dm b/code/modules/mob/living/simple_animal/guardian/guardian.dm index 96f074c5dcc..407076bbd4c 100644 --- a/code/modules/mob/living/simple_animal/guardian/guardian.dm +++ b/code/modules/mob/living/simple_animal/guardian/guardian.dm @@ -187,8 +187,7 @@ var/global/list/parasites = list() //all currently existing/living guardians return 1 /mob/living/simple_animal/hostile/guardian/death() - drop_l_hand() - drop_r_hand() + drop_all_held_items() ..() if(summoner) summoner << "Your [name] died somehow!" @@ -243,11 +242,10 @@ var/global/list/parasites = list() //all currently existing/living guardians return FALSE . = TRUE - if(I == l_hand) - l_hand = null - else if(I == r_hand) - r_hand = null - update_inv_hands() + var/index = get_held_index_of_item(I) + if(index) + held_items[index] = null + update_inv_hands() if(I.pulledby) I.pulledby.stop_pulling() @@ -267,9 +265,11 @@ var/global/list/parasites = list() //all currently existing/living guardians overlays -= guardian_overlays[cache_index] guardian_overlays[cache_index] = null -/mob/living/simple_animal/hostile/guardian/proc/update_inv_hands() +/mob/living/simple_animal/hostile/guardian/update_inv_hands() remove_overlay(GUARDIAN_HANDS_LAYER) var/list/hands_overlays = list() + var/obj/item/l_hand = get_item_for_held_index(1) + var/obj/item/r_hand = get_item_for_held_index(2) if(r_hand) var/r_state = r_hand.item_state @@ -282,7 +282,7 @@ var/global/list/parasites = list() //all currently existing/living guardians if(client && hud_used && hud_used.hud_version != HUD_STYLE_NOHUD) r_hand.layer = ABOVE_HUD_LAYER - r_hand.screen_loc = ui_rhand + r_hand.screen_loc = ui_hand_position(get_held_index_of_item(r_hand)) client.screen |= r_hand if(l_hand) @@ -296,19 +296,13 @@ var/global/list/parasites = list() //all currently existing/living guardians if(client && hud_used && hud_used.hud_version != HUD_STYLE_NOHUD) l_hand.layer = ABOVE_HUD_LAYER - l_hand.screen_loc = ui_lhand + l_hand.screen_loc = ui_hand_position(get_held_index_of_item(l_hand)) client.screen |= l_hand if(hands_overlays.len) guardian_overlays[GUARDIAN_HANDS_LAYER] = hands_overlays apply_overlay(GUARDIAN_HANDS_LAYER) -/mob/living/simple_animal/hostile/guardian/update_inv_l_hand() - update_inv_hands() - -/mob/living/simple_animal/hostile/guardian/update_inv_r_hand() - update_inv_hands() - /mob/living/simple_animal/hostile/guardian/regenerate_icons() update_inv_hands() diff --git a/code/modules/mob/living/simple_animal/guardian/types/charger.dm b/code/modules/mob/living/simple_animal/guardian/types/charger.dm index fc519b92144..2da19573101 100644 --- a/code/modules/mob/living/simple_animal/guardian/types/charger.dm +++ b/code/modules/mob/living/simple_animal/guardian/types/charger.dm @@ -60,9 +60,7 @@ if(H.check_shields(90, "[name]", src, attack_type = THROWN_PROJECTILE_ATTACK)) blocked = 1 if(!blocked) - - L.drop_r_hand() - L.drop_l_hand() + L.drop_all_held_items() L.visible_message("[src] slams into [L]!", "[src] slams into you!") L.apply_damage(20, BRUTE) playsound(get_turf(L), 'sound/effects/meteorimpact.ogg', 100, 1) diff --git a/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm b/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm index 0d2387ef10b..e86c85e182b 100644 --- a/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm +++ b/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm @@ -28,17 +28,13 @@ if(dextrous) var/msg = "*---------*\nThis is \icon[src] \a [src]!\n" msg += "[desc]\n" - if(l_hand && !(l_hand.flags&ABSTRACT)) - if(l_hand.blood_DNA) - msg += "It is holding \icon[l_hand] [l_hand.gender==PLURAL?"some":"a"] blood-stained [l_hand.name] in its left hand!\n" - else - msg += "It is holding \icon[l_hand] \a [l_hand] in its left hand.\n" - if(r_hand && !(r_hand.flags&ABSTRACT)) - if(r_hand.blood_DNA) - msg += "It is holding \icon[r_hand] [r_hand.gender==PLURAL?"some":"a"] blood-stained [r_hand.name] in its right hand!\n" - else - msg += "It is holding \icon[r_hand] \a [r_hand] in its right hand.\n" + for(var/obj/item/I in held_items) + if(!(I.flags & ABSTRACT)) + if(I.blood_DNA) + msg += "It has \icon[I] [I.gender==PLURAL?"some":"a"] blood-stained [I.name] in its [get_held_index_name(get_held_index_of_item(I))]!\n" + else + msg += "It has \icon[I] \a [I] in its [get_held_index_name(get_held_index_of_item(I))].\n" if(internal_storage && !(internal_storage.flags&ABSTRACT)) if(internal_storage.blood_DNA) @@ -53,14 +49,12 @@ /mob/living/simple_animal/hostile/guardian/dextrous/Recall() if(loc == summoner || cooldown > world.time) return 0 - drop_l_hand() - drop_r_hand() + drop_all_held_items() return ..() //lose items, then return /mob/living/simple_animal/hostile/guardian/dextrous/snapback() if(summoner && !(get_dist(get_turf(summoner),get_turf(src)) <= range)) - drop_l_hand() - drop_r_hand() + drop_all_held_items() ..() //lose items, then return //SLOT HANDLING BULLSHIT FOR INTERNAL STORAGE diff --git a/code/modules/mob/living/simple_animal/parrot.dm b/code/modules/mob/living/simple_animal/parrot.dm index 23455487021..ebe6e335255 100644 --- a/code/modules/mob/living/simple_animal/parrot.dm +++ b/code/modules/mob/living/simple_animal/parrot.dm @@ -224,7 +224,7 @@ //Adding things to inventory else if(href_list["add_inv"]) var/add_to = href_list["add_inv"] - if(!usr.get_active_hand()) + if(!usr.get_active_held_item()) usr << "You have nothing in your hand to put on its [add_to]!" return switch(add_to) @@ -233,7 +233,7 @@ usr << "It's already wearing something!" return else - var/obj/item/item_to_add = usr.get_active_hand() + var/obj/item/item_to_add = usr.get_active_held_item() if(!item_to_add) return @@ -633,8 +633,10 @@ item = I else if(iscarbon(AM)) var/mob/living/carbon/C = AM - if((C.l_hand && C.l_hand.w_class <= 2) || (C.r_hand && C.r_hand.w_class <= 2)) - item = C + for(var/obj/item/I in C.held_items) + if(I.w_class <= 2) + item = I + break if(item) if(!AStar(src, get_turf(item), /turf/proc/Distance_cardinal)) item = null @@ -668,8 +670,9 @@ if(iscarbon(AM)) var/mob/living/carbon/C = AM - if(C.l_hand && C.l_hand.w_class <= 2 || C.r_hand && C.r_hand.w_class <= 2) - return C + for(var/obj/item/I in C.held_items) + if(I.w_class <= 2) + return C return null @@ -719,11 +722,10 @@ var/obj/item/stolen_item = null for(var/mob/living/carbon/C in view(1,src)) - if(C.l_hand && C.l_hand.w_class <= 2) - stolen_item = C.l_hand - - if(C.r_hand && C.r_hand.w_class <= 2) - stolen_item = C.r_hand + for(var/obj/item/I in C.held_items) + if(I.w_class <= 2) + stolen_item = I + break if(stolen_item) C.unEquip(stolen_item) diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 342ed9d9946..e5134bf3398 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -412,8 +412,7 @@ for(var/i in loot) new i(loc) if(dextrous) - unEquip(r_hand) - unEquip(l_hand) + drop_all_held_items() if(!gibbed) if(death_sound) playsound(get_turf(src),death_sound, 200, 1) @@ -545,8 +544,7 @@ /mob/living/simple_animal/update_canmove() if(paralysis || stunned || weakened || stat || resting) - drop_r_hand() - drop_l_hand() + drop_all_held_items() canmove = 0 else if(buckled) canmove = 0 @@ -622,54 +620,63 @@ /mob/living/simple_animal/activate_hand(selhand) if(!dextrous) return ..() + if(!selhand) + selhand = (selhand % held_items.len)+1 if(istext(selhand)) selhand = lowertext(selhand) if(selhand == "right" || selhand == "r") - selhand = 0 + selhand = 2 if(selhand == "left" || selhand == "l") selhand = 1 - if(selhand != src.hand) - swap_hand() + if(selhand != active_hand_index) + swap_hand(selhand) else mode() -/mob/living/simple_animal/swap_hand() +/mob/living/simple_animal/swap_hand(hand_index) if(!dextrous) return ..() - var/obj/item/held_item = get_active_hand() + if(!hand_index) + hand_index = (hand_index % held_items.len)+1 + var/obj/item/held_item = get_active_held_item() if(held_item) if(istype(held_item, /obj/item/weapon/twohanded)) var/obj/item/weapon/twohanded/T = held_item if(T.wielded == 1) usr << "Your other hand is too busy holding the [T.name]." return - hand = !hand - if(hud_used && hud_used.inv_slots[slot_l_hand] && hud_used.inv_slots[slot_r_hand]) + var/oindex = active_hand_index + active_hand_index = hand_index + if(hud_used) var/obj/screen/inventory/hand/H - H = hud_used.inv_slots[slot_l_hand] - H.update_icon() - H = hud_used.inv_slots[slot_r_hand] - H.update_icon() + H = hud_used.hand_slots["[hand_index]"] + if(H) + H.update_icon() + H = hud_used.hand_slots["[oindex]"] + if(H) + H.update_icon() /mob/living/simple_animal/UnarmedAttack(atom/A, proximity) if(!dextrous) return ..() if(!ismob(A)) A.attack_hand(src) - update_hand_icons() + update_inv_hands() /mob/living/simple_animal/put_in_hands(obj/item/I) ..() - update_hand_icons() + update_inv_hands() -/mob/living/simple_animal/proc/update_hand_icons() +/mob/living/simple_animal/update_inv_hands() if(client && hud_used && hud_used.hud_version != HUD_STYLE_NOHUD) + var/obj/item/l_hand = get_item_for_held_index(1) + var/obj/item/r_hand = get_item_for_held_index(2) if(r_hand) r_hand.layer = ABOVE_HUD_LAYER - r_hand.screen_loc = ui_rhand + r_hand.screen_loc = ui_hand_position(get_held_index_of_item(r_hand)) client.screen |= r_hand if(l_hand) l_hand.layer = ABOVE_HUD_LAYER - l_hand.screen_loc = ui_lhand + l_hand.screen_loc = ui_hand_position(get_held_index_of_item(l_hand)) client.screen |= l_hand diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 77dd49ef152..52f58164289 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -178,11 +178,6 @@ var/next_mob_id = 0 return /mob/proc/get_item_by_slot(slot_id) - switch(slot_id) - if(slot_l_hand) - return l_hand - if(slot_r_hand) - return r_hand return null /mob/proc/restrained(ignore_grab) @@ -193,7 +188,7 @@ var/next_mob_id = 0 //This proc is called whenever someone clicks an inventory ui slot. /mob/proc/attack_ui(slot) - var/obj/item/W = get_active_hand() + var/obj/item/W = get_active_held_item() if(istype(W)) if(equip_to_slot_if_possible(W, slot,0,0,0)) @@ -399,16 +394,11 @@ var/next_mob_id = 0 if(incapacitated()) return - if(hand) - var/obj/item/W = l_hand - if (W) - W.attack_self(src) - update_inv_l_hand() - else - var/obj/item/W = r_hand - if (W) - W.attack_self(src) - update_inv_r_hand() + var/obj/item/I = get_active_held_item() + if(I) + I.attack_self(src) + update_inv_hands() + /* /mob/verb/dump_source() @@ -694,8 +684,7 @@ var/next_mob_id = 0 var/has_arms = get_num_arms() var/ignore_legs = get_leg_ignore() if(ko || resting || stunned || chokehold) - drop_r_hand() - drop_l_hand() + drop_all_held_items() unset_machine() if(pulling) stop_pulling() @@ -728,8 +717,7 @@ var/next_mob_id = 0 /mob/proc/fall(forced) - drop_l_hand() - drop_r_hand() + drop_all_held_items() /mob/verb/eastface() set hidden = 1 diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index b361cf48130..ee73870dfd0 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -11,7 +11,6 @@ var/stat = 0 //Whether a mob is alive or dead. TODO: Move this to living - Nodrak - var/obj/screen/hands = null /*A bunch of this stuff really needs to go under their own defines instead of being globally attached to mob. A variable should only be globally attached to turfs/objects/whatever, when it is in fact needed as such. The current method unnecessarily clusters up the variable list, especially for humans (although rearranging won't really clean it up a lot but the difference will be noticable for other mobs). @@ -38,7 +37,6 @@ var/next_move = null var/notransform = null //Carbon - var/hand = null var/eye_blind = 0 //Carbon var/eye_blurry = 0 //Carbon var/ear_deaf = 0 //Carbon @@ -62,7 +60,6 @@ var/timeofdeath = 0//Living var/cpr_time = 1//Carbon - var/bodytemperature = 310.055 //98.7 F var/drowsyness = 0//Carbon var/dizziness = 0//Carbon @@ -79,8 +76,12 @@ var/m_intent = "run"//Living var/lastKnownIP = null var/atom/movable/buckled = null//Living - var/obj/item/l_hand = null//Living - var/obj/item/r_hand = null//Living + + //Hands + var/active_hand_index = 1 + var/list/held_items = list(null, null) //len = number of hands, eg: 2 nulls is 2 empty hands, 1 item and 1 null is 1 full hand and 1 empty hand. + //held_items[active_hand_index] is the actively held item, but please use get_active_held_item() instead, because OOP + var/obj/item/weapon/storage/s_active = null//Carbon var/see_override = 0 //0 for no override, sets see_invisible = see_override in mob life process diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 3e734dee12f..37e60e3b93c 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -273,8 +273,9 @@ It's fairly easy to fix if dealing with single letters but not so much with comp return 0 /mob/proc/abiotic(full_body = 0) - if(l_hand && !l_hand.flags&NODROP || r_hand && !r_hand.flags&NODROP) - return 1 + for(var/obj/item/I in held_items) + if(!(I.flags & NODROP)) + return 1 return 0 //converts intent-strings into numbers and back @@ -384,10 +385,6 @@ It's fairly easy to fix if dealing with single letters but not so much with comp return 1 return 0 -/proc/get_both_hands(mob/living/carbon/M) - var/list/hands = list(M.l_hand, M.r_hand) - return hands - /mob/proc/reagent_check(datum/reagent/R) // utilized in the species code return 1 diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index d7b4a73fc86..5cbc3b370bc 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -55,7 +55,7 @@ /client/Northwest() - if(!usr.get_active_hand()) + if(!usr.get_active_held_item()) usr << "You have nothing to drop in your hand!" return usr.drop_item() diff --git a/code/modules/mob/update_icons.dm b/code/modules/mob/update_icons.dm index b14056f4186..e2cb8d95974 100644 --- a/code/modules/mob/update_icons.dm +++ b/code/modules/mob/update_icons.dm @@ -19,10 +19,7 @@ /mob/proc/update_inv_back() return -/mob/proc/update_inv_l_hand() - return - -/mob/proc/update_inv_r_hand() +/mob/proc/update_inv_hands() return /mob/proc/update_inv_wear_mask() @@ -62,4 +59,4 @@ return /mob/proc/update_inv_ears() - return + return \ No newline at end of file diff --git a/code/modules/modular_computers/computers/item/laptop.dm b/code/modules/modular_computers/computers/item/laptop.dm index 51c91a595ae..946a0c2fe52 100644 --- a/code/modules/modular_computers/computers/item/laptop.dm +++ b/code/modules/modular_computers/computers/item/laptop.dm @@ -55,12 +55,7 @@ if(!M.restrained() && !M.stat) if(!isturf(loc) || !Adjacent(M)) return - - switch(H.slot_id) - if(slot_r_hand) - M.put_in_r_hand(src) - if(slot_l_hand) - M.put_in_l_hand(src) + M.put_in_hand(src, H.held_index) /obj/item/device/modular_computer/laptop/attack_hand(mob/user) if(screen_on && isturf(loc)) diff --git a/code/modules/modular_computers/file_system/program.dm b/code/modules/modular_computers/file_system/program.dm index b8ec10694b8..8ddff02fb64 100644 --- a/code/modules/modular_computers/file_system/program.dm +++ b/code/modules/modular_computers/file_system/program.dm @@ -89,7 +89,7 @@ if(ishuman(user)) var/mob/living/carbon/human/h = user var/obj/item/weapon/card/id/I = h.get_idcard() - var/obj/item/weapon/card/id/C = h.get_active_hand() + var/obj/item/weapon/card/id/C = h.get_active_held_item() if(C) C = C.GetID() if(!(C && istype(C))) diff --git a/code/modules/modular_computers/file_system/programs/card.dm b/code/modules/modular_computers/file_system/programs/card.dm index 1e201da470b..780045d8b73 100644 --- a/code/modules/modular_computers/file_system/programs/card.dm +++ b/code/modules/modular_computers/file_system/programs/card.dm @@ -169,7 +169,7 @@ data_core.manifest_modify(id_card.registered_name, id_card.assignment) computer.proc_eject_id(user, 1) else - var/obj/item/I = usr.get_active_hand() + var/obj/item/I = usr.get_active_held_item() if (istype(I, /obj/item/weapon/card/id)) if(!usr.drop_item()) return @@ -185,7 +185,7 @@ minor = 0 computer.proc_eject_id(user, 2) else - var/obj/item/I = usr.get_active_hand() + var/obj/item/I = usr.get_active_held_item() if (istype(I, /obj/item/weapon/card/id)) if(!usr.drop_item()) return diff --git a/code/modules/ninja/suit/n_suit_verbs/ninja_stars.dm b/code/modules/ninja/suit/n_suit_verbs/ninja_stars.dm index 1fa003fa76a..39e7f5c5701 100644 --- a/code/modules/ninja/suit/n_suit_verbs/ninja_stars.dm +++ b/code/modules/ninja/suit/n_suit_verbs/ninja_stars.dm @@ -9,11 +9,11 @@ if(!ninjacost(10)) var/mob/living/carbon/human/H = affecting - var/slot = H.hand ? slot_l_hand : slot_r_hand - - if(H.equip_to_slot_or_del(new /obj/item/weapon/throwing_star/ninja(H), slot)) + var/obj/item/weapon/throwing_star/ninja/N = new(H) + if(H.put_in_hands(N)) H << "A throwing star has been created in your hand!" - + else + qdel(N) H.throw_mode_on() //So they can quickly throw it. diff --git a/code/modules/paperwork/clipboard.dm b/code/modules/paperwork/clipboard.dm index b58b7d2bfec..f9e66b606ee 100644 --- a/code/modules/paperwork/clipboard.dm +++ b/code/modules/paperwork/clipboard.dm @@ -35,7 +35,7 @@ user << "You clip the paper onto \the [src]." update_icon() else if(toppaper) - toppaper.attackby(usr.get_active_hand(), usr) + toppaper.attackby(user.get_active_held_item(), user) update_icon() @@ -75,8 +75,9 @@ if(href_list["addpen"]) if(!haspen) - if(istype(usr.get_active_hand(), /obj/item/weapon/pen)) - var/obj/item/weapon/pen/W = usr.get_active_hand() + var/obj/item/held = usr.get_active_held_item() + if(istype(held, /obj/item/weapon/pen)) + var/obj/item/weapon/pen/W = held if(!usr.unEquip(W)) return W.loc = src @@ -86,8 +87,8 @@ if(href_list["write"]) var/obj/item/P = locate(href_list["write"]) if(istype(P) && P.loc == src) - if(usr.get_active_hand()) - P.attackby(usr.get_active_hand(), usr) + if(usr.get_active_held_item()) + P.attackby(usr.get_active_held_item(), usr) if(href_list["remove"]) var/obj/item/P = locate(href_list["remove"]) diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm index f6b887f1a2f..87b424efbfb 100644 --- a/code/modules/paperwork/paper.dm +++ b/code/modules/paperwork/paper.dm @@ -257,14 +257,14 @@ var/t = stripped_multiline_input("Enter what you want to write:", "Write") if(!t) return - var/obj/item/i = usr.get_active_hand() //Check to see if he still got that darn pen, also check if he's using a crayon or pen. + var/obj/item/i = usr.get_active_held_item() //Check to see if he still got that darn pen, also check if he's using a crayon or pen. var/iscrayon = 0 if(!istype(i, /obj/item/weapon/pen)) if(!istype(i, /obj/item/toy/crayon)) return iscrayon = 1 - if(!in_range(src, usr) && loc != usr && !istype(loc, /obj/item/weapon/clipboard) && loc.loc != usr && usr.get_active_hand() != i) //Some check to see if he's allowed to write + if(!in_range(src, usr) && loc != usr && !istype(loc, /obj/item/weapon/clipboard) && loc.loc != usr && usr.get_active_held_item() != i) //Some check to see if he's allowed to write return t = parsepencode(t, i, usr, iscrayon) // Encode everything from pencode to html diff --git a/code/modules/paperwork/paper_cutter.dm b/code/modules/paperwork/paper_cutter.dm index 88d12fbd1c5..d147fb85a14 100644 --- a/code/modules/paperwork/paper_cutter.dm +++ b/code/modules/paperwork/paper_cutter.dm @@ -97,11 +97,7 @@ if(!remove_item_from_storage(M)) if(!M.unEquip(src)) return - switch(H.slot_id) - if(slot_r_hand) - M.put_in_r_hand(src) - if(slot_l_hand) - M.put_in_l_hand(src) + M.put_in_hand(src, H.held_index) add_fingerprint(M) diff --git a/code/modules/paperwork/paperbin.dm b/code/modules/paperwork/paperbin.dm index 08f1f9bd76f..f559e5bde98 100644 --- a/code/modules/paperwork/paperbin.dm +++ b/code/modules/paperwork/paperbin.dm @@ -43,11 +43,7 @@ if(!remove_item_from_storage(M)) if(!M.unEquip(src)) return - switch(H.slot_id) - if(slot_r_hand) - M.put_in_r_hand(src) - if(slot_l_hand) - M.put_in_l_hand(src) + M.put_in_hand(src, H.held_index) add_fingerprint(M) diff --git a/code/modules/paperwork/photography.dm b/code/modules/paperwork/photography.dm index 52b39bc2737..4007929f9a9 100644 --- a/code/modules/paperwork/photography.dm +++ b/code/modules/paperwork/photography.dm @@ -245,17 +245,17 @@ else continue - var/holding = null + var/list/holding = list() if(istype(M, /mob/living)) var/mob/living/L = M - if(L.l_hand || L.r_hand) - if(L.l_hand) holding = "They are holding \a [L.l_hand]" - if(L.r_hand) - if(holding) - holding += " and \a [L.r_hand]" - else - holding = "They are holding \a [L.r_hand]" + + for(var/obj/item/I in L.held_items) + if(!holding) + holding += "They are holding \a [I]" + else + holding += " and \a [I]" + holding = holding.Join() if(!mob_detail) mob_detail = "You can see [L] on the photo[L.health < (L.maxHealth * 0.75) ? " - [L] looks hurt":""].[holding ? " [holding]":"."]. " diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm index 68c06b4cb51..9b6f7a79297 100644 --- a/code/modules/power/lighting.dm +++ b/code/modules/power/lighting.dm @@ -439,7 +439,7 @@ else user << "You try to remove the light [fitting], but you burn your hand on it!" - var/obj/item/bodypart/affecting = H.get_bodypart("[user.hand ? "l" : "r" ]_arm") + 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() diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 03df590ca0a..9311a0e0e42 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -125,7 +125,7 @@ user.visible_message("[user] fires [src]!", "You fire [src]!", "You hear a [istype(src, /obj/item/weapon/gun/energy) ? "laser blast" : "gunshot"]!") if(weapon_weight >= WEAPON_MEDIUM) - if(user.get_inactive_hand()) + if(user.get_inactive_held_item()) if(prob(15)) if(user.drop_item()) user.visible_message("[src] flies out of [user]'s hands!", "[src] kicks out of your grip!") @@ -171,7 +171,7 @@ user.drop_item() return - if(weapon_weight == WEAPON_HEAVY && user.get_inactive_hand()) + if(weapon_weight == WEAPON_HEAVY && user.get_inactive_held_item()) user << "You need both hands free to fire \the [src]!" return @@ -207,7 +207,7 @@ obj/item/weapon/gun/proc/newshot() return if(weapon_weight) - if(user.get_inactive_hand()) + if(user.get_inactive_held_item()) recoil = 4 //one-handed kick else recoil = initial(recoil) @@ -218,7 +218,7 @@ obj/item/weapon/gun/proc/newshot() if(!user) break if(!issilicon(user)) - if( i>1 && !(src in get_both_hands(user))) //for burst firing + if( i>1 && !(user.is_holding(src))) //for burst firing break if(chambered) var/sprd = 0 @@ -261,10 +261,7 @@ obj/item/weapon/gun/proc/newshot() semicd = 0 if(user) - if(user.hand) - user.update_inv_l_hand() - else - user.update_inv_r_hand() + user.update_inv_hands() feedback_add_details("gun_fired","[src.type]") /obj/item/weapon/gun/attack(mob/M as mob, mob/user) diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm index 9001dd964d5..f729b9966cf 100644 --- a/code/modules/projectiles/guns/energy.dm +++ b/code/modules/projectiles/guns/energy.dm @@ -139,7 +139,7 @@ if (src.can_shoot()) user.visible_message("[user] is putting the barrel of the [src.name] in \his mouth. It looks like \he's trying to commit suicide.") sleep(25) - if(user.l_hand == src || user.r_hand == src) + if(user.is_holding(src)) user.visible_message("[user] melts \his face off with the [src.name]!") playsound(loc, fire_sound, 50, 1, -1) var/obj/item/ammo_casing/energy/shot = ammo_type[select] diff --git a/code/modules/projectiles/guns/projectile.dm b/code/modules/projectiles/guns/projectile.dm index cd5b9c737ab..594df3bd3b6 100644 --- a/code/modules/projectiles/guns/projectile.dm +++ b/code/modules/projectiles/guns/projectile.dm @@ -98,7 +98,7 @@ if(loc == user) if(suppressed && can_unsuppress) var/obj/item/weapon/suppressor/S = suppressed - if(user.l_hand != src && user.r_hand != src) + if(!user.is_holding(src)) ..() return user << "You unscrew [suppressed] from [src]." @@ -145,7 +145,7 @@ if (src.chambered && src.chambered.BB && !src.chambered.BB.nodamage) user.visible_message("[user] is putting the barrel of the [src.name] in \his mouth. It looks like \he's trying to commit suicide.") sleep(25) - if(user.l_hand == src || user.r_hand == src) + if(user.is_holding(src)) process_fire(user, user, 0, zone_override = "head") user.visible_message("[user] blows \his brains out with the [src.name]!") return(BRUTELOSS) diff --git a/code/modules/projectiles/guns/projectile/laser_gatling.dm b/code/modules/projectiles/guns/projectile/laser_gatling.dm index 35210e78702..43de02219f3 100644 --- a/code/modules/projectiles/guns/projectile/laser_gatling.dm +++ b/code/modules/projectiles/guns/projectile/laser_gatling.dm @@ -69,11 +69,7 @@ var/obj/screen/inventory/hand/H = over_object if(!M.unEquip(src)) return - switch(H.slot_id) - if(slot_r_hand) - M.put_in_r_hand(src) - if(slot_l_hand) - M.put_in_l_hand(src) + M.put_in_hand(src, H.held_index) /obj/item/weapon/minigunpack/update_icon() diff --git a/code/modules/reagents/chemistry/reagents/drug_reagents.dm b/code/modules/reagents/chemistry/reagents/drug_reagents.dm index 8e130dac8ce..939f77472cf 100644 --- a/code/modules/reagents/chemistry/reagents/drug_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drug_reagents.dm @@ -173,13 +173,13 @@ /datum/reagent/drug/methamphetamine/overdose_process(mob/living/M) if(M.canmove && !istype(M.loc, /atom/movable)) - for(var/i = 0, i < 4, i++) + for(var/i in 1 to 4) step(M, pick(cardinal)) if(prob(20)) M.emote("laugh") if(prob(33)) M.visible_message("[M]'s hands flip out and flail everywhere!") - var/obj/item/I = M.get_active_hand() + var/obj/item/I = M.get_active_held_item() if(I) M.drop_item() ..() @@ -252,12 +252,12 @@ /datum/reagent/drug/bath_salts/overdose_process(mob/living/M) M.hallucination += 10 if(M.canmove && !istype(M.loc, /atom/movable)) - for(var/i = 0, i < 8, i++) + for(var/i in 1 to 8) step(M, pick(cardinal)) if(prob(20)) M.emote(pick("twitch","drool","moan")) if(prob(33)) - var/obj/item/I = M.get_active_hand() + var/obj/item/I = M.get_active_held_item() if(I) M.drop_item() ..() diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm index b81330a3099..2461aaba745 100644 --- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm @@ -579,7 +579,7 @@ /datum/reagent/medicine/morphine/overdose_process(mob/living/M) if(prob(33)) - var/obj/item/I = M.get_active_hand() + var/obj/item/I = M.get_active_held_item() if(I) M.drop_item() M.Dizzy(2) @@ -588,7 +588,7 @@ /datum/reagent/medicine/morphine/addiction_act_stage1(mob/living/M) if(prob(33)) - var/obj/item/I = M.get_active_hand() + var/obj/item/I = M.get_active_held_item() if(I) M.drop_item() M.Dizzy(2) @@ -597,7 +597,7 @@ /datum/reagent/medicine/morphine/addiction_act_stage2(mob/living/M) if(prob(33)) - var/obj/item/I = M.get_active_hand() + var/obj/item/I = M.get_active_held_item() if(I) M.drop_item() M.adjustToxLoss(1*REM, 0) @@ -608,7 +608,7 @@ /datum/reagent/medicine/morphine/addiction_act_stage3(mob/living/M) if(prob(33)) - var/obj/item/I = M.get_active_hand() + var/obj/item/I = M.get_active_held_item() if(I) M.drop_item() M.adjustToxLoss(2*REM, 0) @@ -619,7 +619,7 @@ /datum/reagent/medicine/morphine/addiction_act_stage4(mob/living/M) if(prob(33)) - var/obj/item/I = M.get_active_hand() + var/obj/item/I = M.get_active_held_item() if(I) M.drop_item() M.adjustToxLoss(3*REM, 0) diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index 64de2aef123..ace882be22e 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -748,10 +748,8 @@ if(H.lip_style) H.lip_style = null H.update_body() - if(C.r_hand) - C.r_hand.clean_blood() - if(C.l_hand) - C.l_hand.clean_blood() + for(var/obj/item/I in C.held_items) + I.clean_blood() if(C.wear_mask) if(C.wear_mask.clean_blood()) C.update_inv_wear_mask() diff --git a/code/modules/reagents/reagent_containers/blood_pack.dm b/code/modules/reagents/reagent_containers/blood_pack.dm index 08b12d92666..1ed89a74db8 100644 --- a/code/modules/reagents/reagent_containers/blood_pack.dm +++ b/code/modules/reagents/reagent_containers/blood_pack.dm @@ -78,7 +78,7 @@ var/t = stripped_input(user, "What would you like to label the blood pack?", name, null, 53) if(!user.canUseTopic(src)) return - if(user.get_active_hand() != I) + if(user.get_active_held_item() != I) return if(loc != user) return diff --git a/code/modules/spells/spell_types/charge.dm b/code/modules/spells/spell_types/charge.dm index 57088176cb2..ebd4933f58d 100644 --- a/code/modules/spells/spell_types/charge.dm +++ b/code/modules/spells/spell_types/charge.dm @@ -14,7 +14,7 @@ /obj/effect/proc_holder/spell/targeted/charge/cast(list/targets,mob/user = usr) for(var/mob/living/L in targets) - var/list/hand_items = list(L.get_active_hand(),L.get_inactive_hand()) + var/list/hand_items = list(L.get_active_held_item(),L.get_inactive_held_item()) var/charged_item = null var/burnt_out = 0 diff --git a/code/modules/spells/spell_types/lichdom.dm b/code/modules/spells/spell_types/lichdom.dm index 511f446bf4f..9a1d27ebbc7 100644 --- a/code/modules/spells/spell_types/lichdom.dm +++ b/code/modules/spells/spell_types/lichdom.dm @@ -43,7 +43,7 @@ for(var/mob/M in targets) var/list/hand_items = list() if(iscarbon(M)) - hand_items = list(M.get_active_hand(),M.get_inactive_hand()) + hand_items = list(M.get_active_held_item(),M.get_inactive_held_item()) if(marked_item && !stat_allowed) //sanity, shouldn't happen without badminry marked_item = null diff --git a/code/modules/spells/spell_types/summonitem.dm b/code/modules/spells/spell_types/summonitem.dm index e4b02f8b08b..4d6d1b5a3b3 100644 --- a/code/modules/spells/spell_types/summonitem.dm +++ b/code/modules/spells/spell_types/summonitem.dm @@ -17,8 +17,7 @@ /obj/effect/proc_holder/spell/targeted/summonitem/cast(list/targets,mob/user = usr) for(var/mob/living/L in targets) - var/list/hand_items = list(L.get_active_hand(),L.get_inactive_hand()) - var/butterfingers = 0 + var/list/hand_items = list(L.get_active_held_item(),L.get_inactive_held_item()) var/message if(!marked_item) //linking item to the spell @@ -93,17 +92,7 @@ if(item_to_retrive.loc) item_to_retrive.loc.visible_message("The [item_to_retrive.name] suddenly disappears!") - - - if(L.hand) //left active hand - if(!L.equip_to_slot_if_possible(item_to_retrive, slot_l_hand, 0, 1, 1)) - if(!L.equip_to_slot_if_possible(item_to_retrive, slot_r_hand, 0, 1, 1)) - butterfingers = 1 - else //right active hand - if(!L.equip_to_slot_if_possible(item_to_retrive, slot_r_hand, 0, 1, 1)) - if(!L.equip_to_slot_if_possible(item_to_retrive, slot_l_hand, 0, 1, 1)) - butterfingers = 1 - if(butterfingers) + if(!L.put_in_hands(item_to_retrive)) item_to_retrive.loc = L.loc item_to_retrive.loc.visible_message("The [item_to_retrive.name] suddenly appears!") playsound(get_turf(L),"sound/magic/SummonItems_generic.ogg",50,1) diff --git a/code/modules/spells/spell_types/touch_attacks.dm b/code/modules/spells/spell_types/touch_attacks.dm index 51fa79bccc7..7cc593a1d0d 100644 --- a/code/modules/spells/spell_types/touch_attacks.dm +++ b/code/modules/spells/spell_types/touch_attacks.dm @@ -24,17 +24,8 @@ sleep(1) /obj/effect/proc_holder/spell/targeted/touch/proc/ChargeHand(mob/living/carbon/user) - var/hand_handled = 1 attached_hand = new hand_path(src) - if(user.hand) //left active hand - if(!user.equip_to_slot_if_possible(attached_hand, slot_l_hand, 0, 1, 1)) - if(!user.equip_to_slot_if_possible(attached_hand, slot_r_hand, 0, 1, 1)) - hand_handled = 0 - else //right active hand - if(!user.equip_to_slot_if_possible(attached_hand, slot_r_hand, 0, 1, 1)) - if(!user.equip_to_slot_if_possible(attached_hand, slot_l_hand, 0, 1, 1)) - hand_handled = 0 - if(!hand_handled) + if(!user.put_in_hands(attached_hand)) qdel(attached_hand) charge_counter = charge_max attached_hand = null diff --git a/code/modules/surgery/bodyparts/bodyparts.dm b/code/modules/surgery/bodyparts/bodyparts.dm index 42b001e1ddd..74c8679cd78 100644 --- a/code/modules/surgery/bodyparts/bodyparts.dm +++ b/code/modules/surgery/bodyparts/bodyparts.dm @@ -16,6 +16,7 @@ var/burn_dam = 0 var/max_damage = 0 var/list/embedded_objects = list() + var/held_index = 0 //are we a hand? if so, which one! //Coloring and proper item icon update var/skin_tone = "" @@ -287,7 +288,6 @@ return I - /obj/item/bodypart/chest name = "chest" desc = "It's impolite to stare at a person's chest." diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm index 5d2e56971d7..b3a9c4aebb1 100644 --- a/code/modules/surgery/bodyparts/dismemberment.dm +++ b/code/modules/surgery/bodyparts/dismemberment.dm @@ -69,6 +69,10 @@ if(!no_update) update_limb(1) H.bodyparts -= src + if(held_index) + H.unEquip(owner.get_item_for_held_index(held_index), 1) + H.hand_organs[held_index] = null + owner = null for(var/X in H.surgeries) //if we had an ongoing surgery on that limb, we stop it. @@ -138,11 +142,9 @@ H.handcuffed = null H.update_handcuffed() if(H.hud_used) - var/obj/screen/inventory/R = H.hud_used.inv_slots[slot_r_hand] + var/obj/screen/inventory/hand/R = H.hud_used.hand_slots["[held_index]"] if(R) R.update_icon() - if(H.r_hand) - H.unEquip(H.r_hand, 1) if(H.gloves) H.unEquip(H.gloves, 1) H.update_inv_gloves() //to remove the bloody hands overlay @@ -158,11 +160,9 @@ H.handcuffed = null H.update_handcuffed() if(H.hud_used) - var/obj/screen/inventory/L = H.hud_used.inv_slots[slot_l_hand] + var/obj/screen/inventory/hand/L = H.hud_used.hand_slots["[held_index]"] if(L) L.update_icon() - if(H.l_hand) - H.unEquip(H.l_hand, 1) if(H.gloves) H.unEquip(H.gloves, 1) H.update_inv_gloves() //to remove the bloody hands overlay @@ -258,14 +258,14 @@ /obj/item/bodypart/r_arm/attach_limb(mob/living/carbon/human/H, special) ..() if(H.hud_used) - var/obj/screen/inventory/R = H.hud_used.inv_slots[slot_r_hand] + 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/L = H.hud_used.inv_slots[slot_l_hand] + var/obj/screen/inventory/hand/L = H.hud_used.hand_slots["[held_index]"] if(L) L.update_icon() diff --git a/code/modules/surgery/bodyparts/helpers.dm b/code/modules/surgery/bodyparts/helpers.dm index f3e6fdbeabc..8df7c38ed3e 100644 --- a/code/modules/surgery/bodyparts/helpers.dm +++ b/code/modules/surgery/bodyparts/helpers.dm @@ -10,44 +10,36 @@ if(L.body_zone == zone) return L -//Mob has their active hand -/mob/proc/has_active_hand() - return 1 - -/mob/living/carbon/human/has_active_hand() - var/obj/item/bodypart/L - if(hand) - L = get_bodypart("l_arm") - else - L = get_bodypart("r_arm") - if(!L) - return 0 - return 1 +/mob/living/carbon/human/has_hand_for_held_index(i) + if(i) + var/obj/item/bodypart/L = hand_organs[i] + if(L) + return L + return FALSE /mob/proc/has_left_hand() - return 1 + return TRUE /mob/living/carbon/human/has_left_hand() - var/obj/item/bodypart/L - L = get_bodypart("l_arm") - if(!L) - return 0 - return 1 + for(var/obj/item/bodypart/L in hand_organs) + if(!(L.held_index % 2)) + return TRUE + return FALSE /mob/proc/has_right_hand() - return 1 + return TRUE /mob/living/carbon/human/has_right_hand() - var/obj/item/bodypart/L - L = get_bodypart("r_arm") - if(!L) - return 0 - return 1 + for(var/obj/item/bodypart/L in hand_organs) + 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 diff --git a/code/modules/surgery/helpers.dm b/code/modules/surgery/helpers.dm index 79b641e3c06..982ef0d4d40 100644 --- a/code/modules/surgery/helpers.dm +++ b/code/modules/surgery/helpers.dm @@ -76,7 +76,7 @@ user.visible_message("[user] removes the drapes from [M]'s [parse_zone(selected_zone)].", \ "You remove the drapes from [M]'s [parse_zone(selected_zone)].") qdel(current_surgery) - else if(istype(user.get_inactive_hand(), /obj/item/weapon/cautery) && current_surgery.can_cancel) + else if(istype(user.get_inactive_held_item(), /obj/item/weapon/cautery) && current_surgery.can_cancel) M.surgeries -= current_surgery user.visible_message("[user] mends the incision and removes the drapes from [M]'s [parse_zone(selected_zone)].", \ "You mend the incision and remove the drapes from [M]'s [parse_zone(selected_zone)].") diff --git a/code/modules/surgery/implant_removal.dm b/code/modules/surgery/implant_removal.dm index b3ab5a6379c..92704aa1356 100644 --- a/code/modules/surgery/implant_removal.dm +++ b/code/modules/surgery/implant_removal.dm @@ -26,14 +26,11 @@ I.removed(target) var/obj/item/weapon/implantcase/case - - if(istype(user.get_item_by_slot(slot_l_hand), /obj/item/weapon/implantcase)) - case = user.get_item_by_slot(slot_l_hand) - else if(istype(user.get_item_by_slot(slot_r_hand), /obj/item/weapon/implantcase)) - case = user.get_item_by_slot(slot_r_hand) - else + for(var/obj/item/weapon/implantcase/ic in user.held_items) + case = ic + break + if(!case) case = locate(/obj/item/weapon/implantcase) in get_turf(target) - if(case && !case.imp) case.imp = I I.loc = case diff --git a/code/modules/surgery/limb_augmentation.dm b/code/modules/surgery/limb_augmentation.dm index f0a03ea7269..3a00620a172 100644 --- a/code/modules/surgery/limb_augmentation.dm +++ b/code/modules/surgery/limb_augmentation.dm @@ -84,7 +84,7 @@ user.visible_message("[user] begins to install the chainsaw onto [target].", "You begin to install the chainsaw onto [target]...") /datum/surgery_step/chainsaw/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - if(target.l_hand && target.r_hand) + if(!target.get_empty_held_indexes()) user << "You can't fit the chainsaw in while [target]'s hands are full!" return 0 else @@ -104,9 +104,7 @@ requires_organic_bodypart = 0 /datum/surgery/chainsaw_removal/can_start(mob/user, mob/living/carbon/target) - var/list/hands = get_both_hands(target) - var/M = locate(/obj/item/weapon/mounted_chainsaw) in hands - if(M) + if(target.is_holding_item_of_type(/obj/item/weapon/mounted_chainsaw)) return 1//can continue surgery else return 0//surgery will never be available @@ -120,8 +118,7 @@ user.visible_message("[user] begins sawing the chainsaw off of [target]'s arms.", "You begin removing [target]'s chainsaw...") /datum/surgery_step/chainsaw_removal/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - var/list/hands = get_both_hands(target) - for(var/obj/item/weapon/mounted_chainsaw/V in hands) + for(var/obj/item/weapon/mounted_chainsaw/V in target.held_items) target.unEquip(V, 1) user.visible_message("[user] carefully saws [target]'s arm free of the chainsaw.", "You remove the chainsaw.") return 1 diff --git a/code/modules/surgery/organ_manipulation.dm b/code/modules/surgery/organ_manipulation.dm index 8e8eccc4c8a..f2ccd41e270 100644 --- a/code/modules/surgery/organ_manipulation.dm +++ b/code/modules/surgery/organ_manipulation.dm @@ -77,7 +77,7 @@ organs[O.name] = O I = input("Remove which organ?", "Surgery", null, null) as null|anything in organs - if(I && user && target && user.Adjacent(target) && user.get_active_hand() == tool) + if(I && user && target && user.Adjacent(target) && user.get_active_held_item() == tool) I = organs[I] if(!I) return -1 user.visible_message("[user] begins to extract [I] from [target]'s [parse_zone(target_zone)].", diff --git a/code/modules/surgery/organs/augments_arms.dm b/code/modules/surgery/organs/augments_arms.dm index 3cdf2328b19..76220ef9ddc 100644 --- a/code/modules/surgery/organs/augments_arms.dm +++ b/code/modules/surgery/organs/augments_arms.dm @@ -85,8 +85,7 @@ holder.w_class = 5 holder.materials = null - var/arm_slot = (zone == "r_arm" ? slot_r_hand : slot_l_hand) - var/obj/item/arm_item = owner.get_item_by_slot(arm_slot) + var/obj/item/arm_item = owner.get_active_held_item() if(arm_item) if(!owner.unEquip(arm_item)) @@ -95,13 +94,13 @@ else owner << "You drop [arm_item] to activate [src]!" - if(zone == "r_arm" ? !owner.put_in_r_hand(holder) : !owner.put_in_l_hand(holder)) + var/result = (zone == "r_arm" ? owner.put_in_r_hand(holder) : owner.put_in_l_hand(holder)) + if(!result) owner << "Your [src] fails to activate!" return // Activate the hand that now holds our item. - if(zone == "r_arm" ? owner.hand : !owner.hand) - owner.swap_hand() + owner.swap_hand(result)//... or the 1st hand if the index gets lost somehow owner.visible_message("[owner] extends [holder] from \his [zone == "r_arm" ? "right" : "left"] arm.", "You extend [holder] from your [zone == "r_arm" ? "right" : "left"] arm.", @@ -114,8 +113,7 @@ return // You can emag the arm-mounted implant by activating it while holding emag in it's hand. - var/arm_slot = (zone == "r_arm" ? slot_r_hand : slot_l_hand) - if(istype(owner.get_item_by_slot(arm_slot), /obj/item/weapon/card/emag) && emag_act()) + if(istype(owner.get_active_held_item(), /obj/item/weapon/card/emag) && emag_act()) return if(!holder || (holder in src)) diff --git a/code/modules/surgery/organs/augments_internal.dm b/code/modules/surgery/organs/augments_internal.dm index 55a3ff40153..3a5abcf647e 100644 --- a/code/modules/surgery/organs/augments_internal.dm +++ b/code/modules/surgery/organs/augments_internal.dm @@ -41,10 +41,7 @@ name = "anti-drop implant" desc = "This cybernetic brain implant will allow you to force your hand muscles to contract, preventing item dropping. Twitch ear to toggle." var/active = 0 - var/l_hand_ignore = 0 - var/r_hand_ignore = 0 - var/obj/item/l_hand_obj = null - var/obj/item/r_hand_obj = null + var/list/stored_items = list() implant_color = "#DE7E00" slot = "brain_antidrop" origin_tech = "materials=4;programming=5;biotech=4" @@ -53,66 +50,41 @@ /obj/item/organ/cyberimp/brain/anti_drop/ui_action_click() active = !active if(active) - l_hand_obj = owner.l_hand - r_hand_obj = owner.r_hand - if(l_hand_obj) - if(owner.l_hand.flags & NODROP) - l_hand_ignore = 1 - else - owner.l_hand.flags |= NODROP - l_hand_ignore = 0 + for(var/obj/item/I in owner.held_items) + if(!(I.flags & NODROP)) + stored_items += I - if(r_hand_obj) - if(owner.r_hand.flags & NODROP) - r_hand_ignore = 1 - else - owner.r_hand.flags |= NODROP - r_hand_ignore = 0 - - if(!l_hand_obj && !r_hand_obj) + var/list/L = owner.get_empty_held_indexes() + if(L && L.len == owner.held_items.len) owner << "You are not holding any items, your hands relax..." active = 0 + stored_items = list() else - var/msg = 0 - msg += !l_hand_ignore && l_hand_obj ? 1 : 0 - msg += !r_hand_ignore && r_hand_obj ? 2 : 0 - switch(msg) - if(1) - owner << "Your left hand's grip tightens." - if(2) - owner << "Your right hand's grip tightens." - if(3) - owner << "Both of your hand's grips tighten." + for(var/obj/item/I in stored_items) + owner << "Your [owner.get_held_index_name(owner.get_held_index_of_item(I))]'s grip tightens." else release_items() owner << "Your hands relax..." - l_hand_obj = null - r_hand_obj = null + /obj/item/organ/cyberimp/brain/anti_drop/emp_act(severity) if(!owner) return var/range = severity ? 10 : 5 var/atom/A - var/obj/item/L_item = owner.l_hand - var/obj/item/R_item = owner.r_hand - release_items() ..() - if(L_item) + for(var/obj/item/I in stored_items) A = pick(oview(range)) - L_item.throw_at(A, range, 2) - owner << "Your left arm spasms and throws the [L_item.name]!" - if(R_item) - A = pick(oview(range)) - R_item.throw_at(A, range, 2) - owner << "Your right arm spasms and throws the [R_item.name]!" + I.throw_at(A, range, 2) + owner << "Your [owner.get_held_index_name(owner.get_held_index_of_item(I))] spasms and throws the [I.name]!" + stored_items = list() + /obj/item/organ/cyberimp/brain/anti_drop/proc/release_items() - if(!l_hand_ignore && l_hand_obj in owner.contents) - l_hand_obj.flags ^= NODROP - if(!r_hand_ignore && r_hand_obj in owner.contents) - r_hand_obj.flags ^= NODROP + for(var/obj/item/I in stored_items) + I.flags ^= NODROP + /obj/item/organ/cyberimp/brain/anti_drop/Remove(var/mob/living/carbon/M, special = 0) if(active) diff --git a/code/modules/surgery/surgery.dm b/code/modules/surgery/surgery.dm index 1b8616c1fbb..35b15432304 100644 --- a/code/modules/surgery/surgery.dm +++ b/code/modules/surgery/surgery.dm @@ -45,7 +45,7 @@ var/datum/surgery_step/S = get_surgery_step() if(S) - if(S.try_op(user, target, user.zone_selected, user.get_active_hand(), src)) + if(S.try_op(user, target, user.zone_selected, user.get_active_held_item(), src)) return 1 return 0 diff --git a/code/modules/telesci/bscrystal.dm b/code/modules/telesci/bscrystal.dm index e9394c806b2..1077931fcbf 100644 --- a/code/modules/telesci/bscrystal.dm +++ b/code/modules/telesci/bscrystal.dm @@ -62,7 +62,7 @@ return /obj/item/stack/sheet/bluespace_crystal/attack_hand(mob/user) - if (user.get_inactive_hand() == src) + if (user.get_inactive_held_item() == src) if(zero_amount()) // in this case, a sanity check return var/obj/item/weapon/ore/bluespace_crystal/BC = new(src) diff --git a/code/modules/tgui/states/hands.dm b/code/modules/tgui/states/hands.dm index e3e110a2a83..a312bcecddf 100644 --- a/code/modules/tgui/states/hands.dm +++ b/code/modules/tgui/states/hands.dm @@ -15,7 +15,7 @@ return UI_CLOSE /mob/living/hands_can_use_topic(src_object) - if(src_object in get_both_hands(src)) + if(is_holding(src_object)) return UI_INTERACTIVE return UI_CLOSE diff --git a/code/modules/vehicles/vehicle.dm b/code/modules/vehicles/vehicle.dm index 064a6bb1477..9c9a53cd9e1 100644 --- a/code/modules/vehicles/vehicle.dm +++ b/code/modules/vehicles/vehicle.dm @@ -52,7 +52,7 @@ //KEYS /obj/vehicle/proc/keycheck(mob/user) if(keytype) - if(istype(user.l_hand, keytype) || istype(user.r_hand, keytype)) + if(user.is_holding_item_of_type(keytype)) return 1 else return 1 diff --git a/code/modules/zombie/items.dm b/code/modules/zombie/items.dm index 9057dff9547..c2aa26041cd 100644 --- a/code/modules/zombie/items.dm +++ b/code/modules/zombie/items.dm @@ -17,12 +17,12 @@ /obj/item/zombie_hand/equipped(mob/user, slot) . = ..() - switch(slot) - // Yes, these intentionally don't match - if(slot_l_hand) - icon_state = icon_right - if(slot_r_hand) - icon_state = icon_left + //these are intentionally inverted + var/i = user.get_held_index_of_item(src) + if(!(i % 2)) + icon_state = icon_left + else + icon_state = icon_right /obj/item/zombie_hand/afterattack(atom/target, mob/user, proximity_flag) . = ..() From e19b154d00560a153f123dcc0362588f825b0061 Mon Sep 17 00:00:00 2001 From: Remie Richards Date: Fri, 2 Sep 2016 17:57:59 +0100 Subject: [PATCH 02/41] First round of fixes: - Fixed swap hands finding the wrong index - Fixed dual HANDS_LAYER reading for abductors - Fixed old comments - Removed lingering pieces of a previous version - Finish hooking up stripping --- code/__DEFINES/clothing.dm | 4 +-- .../miniantags/abduction/machinery/console.dm | 2 +- code/modules/mob/inventory.dm | 4 --- code/modules/mob/living/carbon/carbon.dm | 4 +-- .../mob/living/carbon/human/update_icons.dm | 2 +- code/modules/mob/living/carbon/inventory.dm | 2 +- code/modules/mob/living/living.dm | 30 ++++++++++++++----- .../mob/living/simple_animal/simple_animal.dm | 4 +-- code/modules/mob/mob.dm | 9 ++++-- 9 files changed, 39 insertions(+), 22 deletions(-) diff --git a/code/__DEFINES/clothing.dm b/code/__DEFINES/clothing.dm index 6fbb8e5d7d1..93b422cdaa8 100644 --- a/code/__DEFINES/clothing.dm +++ b/code/__DEFINES/clothing.dm @@ -17,8 +17,8 @@ #define slot_back 1 #define slot_wear_mask 2 #define slot_handcuffed 3 -#define slot_hands 4 //wherever you provide a slot for hands you provide slot_hands AND a hand index (1 to held_items.len) - //there are various helper procs to find an appropriate index +#define slot_hands 4 //wherever you provide a slot for hands you provide slot_hands + //slot_hands as a slot will pick ANY available hand #define slot_belt 5 #define slot_wear_id 6 #define slot_ears 7 diff --git a/code/game/gamemodes/miniantags/abduction/machinery/console.dm b/code/game/gamemodes/miniantags/abduction/machinery/console.dm index 2aaacb4565f..7dfbb31daca 100644 --- a/code/game/gamemodes/miniantags/abduction/machinery/console.dm +++ b/code/game/gamemodes/miniantags/abduction/machinery/console.dm @@ -173,7 +173,7 @@ entry.name = target.name entry.icon = target.icon entry.icon_state = target.icon_state - entry.overlays = target.get_overlays_copy(list(HANDS_LAYER,HANDS_LAYER)) + entry.overlays = target.get_overlays_copy(list(HANDS_LAYER)) for(var/i=1,i<=disguises.len,i++) var/datum/icon_snapshot/temp = disguises[i] if(temp.name == entry.name) diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm index 8e3cb40fbf4..194dfc4adc9 100644 --- a/code/modules/mob/inventory.dm +++ b/code/modules/mob/inventory.dm @@ -228,10 +228,6 @@ return FALSE -/* -/mob/proc/drop_l_hand() //pending re-implementation -/mob/proc/drop_r_hand() -*/ /mob/proc/drop_all_held_items() if(!loc || !loc.allow_drop()) return diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 001fe2d50ce..8175cf4e862 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -81,7 +81,7 @@ /mob/living/carbon/swap_hand(held_index) if(!held_index) - held_index = (held_index % held_items.len)+1 + held_index = (active_hand_index % held_items.len)+1 var/obj/item/item_in_hand = src.get_active_held_item() if(item_in_hand) //this segment checks if the item in your hand is twohanded. @@ -103,7 +103,7 @@ /mob/living/carbon/activate_hand(selhand) //l/r OR 1-held_items.len if(!selhand) - selhand = (selhand % held_items.len)+1 + selhand = (active_hand_index % held_items.len)+1 if(istext(selhand)) selhand = lowertext(selhand) diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index d2bb7c4b0c2..cb7289a7ef5 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -458,7 +458,7 @@ There are several things that need to be remembered: /mob/living/carbon/human/proc/get_overlays_copy(list/unwantedLayers) var/list/out = new - for(var/i=1;i<=TOTAL_LAYERS;i++) + for(var/i in 1 to TOTAL_LAYERS) if(overlays_standing[i]) if(i in unwantedLayers) continue diff --git a/code/modules/mob/living/carbon/inventory.dm b/code/modules/mob/living/carbon/inventory.dm index c4589e1125b..e44a4bad371 100644 --- a/code/modules/mob/living/carbon/inventory.dm +++ b/code/modules/mob/living/carbon/inventory.dm @@ -1,4 +1,4 @@ -/mob/living/carbon/get_item_by_slot(slot_id, hand_index) +/mob/living/carbon/get_item_by_slot(slot_id) switch(slot_id) if(slot_back) return back diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index daf09118c9d..3e808f12a1c 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -783,9 +783,15 @@ "[src] tries to remove [who]'s [what.name].") what.add_fingerprint(src) if(do_mob(src, who, what.strip_delay)) - if(what && what == who.get_item_by_slot(where) && Adjacent(who)) - who.unEquip(what) - add_logs(src, who, "stripped", addition="of [what]") + if(what && Adjacent(who)) + if(islist(where)) + var/list/L = where + if(what == who.get_item_for_held_index(L[2])) + who.unEquip(what) + add_logs(src, who, "stripped", addition="of [what]") + if(what == who.get_item_by_slot(where)) + who.unEquip(what) + add_logs(src, who, "stripped", addition="of [what]") // The src mob is trying to place an item on someone // Override if a certain mob should be behave differently when placing items (can't, for example) @@ -795,14 +801,24 @@ src << "You can't put \the [what.name] on [who], it's stuck to your hand!" return if(what) - if(!what.mob_can_equip(who, src, where, 1)) - src << "\The [what.name] doesn't fit in that place!" - return + var/list/where_list + if(islist(where)) + where_list = where + if(!what.mob_can_equip(who, src, where[1], 1)) + src << "\The [what.name] doesn't fit in that place!" + return + else + if(!what.mob_can_equip(who, src, where, 1)) + src << "\The [what.name] doesn't fit in that place!" + return visible_message("[src] tries to put [what] on [who].") if(do_mob(src, who, what.put_on_delay)) if(what && Adjacent(who)) unEquip(what) - who.equip_to_slot_if_possible(what, where, 0, 1) + if(where_list) + who.put_in_hand(what, where_list[2]) + else + who.equip_to_slot_if_possible(what, where, 0, 1) add_logs(src, who, "equipped", what) /mob/living/singularity_act() diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index e5134bf3398..7f05844b296 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -621,7 +621,7 @@ if(!dextrous) return ..() if(!selhand) - selhand = (selhand % held_items.len)+1 + selhand = (active_hand_index % held_items.len)+1 if(istext(selhand)) selhand = lowertext(selhand) if(selhand == "right" || selhand == "r") @@ -637,7 +637,7 @@ if(!dextrous) return ..() if(!hand_index) - hand_index = (hand_index % held_items.len)+1 + hand_index = (active_hand_index % held_items.len)+1 var/obj/item/held_item = get_active_held_item() if(held_item) if(istype(held_item, /obj/item/weapon/twohanded)) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 52f58164289..c30137a2dae 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -528,8 +528,13 @@ var/next_mob_id = 0 if(usr.canUseTopic(src, BE_CLOSE, NO_DEXTERY)) if(href_list["item"]) var/slot = text2num(href_list["item"]) - var/obj/item/what = get_item_by_slot(slot) - + var/hand_index = text2num(href_list["hand_index"]) + var/obj/item/what + if(hand_index) + what = get_item_for_held_index(hand_index) + slot = list(slot,hand_index) + else + what = get_item_by_slot(slot) if(what) usr.stripPanelUnequip(what,src,slot) else From 09fee94db5bd0627f522e2a561b09edfa3589bdd Mon Sep 17 00:00:00 2001 From: Remie Richards Date: Sat, 3 Sep 2016 11:40:21 +0100 Subject: [PATCH 03/41] Second round of fixes: - Fixed+Future proofed Mutant Parts Sprites - Fixed Lesser Summon Guns activating the wrong hand - Fixes stacks merge()ing with and consuming themselves --- code/game/objects/items/stacks/stack.dm | 2 ++ .../mob/living/carbon/human/species.dm | 23 +++++++++++++++--- .../spells/spell_types/infinite_guns.dm | 1 + icons/mob/mutant_bodyparts.dmi | Bin 45150 -> 45166 bytes icons/mob/wings.dmi | Bin 13965 -> 13976 bytes 5 files changed, 22 insertions(+), 4 deletions(-) diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index 9f742a68855..2e765ab4e05 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -200,6 +200,8 @@ update_icon() /obj/item/stack/proc/merge(obj/item/stack/S) //Merge src into S, as much as possible + if(S == src) //amusingly this can cause a stack to consume itself, let's not allow that. + return var/transfer = get_amount() if(S.is_cyborg) transfer = min(transfer, round((S.source.max_energy - S.source.energy) / S.cost)) diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 32d34cbaf95..699ded25a7a 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -380,6 +380,8 @@ var/image/I for(var/layer in relevent_layers) + var/layertext = mutant_bodyparts_layertext(layer) + for(var/bodypart in bodyparts_to_add) var/datum/sprite_accessory/S switch(bodypart) @@ -423,9 +425,9 @@ var/icon_string if(S.gender_specific) - icon_string = "[g]_[bodypart]_[S.icon_state]_[layer]" + icon_string = "[g]_[bodypart]_[S.icon_state]_[layertext]" else - icon_string = "m_[bodypart]_[S.icon_state]_[layer]" + icon_string = "m_[bodypart]_[S.icon_state]_[layertext]" I = image("icon" = S.icon, "icon_state" = icon_string, "layer" =- layer) @@ -455,9 +457,9 @@ if(S.hasinner) if(S.gender_specific) - icon_string = "[g]_[bodypart]inner_[S.icon_state]_[layer]" + icon_string = "[g]_[bodypart]inner_[S.icon_state]_[layertext]" else - icon_string = "m_[bodypart]inner_[S.icon_state]_[layer]" + icon_string = "m_[bodypart]inner_[S.icon_state]_[layertext]" I = image("icon" = S.icon, "icon_state" = icon_string, "layer" =- layer) @@ -473,6 +475,19 @@ H.apply_overlay(BODY_ADJ_LAYER) H.apply_overlay(BODY_FRONT_LAYER) + +//This exists so sprite accessories can still be per-layer without having to include that layer's +//number in their sprite name, which causes issues when those numbers change. +/datum/species/proc/mutant_bodyparts_layertext(layer) + switch(layer) + if(BODY_BEHIND_LAYER) + return "BEHIND" + if(BODY_ADJ_LAYER) + return "ADJ" + if(BODY_FRONT_LAYER) + return "FRONT" + + /datum/species/proc/spec_life(mob/living/carbon/human/H) if(NOBREATH in specflags) H.setOxyLoss(0) diff --git a/code/modules/spells/spell_types/infinite_guns.dm b/code/modules/spells/spell_types/infinite_guns.dm index 10b8612c858..d2cc1b32de3 100644 --- a/code/modules/spells/spell_types/infinite_guns.dm +++ b/code/modules/spells/spell_types/infinite_guns.dm @@ -20,3 +20,4 @@ C.drop_item() var/obj/item/weapon/gun/projectile/shotgun/boltaction/enchanted/GUN = new C.put_in_hands(GUN) + C.swap_hand(C.get_held_index_of_item(GUN)) diff --git a/icons/mob/mutant_bodyparts.dmi b/icons/mob/mutant_bodyparts.dmi index 518a57469e54f8ced1d063d6b4213559a3a7d29d..eafe937dc2c0b882ef68637ac0a390ad565ee2e4 100644 GIT binary patch delta 653 zcmV;80&@M{-~#U80+1wsWO`IsbVOxyV{&P5bZKvH004NLy_rvM+AtW#&&j8V+AEs2 zt~>0o!z$Ruq%mpQJu<{3)*L&togu#cLQ*P9TkOYwDh?3H&(Gs0iQl~8y0}|>U9O7x zk7fRkD$S%QJ{7lb-sahkRi+s>-rwX|Ls{LJX+s-g=BAU#wpFC1htKa`fK9NJLgx(J-P_E+YC%4^E` z-U;3Mqiwk(bv;n7H|igUZz(7H!!Wb6SDq=lW1@19c+p#=@h=qgPz8I9jH8e&B5OMm zD&W$*#L`HXl0#z@d>~#SC+o5sOCaU>Wbc|HNu)cQtQ}eKaY!GMtr$icKVeALCO3*e zvVd$2bm;hh*1O3l0?FdBwekVuJGV#98d)Qa?&SE$barz)v#N&2hDuudm`H(MZhOK- ztgT-piNsTQg~MTQLc=vuE;3FHuFv?CC|z!d`&0Y}0DPnhN-!aYiiuE<>d9s9!!tqU n*TrHrAO8*d52_@xv$L)|C;$K;07*naRCt{1-Cu~aj{?uF)Q?7E delta 623 zcmV-#0+9Xg-~!&@0+1wsRC-icbVOxyV{&P5bZKvH004NLwOGq;;~*4Wo3B9aHX2Qn zbTJEWMyWZsZvX-!v4Qc13a4C5akSm3m#4_y+yHde|ZSjN@Q8<2ZDh{T>*?%Qz19GL8eLy|F`RykxG2(T@OU z2h(BzUNYAsHkZ$TD5N>G*8eDombA|J#;dN^zz2ImNb67%`@v}r40}X4)?vn(5gPj3 z9h}k{x9ooq__`+q{GRu{GW;w7y5<)MtVYK>;P(F+h0xO02$akSKq{aY^8rFA!S}lh z07PMD+f&mq_pXfaxEFv+DC(HLQbn9yUm+!Dz(@Sb^4+?BI!$-SwLU?Rhr5wob7Vp& zBOvd}KSfVXAqvYtzW;1iH<)Sac9_^WV$P48X>#(WZ(Ko<6_vPi+RP=w6KcNqLC@bXfH|Eh&HlZ^hMnlz6i73FkPb5 zJ_6~T_t10Ze6we;uihWS@XwS8YGn*}V8q4Aa2xadMJVKvzPxSd=5fFDZ*Bkpc$}TiF$%&k7zWTe|0zD&T@>S( z!IG#E8bRDkp)n2ERFYt?@7hJN9^k<%QK_RgkhP|ljmeJz0(`Y5Hu*015a2svz4flo z5ZH1`xy=>=#n4PXxYV@4*+)~UlQyy-*7=wqz=_>sJJf&c&j delta 167 zcmV;Y09gN+ZH;Y^B!7~6R9JLGWpiV4X>fFDZ*Bkpc$}5au?mAQ6h`4W_bGmKFKvzE zT}q^6&{vRvX%eVWl2Bj2tBauf`QX%eb#FaD^_qS*<*-CB Date: Tue, 6 Sep 2016 01:14:25 -0400 Subject: [PATCH 04/41] Allows multiple items to be inserted into the PDA. --- code/game/objects/items/devices/PDA/PDA.dm | 35 +++++++++++++--------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index a1ded3061aa..dada15e8cbc 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -49,7 +49,7 @@ var/global/list/obj/item/device/pda/PDAs = list() var/obj/item/device/paicard/pai = null // A slot for a personal AI device var/image/photo = null //Scanned photo - + var/list/contained_item = list(/obj/item/weapon/pen, /obj/item/toy/crayon, /obj/item/weapon/lipstick, /obj/item/device/flashlight/pen, /obj/item/clothing/mask/cigarette) /obj/item/device/pda/pickup(mob/user) ..() @@ -700,21 +700,23 @@ var/global/list/obj/item/device/pda/PDAs = list() set name = "Remove Pen" set src in usr + var/obj/item/inserted_item = loc + if(issilicon(usr)) return + var/i if (usr.canUseTopic(src)) - var/obj/item/weapon/pen/O = locate() in src - if(O) - if (istype(loc, /mob)) - var/mob/M = loc - if(M.get_active_hand() == null) - M.put_in_hands(O) - usr << "You remove \the [O] from \the [src]." + for(i = 1, i <= contained_item.len, i++) + inserted_item = locate(contained_item[i]) in src //If items are in the PDA + if(inserted_item) + if (istype(loc, /mob)) + var/mob/M = loc + M.put_in_hands(inserted_item) + usr << "You remove \the [inserted_item] from \the [src]." return - O.loc = get_turf(src) - else - usr << "This PDA does not have a pen in it!" + inserted_item.forceMove() + usr << "This PDA does not have a pen in it!" /obj/item/device/pda/proc/id_check(mob/user, choice as num)//To check for IDs; 1 for in-pda use, 2 for out of pda use. if(choice == 1) @@ -775,9 +777,14 @@ var/global/list/obj/item/device/pda/PDAs = list() pai = C user << "You slot \the [C] into [src]." updateUsrDialog() - else if(istype(C, /obj/item/weapon/pen)) - var/obj/item/weapon/pen/O = locate() in src - if(O) + else if(is_type_in_list(C, contained_item)) + var/obj/item/weapon/pen/Pen = locate() in src + var/obj/item/toy/crayon/Crayon = locate() in src + var/obj/item/weapon/lipstick/Lip = locate() in src + var/obj/item/device/flashlight/pen/Penlight = locate() in src + var/obj/item/clothing/mask/cigarette/Cig = locate() in src + + if(Pen || Crayon || Lip || Penlight || Cig) user << "There is already a pen in \the [src]!" else if(!user.unEquip(C)) From 15e592f28980a651eef6f74131645df2b08f3a6c Mon Sep 17 00:00:00 2001 From: TheCarlSaganExpress Date: Tue, 6 Sep 2016 17:17:06 -0400 Subject: [PATCH 05/41] Changed vars to lowercase --- code/game/objects/items/devices/PDA/PDA.dm | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index dada15e8cbc..0d58ff41c02 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -778,13 +778,13 @@ var/global/list/obj/item/device/pda/PDAs = list() user << "You slot \the [C] into [src]." updateUsrDialog() else if(is_type_in_list(C, contained_item)) - var/obj/item/weapon/pen/Pen = locate() in src - var/obj/item/toy/crayon/Crayon = locate() in src - var/obj/item/weapon/lipstick/Lip = locate() in src - var/obj/item/device/flashlight/pen/Penlight = locate() in src - var/obj/item/clothing/mask/cigarette/Cig = locate() in src + var/obj/item/weapon/pen/pen = locate() in src + var/obj/item/toy/crayon/crayon = locate() in src + var/obj/item/weapon/lipstick/lip = locate() in src + var/obj/item/device/flashlight/pen/penlight = locate() in src + var/obj/item/clothing/mask/cigarette/cig = locate() in src - if(Pen || Crayon || Lip || Penlight || Cig) + if(pen || crayon || lip || penlight || cig) user << "There is already a pen in \the [src]!" else if(!user.unEquip(C)) From de3d4dfa1a8945358745215d4b312a2782ce982f Mon Sep 17 00:00:00 2001 From: TheCarlSaganExpress Date: Wed, 7 Sep 2016 00:44:01 -0400 Subject: [PATCH 06/41] Updates some text --- code/game/objects/items/devices/PDA/PDA.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index 0d58ff41c02..b8ecf78e530 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -785,7 +785,7 @@ var/global/list/obj/item/device/pda/PDAs = list() var/obj/item/clothing/mask/cigarette/cig = locate() in src if(pen || crayon || lip || penlight || cig) - user << "There is already a pen in \the [src]!" + user << "There is already an item in \the [src]!" else if(!user.unEquip(C)) return From cacc091ed3b9913639012f2b4a7a35b23b103062 Mon Sep 17 00:00:00 2001 From: Shadowlight213 Date: Wed, 7 Sep 2016 21:45:14 -0700 Subject: [PATCH 07/41] Makes the surplus crate only give items in the current mode's uplink list Removes sleeping carp scroll from surplus crate --- code/modules/cargo/packs.dm | 4 ++++ code/modules/uplink/uplink_item.dm | 1 + 2 files changed, 5 insertions(+) diff --git a/code/modules/cargo/packs.dm b/code/modules/cargo/packs.dm index ab41d3cae8b..4bdde36e74e 100644 --- a/code/modules/cargo/packs.dm +++ b/code/modules/cargo/packs.dm @@ -156,11 +156,15 @@ datum/supply_pack /datum/supply_pack/emergency/syndicate/fill(obj/structure/closet/crate/C) var/crate_value = 50 + var/list/uplink_items = get_uplink_items() while(crate_value) var/category = pick(uplink_items) var/item = pick(uplink_items[category]) var/datum/uplink_item/I = uplink_items[category][item] + if(I.include_modes.len && !(ticker.mode in I.include_modes)) + continue + if(!I.surplus || prob(100 - I.surplus)) continue if(crate_value < I.cost) diff --git a/code/modules/uplink/uplink_item.dm b/code/modules/uplink/uplink_item.dm index 0df1bc9c0f1..0f6e6bfe59a 100644 --- a/code/modules/uplink/uplink_item.dm +++ b/code/modules/uplink/uplink_item.dm @@ -521,6 +521,7 @@ var/list/uplink_items = list() // Global list so we only initialize this once. deflecting all ranged weapon fire, but you also refuse to use dishonorable ranged weaponry." item = /obj/item/weapon/sleeping_carp_scroll cost = 17 + surplus = 0 exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/gang) /datum/uplink_item/stealthy_weapons/throwingweapons From 5d98fb64d9d55c45a9d7395d5570a9c867c88d9e Mon Sep 17 00:00:00 2001 From: Shadowlight213 Date: Wed, 7 Sep 2016 21:49:54 -0700 Subject: [PATCH 08/41] changes to instead use the argument in get_uplink_items --- code/modules/cargo/packs.dm | 5 +---- code/modules/uplink/uplink_item.dm | 4 ++-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/code/modules/cargo/packs.dm b/code/modules/cargo/packs.dm index 4bdde36e74e..5764994c628 100644 --- a/code/modules/cargo/packs.dm +++ b/code/modules/cargo/packs.dm @@ -156,15 +156,12 @@ datum/supply_pack /datum/supply_pack/emergency/syndicate/fill(obj/structure/closet/crate/C) var/crate_value = 50 - var/list/uplink_items = get_uplink_items() + var/list/uplink_items = get_uplink_items(ticker.mode) while(crate_value) var/category = pick(uplink_items) var/item = pick(uplink_items[category]) var/datum/uplink_item/I = uplink_items[category][item] - if(I.include_modes.len && !(ticker.mode in I.include_modes)) - continue - if(!I.surplus || prob(100 - I.surplus)) continue if(crate_value < I.cost) diff --git a/code/modules/uplink/uplink_item.dm b/code/modules/uplink/uplink_item.dm index 0f6e6bfe59a..75c136ea925 100644 --- a/code/modules/uplink/uplink_item.dm +++ b/code/modules/uplink/uplink_item.dm @@ -1112,7 +1112,7 @@ var/list/uplink_items = list() // Global list so we only initialize this once. exclude_modes = list(/datum/game_mode/nuclear, /datum/game_mode/gang) /datum/uplink_item/badass/surplus/spawn_item(turf/loc, obj/item/device/uplink/U) - var/list/uplink_items = get_uplink_items() + var/list/uplink_items = get_uplink_items(ticker.mode) var/crate_value = 50 var/obj/structure/closet/crate/C = new(loc) @@ -1139,7 +1139,7 @@ var/list/uplink_items = list() // Global list so we only initialize this once. cost = 0 /datum/uplink_item/badass/random/spawn_item(turf/loc, obj/item/device/uplink/U) - var/list/uplink_items = get_uplink_items() + var/list/uplink_items = get_uplink_items(ticker.mode) var/list/possible_items = list() for(var/category in uplink_items) for(var/item in uplink_items[category]) From ab9fa298060126013d922bb063fc98eba63257f1 Mon Sep 17 00:00:00 2001 From: Shadowlight213 Date: Wed, 7 Sep 2016 22:00:44 -0700 Subject: [PATCH 09/41] Fixes assimilate air roundstart runtime --- code/game/turfs/turf.dm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 8e28c283358..38fa21c8333 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -176,6 +176,8 @@ for(var/T in atmos_adjacent_turfs) var/turf/open/S = T + if(!S.air) + return var/list/S_gases = S.air.gases for(var/id in S_gases) total.assert_gas(id) From cdb2c746660f6d6475ad638fb9ccff32cbc28da9 Mon Sep 17 00:00:00 2001 From: Shadowlight213 Date: Wed, 7 Sep 2016 23:12:39 -0700 Subject: [PATCH 10/41] fix --- code/game/turfs/turf.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 38fa21c8333..df8ae690ad0 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -177,7 +177,7 @@ for(var/T in atmos_adjacent_turfs) var/turf/open/S = T if(!S.air) - return + continue var/list/S_gases = S.air.gases for(var/id in S_gases) total.assert_gas(id) From 8533cb12ed8b57d2992a6113f6b09133ba72c5ae Mon Sep 17 00:00:00 2001 From: Joan Lung Date: Thu, 8 Sep 2016 21:58:59 -0400 Subject: [PATCH 11/41] Adds Ash Plants --- code/modules/mining/lavaland/ash_flora.dm | 251 ++++++++++++++++++++++ icons/obj/lavaland/ash_flora.dmi | Bin 0 -> 17343 bytes tgstation.dme | 1 + 3 files changed, 252 insertions(+) create mode 100644 code/modules/mining/lavaland/ash_flora.dm create mode 100644 icons/obj/lavaland/ash_flora.dmi diff --git a/code/modules/mining/lavaland/ash_flora.dm b/code/modules/mining/lavaland/ash_flora.dm new file mode 100644 index 00000000000..4c2d8ea7f3a --- /dev/null +++ b/code/modules/mining/lavaland/ash_flora.dm @@ -0,0 +1,251 @@ +/obj/structure/flora/ash + gender = PLURAL + icon = 'icons/obj/lavaland/ash_flora.dmi' + icon_state = "l_mushroom" + name = "large mushrooms" + desc = "A number of large mushrooms, covered in a faint layer of ash and what can only be spores." + var/harvested_name = "shortened mushrooms" + var/harvested_desc = "Some quickly regrowing mushrooms, formerly known to be quite large." + var/needs_sharp_harvest = TRUE + var/harvest = /obj/item/ash_flora/shavings + var/harvest_amount_low = 1 + var/harvest_amount_high = 3 + var/harvest_time = 60 + var/harvest_message_low = "You pick a mushroom, but fail to collect many shavings from its cap." + var/harvest_message_med = "You pick a mushroom, carefully collecting the shavings from its cap." + var/harvest_message_high = "You harvest and collect shavings from several mushroom caps." + var/harvested = FALSE + var/base_icon + var/regrowth_time_low = 4800 + var/regrowth_time_high = 8400 + +/obj/structure/flora/ash/New() + ..() + base_icon = "[icon_state][rand(1, 4)]" + icon_state = base_icon + if(prob(15)) + harvest(null, TRUE) + +/obj/structure/flora/ash/proc/harvest(user, no_drop) + if(harvested) + return 0 + if(!no_drop) + var/rand_harvested = rand(harvest_amount_low, harvest_amount_high) + if(rand_harvested) + if(user) + var/msg = harvest_message_med + if(rand_harvested == harvest_amount_low) + msg = harvest_message_low + else if(rand_harvested == harvest_amount_high) + msg = harvest_message_high + user << "[msg]" + for(var/i in 1 to rand_harvested) + new harvest(get_turf(src)) + icon_state = "[base_icon]p" + name = harvested_name + desc = harvested_desc + harvested = TRUE + addtimer(src, "regrow", rand(regrowth_time_low, regrowth_time_high)) + return 1 + +/obj/structure/flora/ash/proc/regrow() + icon_state = base_icon + name = initial(name) + desc = initial(desc) + harvested = FALSE + +/obj/structure/flora/ash/attackby(obj/item/weapon/W, mob/user, params) + if(!harvested && needs_sharp_harvest && W.sharpness) + user.visible_message("[user] starts to harvest from [src] with [W].","You begin to harvest from [src] with [W].") + if(do_after(user, harvest_time, target = src)) + harvest(user) + else + ..() + +/obj/structure/flora/ash/attack_hand(mob/user) + if(!harvested && !needs_sharp_harvest) + user.visible_message("[user] starts to harvest from [src].","You begin to harvest from [src].") + if(do_after(user, harvest_time, target = src)) + harvest(user) + else + ..() + +/obj/structure/flora/ash/leaf_shroom + icon_state = "s_mushroom" + name = "leafy mushrooms" + desc = "A number of mushrooms, each of which surrounds a greenish sporangium with a number of leaf-like structures." + harvested_name = "leafless mushrooms" + harvested_desc = "A bunch of formerly-leafed mushrooms, with their sporangiums exposed. Scandalous?" + harvest = /obj/item/ash_flora/mushroom_leaf + needs_sharp_harvest = FALSE + harvest_amount_high = 4 + harvest_time = 20 + harvest_message_low = "You pluck a single, suitable leaf." + harvest_message_med = "You pluck a number of leaves, leaving a few unsuitable ones." + harvest_message_high = "You pluck quite a lot of suitable leaves." + regrowth_time_low = 2400 + regrowth_time_high = 6000 + +/obj/structure/flora/ash/cap_shroom + icon_state = "r_mushroom" + name = "tall mushrooms" + desc = "Several mushrooms, the larger of which have a ring of conks at the midpoint of their stems." + harvested_name = "small mushrooms" + harvested_desc = "Several small mushrooms near the stumps of what likely were larger mushrooms." + harvest = /obj/item/ash_flora/mushroom_cap + harvest_amount_high = 4 + harvest_time = 50 + harvest_message_low = "You slice the cap off of a mushroom." + harvest_message_med = "You slice off a few conks from the larger mushrooms." + harvest_message_high = "You slice off a number of caps and conks from these mushrooms." + regrowth_time_low = 3000 + regrowth_time_high = 5400 + +/obj/structure/flora/ash/stem_shroom + icon_state = "t_mushroom" + name = "numerous mushrooms" + desc = "A large number of mushrooms, some of which have long, fleshy stems." + harvested_name = "tiny mushrooms" + harvested_desc = "A few tiny mushrooms around larger stumps. You can already see them growing back." + harvest = /obj/item/ash_flora/mushroom_stem + harvest_amount_high = 4 + harvest_time = 40 + harvest_message_low = "You pick and slice the cap off of a mushroom, leaving the stem." + harvest_message_med = "You pick and decapitate several mushrooms for their stems." + harvest_message_high = "You acquire a number of stems from these mushrooms." + regrowth_time_low = 3000 + regrowth_time_high = 6000 + +/obj/structure/flora/ash/cacti + icon_state = "cactus" + name = "fruiting cacti" + desc = "Several prickly cacti, brimming with ripe fruit and covered in a thin layer of ash." + harvested_name = "cacti" + harvested_desc = "A bunch of prickly cacti. You can see fruits slowly growing beneath the covering of ash." + harvest = /obj/item/ash_flora/cactus_fruit + needs_sharp_harvest = FALSE + harvest_amount_high = 2 + harvest_time = 10 + harvest_message_low = "You pick a cactus fruit." + harvest_message_med = "You pick several cactus fruit." //shouldn't show up, because you can't get more than two + harvest_message_high = "You pick a pair of cactus fruit." + regrowth_time_low = 4800 + regrowth_time_high = 7200 + +/obj/structure/flora/ash/cacti/Crossed(mob/AM) + if(ishuman(AM) && has_gravity(loc) && prob(70)) + var/mob/living/carbon/human/H = AM + if(!H.shoes && !H.lying) //ouch, my feet. + var/picked_def_zone = pick("l_leg", "r_leg") + var/obj/item/bodypart/O = H.get_bodypart(picked_def_zone) + if(!istype(O) || (PIERCEIMMUNE in H.dna.species.specflags)) + return + H.apply_damage(rand(3, 6), BRUTE, picked_def_zone) + H.Weaken(2) + H.visible_message("[H] steps on a cactus!", \ + "You step on a cactus!") + +/obj/item/ash_flora + name = "mushroom shavings" + desc = "Some shavings from a tall mushroom. With enough, might serve as a bowl." + icon = 'icons/obj/lavaland/ash_flora.dmi' + icon_state = "mushroom_shavings" + w_class = 1 + burn_state = FLAMMABLE + burntime = 30 + var/prepared = FALSE + var/prepared_type = /obj/item/ash_flora/shavings + var/standard_prep = TRUE + +/obj/item/ash_flora/New() + ..() + pixel_x = rand(-4, 4) + pixel_y = rand(-4, 4) + +/obj/item/ash_flora/attackby(obj/item/weapon/W, mob/user, params) + if(!standard_prep || !W.sharpness || !prepare(user)) + ..() + +/obj/item/ash_flora/proc/prepare(mob/user) + if(!prepared) + prepared = TRUE + user << "You prepare [src]." + var/obj/item/ash_flora/A = new prepared_type(get_turf(src)) + if(src in get_both_hands(user)) + user.unEquip(src, TRUE) + user.put_in_hands(A) + qdel(src) + . = 1 + +/obj/item/ash_flora/shavings //for actual crafting + prepared = TRUE + +/obj/item/ash_flora/mushroom_leaf + name = "mushroom leaf" + desc = "A leaflike structure from a mushroom. You should probably wash the ash off." + icon_state = "mushroom_leaf" + standard_prep = FALSE + prepared_type = /obj/item/ash_flora/mushroom_leaf/prepared + +/obj/item/ash_flora/mushroom_leaf/afterattack(atom/target, mob/user, proximity_flag) + if(proximity_flag && (istype(target, /turf/open/floor/plating/ashplanet/wateryrock) || istype(target, /obj/structure/sink))) + prepare(user) + +/obj/item/ash_flora/mushroom_leaf/prepared + name = "washed mushroom leaf" + desc = "A greenish leaflike structure from a mushroom. Kind of like lettuce?" + icon_state = "mushroom_leaf_p" + prepared = TRUE + +/obj/item/ash_flora/mushroom_cap + name = "mushroom cap" + desc = "A mushroom cap. Possibly delicious, at least if you cut it up a bit first." + icon_state = "mushroom_cap" + prepared_type = /obj/item/ash_flora/mushroom_cap/prepared + +/obj/item/ash_flora/mushroom_cap/prepared + name = "sliced mushroom cap" + desc = "A sliced-up mushroom cap, revealing pale yellow innards. It smells faintly salty." + icon_state = "mushroom_cap_p" + prepared = TRUE + +/obj/item/ash_flora/mushroom_stem + name = "mushroom stem" + desc = "A mushroom stem. Slice it up, throw it in a stew." + icon_state = "mushroom_stem" + prepared_type = /obj/item/ash_flora/mushroom_stem/prepared + +/obj/item/ash_flora/mushroom_stem/prepared + name = "sliced mushroom stem" + desc = "A mushroom stem, cut in half to reveal orange flesh. Smells almost like potatos, but with a sour undertone." + icon_state = "mushroom_stem_p" + prepared = TRUE + +/obj/item/ash_flora/cactus_fruit + name = "cactus fruit" + desc = "A cactus fruit covered in a thick, reddish skin. And some ash." + icon_state = "cactus_fruit" + prepared_type = /obj/item/ash_flora/cactus_fruit/prepared + +/obj/item/ash_flora/cactus_fruit/prepared + name = "peeled cactus fruit" + desc = "A cactus fruit with the skin and ash carefully scraped off, revealing a faintly sweet-smelling yellow center." + icon_state = "cactus_fruit_p" + prepared = TRUE + +/obj/item/mushroom_bowl + name = "mushroom bowl" + desc = "A bowl made out of mushrooms. Not food, though it might have contained some at some point." + icon = 'icons/obj/lavaland/ash_flora.dmi' + icon_state = "mushroom_bowl" + w_class = 2 + burn_state = FLAMMABLE + burntime = 40 + +//what you can craft with these things +/datum/crafting_recipe/mushroom_bowl + name = "Mushroom Bowl" + result = /obj/item/mushroom_bowl + reqs = list(/obj/item/ash_flora/shavings = 5) + time = 30 + //category = CAT_PRIMAL //uncomment once ashplanet exists and this wouldn't just take up space fnr diff --git a/icons/obj/lavaland/ash_flora.dmi b/icons/obj/lavaland/ash_flora.dmi new file mode 100644 index 0000000000000000000000000000000000000000..d58541612d2b4a3f6cbba1a6fbcb087e99626657 GIT binary patch literal 17343 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 Date: Thu, 8 Sep 2016 22:03:26 -0400 Subject: [PATCH 12/41] no message --- code/modules/mining/lavaland/ash_flora.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/modules/mining/lavaland/ash_flora.dm b/code/modules/mining/lavaland/ash_flora.dm index 4c2d8ea7f3a..d4b53802f4c 100644 --- a/code/modules/mining/lavaland/ash_flora.dm +++ b/code/modules/mining/lavaland/ash_flora.dm @@ -1,5 +1,6 @@ /obj/structure/flora/ash gender = PLURAL + layer = PROJECTILE_HIT_THRESHHOLD_LAYER //sporangiums up don't shoot icon = 'icons/obj/lavaland/ash_flora.dmi' icon_state = "l_mushroom" name = "large mushrooms" From f145a05f49840fde284462a8fe93d57d59d92dd5 Mon Sep 17 00:00:00 2001 From: Remie Richards Date: Fri, 9 Sep 2016 20:16:40 +0100 Subject: [PATCH 13/41] clarifies bodyparts != organs --- code/modules/mob/inventory.dm | 12 ++++++------ code/modules/mob/living/carbon/human/human.dm | 4 ++-- .../modules/mob/living/carbon/human/human_defines.dm | 2 +- code/modules/surgery/bodyparts/dismemberment.dm | 2 +- code/modules/surgery/bodyparts/helpers.dm | 6 +++--- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm index 194dfc4adc9..ecaf9f1c75f 100644 --- a/code/modules/mob/inventory.dm +++ b/code/modules/mob/inventory.dm @@ -395,13 +395,13 @@ /mob/living/carbon/human/change_number_of_hands(amt) var/old_limbs = held_items.len if(amt < old_limbs) - for(var/i in hand_organs.len to amt step -1) - var/obj/item/bodypart/BP = hand_organs[i] + for(var/i in hand_bodyparts.len to amt step -1) + var/obj/item/bodypart/BP = hand_bodyparts[i] BP.dismember() - hand_organs[i] = null - hand_organs.len = amt + hand_bodyparts[i] = null + hand_bodyparts.len = amt else if(amt > old_limbs) - hand_organs.len = amt + hand_bodyparts.len = amt for(var/i in old_limbs+1 to amt) var/path = /obj/item/bodypart/l_arm if(!(i % 2)) @@ -411,5 +411,5 @@ BP.owner = src BP.held_index = i bodyparts += BP - hand_organs[i] = BP + hand_bodyparts[i] = BP ..() //Don't redraw hands until we have organs for them diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index baf119af757..48f191b4e74 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -25,8 +25,8 @@ bodyparts += r_arm l_arm.held_index = 1 r_arm.held_index = 2 - hand_organs += l_arm - hand_organs += r_arm + hand_bodyparts += l_arm + hand_bodyparts += r_arm for(var/X in bodyparts) var/obj/item/bodypart/O = X O.owner = src diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index b2dee2df5e8..2bccce619fa 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -54,4 +54,4 @@ 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_organs = list() //a collection of arms (or actually whatever the fug /bodyparts you monsters use to wreck my systems) \ No newline at end of file + 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/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm index b3a9c4aebb1..7cacabe3a08 100644 --- a/code/modules/surgery/bodyparts/dismemberment.dm +++ b/code/modules/surgery/bodyparts/dismemberment.dm @@ -71,7 +71,7 @@ H.bodyparts -= src if(held_index) H.unEquip(owner.get_item_for_held_index(held_index), 1) - H.hand_organs[held_index] = null + H.hand_bodyparts[held_index] = null owner = null diff --git a/code/modules/surgery/bodyparts/helpers.dm b/code/modules/surgery/bodyparts/helpers.dm index 8df7c38ed3e..4ceec195c09 100644 --- a/code/modules/surgery/bodyparts/helpers.dm +++ b/code/modules/surgery/bodyparts/helpers.dm @@ -12,7 +12,7 @@ /mob/living/carbon/human/has_hand_for_held_index(i) if(i) - var/obj/item/bodypart/L = hand_organs[i] + var/obj/item/bodypart/L = hand_bodyparts[i] if(L) return L return FALSE @@ -21,7 +21,7 @@ return TRUE /mob/living/carbon/human/has_left_hand() - for(var/obj/item/bodypart/L in hand_organs) + for(var/obj/item/bodypart/L in hand_bodyparts) if(!(L.held_index % 2)) return TRUE return FALSE @@ -30,7 +30,7 @@ return TRUE /mob/living/carbon/human/has_right_hand() - for(var/obj/item/bodypart/L in hand_organs) + for(var/obj/item/bodypart/L in hand_bodyparts) if(L.held_index % 2) return TRUE return FALSE From e1299a401bcc5f5a3e04932536e7bdce6cde55ed Mon Sep 17 00:00:00 2001 From: TheCarlSaganExpress Date: Fri, 9 Sep 2016 16:10:56 -0400 Subject: [PATCH 14/41] Suggested code by Phil. --- code/game/objects/items/devices/PDA/PDA.dm | 33 +++++++++------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index dada15e8cbc..91274eee775 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -49,7 +49,9 @@ var/global/list/obj/item/device/pda/PDAs = list() var/obj/item/device/paicard/pai = null // A slot for a personal AI device var/image/photo = null //Scanned photo + var/list/contained_item = list(/obj/item/weapon/pen, /obj/item/toy/crayon, /obj/item/weapon/lipstick, /obj/item/device/flashlight/pen, /obj/item/clothing/mask/cigarette) + var/obj/item/inserted_item /obj/item/device/pda/pickup(mob/user) ..() @@ -700,23 +702,21 @@ var/global/list/obj/item/device/pda/PDAs = list() set name = "Remove Pen" set src in usr - var/obj/item/inserted_item = loc - if(issilicon(usr)) return + var/obj/item/weapon/pen/O = locate() in src //Needed, otherwise cannot remove default pen in PDA - var/i if (usr.canUseTopic(src)) - for(i = 1, i <= contained_item.len, i++) - inserted_item = locate(contained_item[i]) in src //If items are in the PDA - if(inserted_item) - if (istype(loc, /mob)) + if(is_type_in_list(inserted_item, contained_item) || O) + if(inserted_item || O) + if(istype(loc, /mob)) var/mob/M = loc - M.put_in_hands(inserted_item) - usr << "You remove \the [inserted_item] from \the [src]." + M.put_in_hands(inserted_item || O) + usr << "You remove \the [inserted_item || O] from \the [src]." + inserted_item = null return inserted_item.forceMove() - usr << "This PDA does not have a pen in it!" + usr << "This PDA does not have a pen in it!" /obj/item/device/pda/proc/id_check(mob/user, choice as num)//To check for IDs; 1 for in-pda use, 2 for out of pda use. if(choice == 1) @@ -777,20 +777,15 @@ var/global/list/obj/item/device/pda/PDAs = list() pai = C user << "You slot \the [C] into [src]." updateUsrDialog() - else if(is_type_in_list(C, contained_item)) - var/obj/item/weapon/pen/Pen = locate() in src - var/obj/item/toy/crayon/Crayon = locate() in src - var/obj/item/weapon/lipstick/Lip = locate() in src - var/obj/item/device/flashlight/pen/Penlight = locate() in src - var/obj/item/clothing/mask/cigarette/Cig = locate() in src - - if(Pen || Crayon || Lip || Penlight || Cig) - user << "There is already a pen in \the [src]!" + else if(is_type_in_list(C, contained_item)) //Checks if there is a pen + if(inserted_item) + user << "There is already an item in \the [src]!" else if(!user.unEquip(C)) return C.loc = src user << "You slide \the [C] into \the [src]." + inserted_item = C else if(istype(C, /obj/item/weapon/photo)) var/obj/item/weapon/photo/P = C photo = P.img From f90f7517657b0026f825e7f96f94e9a1e1d00c05 Mon Sep 17 00:00:00 2001 From: TheCarlSaganExpress Date: Fri, 9 Sep 2016 16:38:10 -0400 Subject: [PATCH 15/41] Changes to New() --- code/game/objects/items/devices/PDA/PDA.dm | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index 57b8a96db4a..e2933f761fc 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -51,7 +51,7 @@ var/global/list/obj/item/device/pda/PDAs = list() var/image/photo = null //Scanned photo var/list/contained_item = list(/obj/item/weapon/pen, /obj/item/toy/crayon, /obj/item/weapon/lipstick, /obj/item/device/flashlight/pen, /obj/item/clothing/mask/cigarette) - var/obj/item/inserted_item + var/obj/item/inserted_item //Used for pen, crayon, and lipstick insertion/removal /obj/item/device/pda/pickup(mob/user) ..() @@ -76,7 +76,7 @@ var/global/list/obj/item/device/pda/PDAs = list() PDAs += src if(default_cartridge) cartridge = new default_cartridge(src) - new /obj/item/weapon/pen(src) + inserted_item = new /obj/item/weapon/pen(src) /obj/item/device/pda/proc/update_label() name = "PDA-[owner] ([ownjob])" //Name generalisation @@ -704,15 +704,14 @@ var/global/list/obj/item/device/pda/PDAs = list() if(issilicon(usr)) return - var/obj/item/weapon/pen/O = locate() in src //Needed, otherwise cannot remove default pen in PDA if (usr.canUseTopic(src)) - if(is_type_in_list(inserted_item, contained_item) || O) - if(inserted_item || O) + if(is_type_in_list(inserted_item, contained_item)) + if(inserted_item) if(istype(loc, /mob)) var/mob/M = loc - M.put_in_hands(inserted_item || O) - usr << "You remove \the [inserted_item || O] from \the [src]." + M.put_in_hands(inserted_item) + usr << "You remove \the [inserted_item] from \the [src]." inserted_item = null return inserted_item.forceMove() From 31a73e96f311ea07f2c73d16eb7a5a705bbfce4d Mon Sep 17 00:00:00 2001 From: TheCarlSaganExpress Date: Fri, 9 Sep 2016 16:44:32 -0400 Subject: [PATCH 16/41] Hopefully this fixes my fuckup --- code/game/objects/items/devices/PDA/PDA.dm | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index e2933f761fc..f673bc101dc 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -776,19 +776,8 @@ var/global/list/obj/item/device/pda/PDAs = list() pai = C user << "You slot \the [C] into [src]." updateUsrDialog() -<<<<<<< HEAD else if(is_type_in_list(C, contained_item)) //Checks if there is a pen if(inserted_item) -======= - else if(is_type_in_list(C, contained_item)) - var/obj/item/weapon/pen/pen = locate() in src - var/obj/item/toy/crayon/crayon = locate() in src - var/obj/item/weapon/lipstick/lip = locate() in src - var/obj/item/device/flashlight/pen/penlight = locate() in src - var/obj/item/clothing/mask/cigarette/cig = locate() in src - - if(pen || crayon || lip || penlight || cig) ->>>>>>> de3d4dfa1a8945358745215d4b312a2782ce982f user << "There is already an item in \the [src]!" else if(!user.unEquip(C)) From 277069a06fe10661b376354aac644a428cb8db1f Mon Sep 17 00:00:00 2001 From: Leo Date: Fri, 9 Sep 2016 23:37:09 -0300 Subject: [PATCH 17/41] Changes 'Notes Memory' back to just 'Notes' again --- code/modules/mob/mob.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 2a98cae186b..75cc53815d6 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -422,7 +422,7 @@ var/next_mob_id = 0 */ /mob/verb/memory() - set name = "Notes Memory" + set name = "Notes" set category = "IC" set desc = "View your character's notes memory." if(mind) From e1c7d0d57443d26fc72d43513bab3bb40d6be304 Mon Sep 17 00:00:00 2001 From: Joan Lung Date: Sat, 10 Sep 2016 09:29:14 -0400 Subject: [PATCH 18/41] you missssed oooone --- code/modules/mining/lavaland/ash_flora.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/mining/lavaland/ash_flora.dm b/code/modules/mining/lavaland/ash_flora.dm index d4b53802f4c..2d831483647 100644 --- a/code/modules/mining/lavaland/ash_flora.dm +++ b/code/modules/mining/lavaland/ash_flora.dm @@ -61,7 +61,7 @@ if(do_after(user, harvest_time, target = src)) harvest(user) else - ..() + return ..() /obj/structure/flora/ash/attack_hand(mob/user) if(!harvested && !needs_sharp_harvest) @@ -165,7 +165,7 @@ /obj/item/ash_flora/attackby(obj/item/weapon/W, mob/user, params) if(!standard_prep || !W.sharpness || !prepare(user)) - ..() + return ..() /obj/item/ash_flora/proc/prepare(mob/user) if(!prepared) From 3f2e21a0493de87ce65261da98428620c665bce4 Mon Sep 17 00:00:00 2001 From: Leo Date: Sat, 10 Sep 2016 13:31:53 -0300 Subject: [PATCH 19/41] Changes the view admin notes to view admin remarks --- code/modules/client/verbs/ooc.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/client/verbs/ooc.dm b/code/modules/client/verbs/ooc.dm index 7788d269c21..e37951e777e 100644 --- a/code/modules/client/verbs/ooc.dm +++ b/code/modules/client/verbs/ooc.dm @@ -143,7 +143,7 @@ var/global/normal_ooc_colour = OOC_COLOR src << "The Message of the Day has not been set." /client/proc/self_notes() - set name = "View Admin Notes" + set name = "View Admin Remarks" set category = "OOC" set desc = "View the notes that admins have written about you" From 383cbdfe38f9814b9b01e16bb3495e3cbc538617 Mon Sep 17 00:00:00 2001 From: tgstation-server Date: Sat, 10 Sep 2016 17:08:57 +0000 Subject: [PATCH 20/41] Automatic changelog generation for PR #20395 [ci skip] --- html/changelogs/AutoChangeLog-pr-20395.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-20395.yml diff --git a/html/changelogs/AutoChangeLog-pr-20395.yml b/html/changelogs/AutoChangeLog-pr-20395.yml new file mode 100644 index 00000000000..079783c4ca8 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-20395.yml @@ -0,0 +1,5 @@ +author: "Shadowlight213" +delete-after: True +changes: + - rscdel: "The surplus crate and random item will now only contain items allowed by the gamemode" + - rscdel: "removes sleeping carp scroll from surplus crates" From 424be04026283a96513489ed9f3c5560b927ff7a Mon Sep 17 00:00:00 2001 From: Cheridan Date: Sat, 10 Sep 2016 12:55:37 -0500 Subject: [PATCH 21/41] Fixes absurd amount of gib production (#20408) --- code/modules/food_and_drinks/kitchen_machinery/gibber.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/food_and_drinks/kitchen_machinery/gibber.dm b/code/modules/food_and_drinks/kitchen_machinery/gibber.dm index 2f88a2ae9d5..62532557e49 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/gibber.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/gibber.dm @@ -62,7 +62,7 @@ /obj/machinery/gibber/RefreshParts() var/gib_time = 40 for(var/obj/item/weapon/stock_parts/matter_bin/B in component_parts) - meat_produced += 3 * B.rating + meat_produced += B.rating for(var/obj/item/weapon/stock_parts/manipulator/M in component_parts) gib_time -= 5 * M.rating gibtime = gib_time @@ -229,7 +229,7 @@ var/obj/item/meatslab = allmeat[i] meatslab.loc = src.loc meatslab.throw_at_fast(pick(nearby_turfs),i,3) - for (var/turfs=1 to meat_produced*3) + for (var/turfs=1 to meat_produced) var/turf/gibturf = pick(nearby_turfs) if (!gibturf.density && src in view(gibturf)) new gibtype(gibturf,i) From 8dd507995a97f742bce3a1e8af66d64f7354c656 Mon Sep 17 00:00:00 2001 From: Remie Richards Date: Sat, 10 Sep 2016 20:42:34 +0100 Subject: [PATCH 22/41] Fixes conflicts, dang it people if(src != user.l_hand && src != user.r_hand) is shit code, shiiiiiiiiiiit. --- code/game/objects/items/weapons/twohanded.dm | 2 +- code/modules/mining/lavaland/ash_flora.dm | 2 +- code/modules/mining/lavaland/necropolis_chests.dm | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/code/game/objects/items/weapons/twohanded.dm b/code/game/objects/items/weapons/twohanded.dm index ba7f17da609..67792738d2b 100644 --- a/code/game/objects/items/weapons/twohanded.dm +++ b/code/game/objects/items/weapons/twohanded.dm @@ -109,7 +109,7 @@ /obj/item/weapon/twohanded/equipped(mob/user, slot) ..() - if(slot != slot_l_hand && slot != slot_r_hand && wielded) + if(!user.is_holding(src) && wielded) unwield(user) ///////////OFFHAND/////////////// diff --git a/code/modules/mining/lavaland/ash_flora.dm b/code/modules/mining/lavaland/ash_flora.dm index 2d831483647..eb9e319ee09 100644 --- a/code/modules/mining/lavaland/ash_flora.dm +++ b/code/modules/mining/lavaland/ash_flora.dm @@ -172,7 +172,7 @@ prepared = TRUE user << "You prepare [src]." var/obj/item/ash_flora/A = new prepared_type(get_turf(src)) - if(src in get_both_hands(user)) + if(user.is_holding(src)) user.unEquip(src, TRUE) user.put_in_hands(A) qdel(src) diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm index 993ac2b2d57..066ae8d47a7 100644 --- a/code/modules/mining/lavaland/necropolis_chests.dm +++ b/code/modules/mining/lavaland/necropolis_chests.dm @@ -829,7 +829,7 @@ else user << "You need to be on solid ground to produce a rune!" return - if(src != user.l_hand && src != user.r_hand) //you need to hold the staff to teleport + if(!user.is_holding(src)) //you need to hold the staff to teleport user << "You need to hold the staff in your hands to [rune ? "teleport with it":"create a rune"]!" return if(get_dist(user, rune) <= 2) //rune too close abort From c33e6e1b05feafbf4e070bee05bae6de941f3ced Mon Sep 17 00:00:00 2001 From: TheCarlSaganExpress Date: Sat, 10 Sep 2016 18:11:40 -0400 Subject: [PATCH 23/41] Requested code changes --- code/game/objects/items/devices/PDA/PDA.dm | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index f673bc101dc..8f2aa96ada7 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -706,16 +706,15 @@ var/global/list/obj/item/device/pda/PDAs = list() return if (usr.canUseTopic(src)) - if(is_type_in_list(inserted_item, contained_item)) - if(inserted_item) - if(istype(loc, /mob)) - var/mob/M = loc - M.put_in_hands(inserted_item) - usr << "You remove \the [inserted_item] from \the [src]." - inserted_item = null - return - inserted_item.forceMove() - usr << "This PDA does not have a pen in it!" + if(inserted_item) + if(ismob(loc)) + var/mob/M = loc + M.put_in_hands(inserted_item) + usr << "You remove \the [inserted_item] from \the [src]." + inserted_item = null + return + inserted_item.forceMove(loc) + usr << "This PDA does not have a pen in it!" /obj/item/device/pda/proc/id_check(mob/user, choice as num)//To check for IDs; 1 for in-pda use, 2 for out of pda use. if(choice == 1) @@ -782,7 +781,7 @@ var/global/list/obj/item/device/pda/PDAs = list() else if(!user.unEquip(C)) return - C.loc = src + C.forceMove(src) user << "You slide \the [C] into \the [src]." inserted_item = C else if(istype(C, /obj/item/weapon/photo)) From 3cab00bf09c0f5fb5a2fe7622430db9619af7e57 Mon Sep 17 00:00:00 2001 From: tgstation-server Date: Sat, 10 Sep 2016 23:44:38 +0000 Subject: [PATCH 24/41] Automatic changelog generation for PR #20370 [ci skip] --- html/changelogs/AutoChangeLog-pr-20370.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-20370.yml diff --git a/html/changelogs/AutoChangeLog-pr-20370.yml b/html/changelogs/AutoChangeLog-pr-20370.yml new file mode 100644 index 00000000000..af148b7acfe --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-20370.yml @@ -0,0 +1,4 @@ +author: "TheCarlSaganExpress" +delete-after: True +changes: + - rscadd: "Crayons, lipstick, cigarettes, and penlights can now be inserted into PDAs." From e80072378450f5b7a9bd0a5113571c78a3d3257f Mon Sep 17 00:00:00 2001 From: Cheridan Date: Sat, 10 Sep 2016 20:14:36 -0500 Subject: [PATCH 25/41] Revert "Allows different items to be inserted into the PDA." --- code/game/objects/items/devices/PDA/PDA.dm | 32 +++++++++++----------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index 8f2aa96ada7..a1ded3061aa 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -50,8 +50,6 @@ var/global/list/obj/item/device/pda/PDAs = list() var/image/photo = null //Scanned photo - var/list/contained_item = list(/obj/item/weapon/pen, /obj/item/toy/crayon, /obj/item/weapon/lipstick, /obj/item/device/flashlight/pen, /obj/item/clothing/mask/cigarette) - var/obj/item/inserted_item //Used for pen, crayon, and lipstick insertion/removal /obj/item/device/pda/pickup(mob/user) ..() @@ -76,7 +74,7 @@ var/global/list/obj/item/device/pda/PDAs = list() PDAs += src if(default_cartridge) cartridge = new default_cartridge(src) - inserted_item = new /obj/item/weapon/pen(src) + new /obj/item/weapon/pen(src) /obj/item/device/pda/proc/update_label() name = "PDA-[owner] ([ownjob])" //Name generalisation @@ -706,15 +704,17 @@ var/global/list/obj/item/device/pda/PDAs = list() return if (usr.canUseTopic(src)) - if(inserted_item) - if(ismob(loc)) + var/obj/item/weapon/pen/O = locate() in src + if(O) + if (istype(loc, /mob)) var/mob/M = loc - M.put_in_hands(inserted_item) - usr << "You remove \the [inserted_item] from \the [src]." - inserted_item = null - return - inserted_item.forceMove(loc) - usr << "This PDA does not have a pen in it!" + if(M.get_active_hand() == null) + M.put_in_hands(O) + usr << "You remove \the [O] from \the [src]." + return + O.loc = get_turf(src) + else + usr << "This PDA does not have a pen in it!" /obj/item/device/pda/proc/id_check(mob/user, choice as num)//To check for IDs; 1 for in-pda use, 2 for out of pda use. if(choice == 1) @@ -775,15 +775,15 @@ var/global/list/obj/item/device/pda/PDAs = list() pai = C user << "You slot \the [C] into [src]." updateUsrDialog() - else if(is_type_in_list(C, contained_item)) //Checks if there is a pen - if(inserted_item) - user << "There is already an item in \the [src]!" + else if(istype(C, /obj/item/weapon/pen)) + var/obj/item/weapon/pen/O = locate() in src + if(O) + user << "There is already a pen in \the [src]!" else if(!user.unEquip(C)) return - C.forceMove(src) + C.loc = src user << "You slide \the [C] into \the [src]." - inserted_item = C else if(istype(C, /obj/item/weapon/photo)) var/obj/item/weapon/photo/P = C photo = P.img From 7c3065bb349c7d5ab7a181ad5ee5c79aa0f9c641 Mon Sep 17 00:00:00 2001 From: tgstation-server Date: Sun, 11 Sep 2016 01:38:47 +0000 Subject: [PATCH 26/41] Automatic changelog generation for PR #20283 [ci skip] --- html/changelogs/AutoChangeLog-pr-20283.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-20283.yml diff --git a/html/changelogs/AutoChangeLog-pr-20283.yml b/html/changelogs/AutoChangeLog-pr-20283.yml new file mode 100644 index 00000000000..e990daac41d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-20283.yml @@ -0,0 +1,4 @@ +author: "RemieRichards" +delete-after: True +changes: + - rscadd: "Added the functionality for mobs to have multiple hands, this might have broken some things, so please report any weirdness" From 2a58dd54a95060c22dfbcef0ca32027103854d61 Mon Sep 17 00:00:00 2001 From: nullbear Date: Sun, 11 Sep 2016 01:46:26 -0700 Subject: [PATCH 27/41] Adds explosion helper proc w/ diminishing returns (#20319) * Adds new explosion proc Adds a new proc for calling explosions, which uses 'power' instead of a set of ranges. Power (1 - 100) is based on minimum explosions size (0, 0, 1) to maximum explosion size (5, 10, 20) Formula keeps explosions within a 'sane' range. So while it is possible to bypass maxcap using this, it will require a LOT of work. I've done some balance testing, and a halfcap (2,5,10) can be made using a double bluespace beaker of water and potassium. A (3,7,14) can be made using black powder, and the largest bluespace grenade explosion can be made using nitroglycerine, at (6, 12, 24) which is only slightly larger than maxcap. You can check out https://www.desmos.com/calculator/pgfz0gqqxf to see how the explosive power affects range. T is 'units of explosion' and P is a multiplier. Multipliers for explosive reagents are: water/potass = 1/10, black powder/meth = 1/6, nitroglycerin = 1/2. * Clarity Changes Renames dynamic explosion proc for clarity. Makes dyn_x explosions scaleable with DYN_EX_SCALE variable. Adds debug dyn_x verbs, and a dyn_x drop_bomb proc to fun admin verbs. * Adjusts formula better efficiency and readability. Adds debug proc for changing explosion scale. Adds a comment containing common power/explosion sizes. * oops --- code/_globalvars/configuration.dm | 1 + .../effects/effect_system/effects_other.dm | 22 +------- code/game/objects/explosion.dm | 14 +++++ code/modules/admin/admin_verbs.dm | 51 +++++++++++++++++++ 4 files changed, 68 insertions(+), 20 deletions(-) diff --git a/code/_globalvars/configuration.dm b/code/_globalvars/configuration.dm index e18125ab284..21155f2d2dd 100644 --- a/code/_globalvars/configuration.dm +++ b/code/_globalvars/configuration.dm @@ -41,4 +41,5 @@ var/MAX_EX_HEAVY_RANGE = 7 var/MAX_EX_LIGHT_RANGE = 14 var/MAX_EX_FLASH_RANGE = 14 var/MAX_EX_FLAME_RANGE = 14 +var/DYN_EX_SCALE = 0.5 diff --git a/code/game/objects/effects/effect_system/effects_other.dm b/code/game/objects/effects/effect_system/effects_other.dm index fe303b4782c..585dfedf0ab 100644 --- a/code/game/objects/effects/effect_system/effects_other.dm +++ b/code/game/objects/effects/effect_system/effects_other.dm @@ -105,7 +105,7 @@ if(explosion_message) location.visible_message("The solution violently explodes!", \ "You hear an explosion!") - if (amount <= 2) + if (amount < 1) var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread s.set_up(2, 1, location) s.start() @@ -116,22 +116,4 @@ M.Weaken(rand(1,5)) return else - var/devastation = -1 - var/heavy = -1 - var/light = -1 - var/flash = -1 - - // Clamp all values to MAX_EXPLOSION_RANGE - if (round(amount/12) > 0) - devastation = min (MAX_EX_DEVESTATION_RANGE, devastation + round(amount/12)) - - if (round(amount/6) > 0) - heavy = min (MAX_EX_HEAVY_RANGE, heavy + round(amount/6)) - - if (round(amount/3) > 0) - light = min (MAX_EX_LIGHT_RANGE, light + round(amount/3)) - - if (flashing && flashing_factor) - flash += (round(amount/4) * flashing_factor) - - explosion(location, devastation, heavy, light, flash) + dyn_explosion(location, amount, flashing_factor) \ No newline at end of file diff --git a/code/game/objects/explosion.dm b/code/game/objects/explosion.dm index 248a17a77f0..2802cce4314 100644 --- a/code/game/objects/explosion.dm +++ b/code/game/objects/explosion.dm @@ -246,4 +246,18 @@ T.color = null T.maptext = "" +proc/dyn_explosion(turf/epicenter, power, flash_range, adminlog = 1, ignorecap = 1, flame_range = 0 ,silent = 0, smoke = 1) + if(!power) + return + var/range = 0 + range = round((2 * power)**DYN_EX_SCALE) + explosion(epicenter, round(range * 0.25), round(range * 0.5), round(range), flash_range*range, adminlog, ignorecap, flame_range*range, silent, smoke) +// Using default dyn_ex scale: +// 100 explosion power is a (5, 10, 20) explosion. +// 75 explosion power is a (4, 8, 17) explosion. +// 50 explosion power is a (3, 7, 14) explosion. +// 25 explosion power is a (2, 5, 10) explosion. +// 10 explosion power is a (1, 3, 6) explosion. +// 5 explosion power is a (0, 1, 3) explosion. +// 1 explosion power is a (0, 0, 1) explosion. \ No newline at end of file diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index c67f8d1c3b2..43cd0a61fdc 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -82,6 +82,8 @@ var/list/admin_verbs_fun = list( /client/proc/cmd_admin_dress, /client/proc/cmd_admin_gib_self, /client/proc/drop_bomb, + /client/proc/set_dynex_scale, + /client/proc/drop_dynex_bomb, /client/proc/cinematic, /client/proc/one_click_antag, /client/proc/send_space_ninja, @@ -142,6 +144,9 @@ var/list/admin_verbs_debug = list( /client/proc/check_bomb_impacts, /proc/machine_upgrade, /client/proc/populate_world, + /client/proc/get_dynex_power, //*debug verbs for dynex explosions. + /client/proc/get_dynex_range, //*debug verbs for dynex explosions. + /client/proc/set_dynex_scale, /client/proc/cmd_display_del_log, /client/proc/reset_latejoin_spawns, /client/proc/create_outfits, @@ -196,6 +201,10 @@ var/list/admin_verbs_hideable = list( /client/proc/cmd_admin_dress, /client/proc/cmd_admin_gib_self, /client/proc/drop_bomb, + /client/proc/drop_dynex_bomb, + /client/proc/get_dynex_range, + /client/proc/get_dynex_power, + /client/proc/set_dynex_scale, /client/proc/cinematic, /client/proc/send_space_ninja, /client/proc/cmd_admin_add_freeform_ai_law, @@ -514,6 +523,48 @@ var/list/admin_verbs_hideable = list( message_admins("[ckey] creating an admin explosion at [epicenter.loc].") feedback_add_details("admin_verb","DB") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! +/client/proc/drop_dynex_bomb() + set category = "Special Verbs" + set name = "Drop DynEx Bomb" + set desc = "Cause an explosion of varying strength at your location." + + var/ex_power = input("Explosive Power:") as null|num + var/turf/epicenter = mob.loc + if(ex_power && epicenter) + dyn_explosion(epicenter, ex_power) + message_admins("[ckey] creating an admin explosion at [epicenter.loc].") + feedback_add_details("admin_verb","DDXB") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/get_dynex_range() + set category = "Debug" + set name = "Get DynEx Range" + set desc = "Get the estimated range of a bomb, using explosive power." + + var/ex_power = input("Explosive Power:") as null|num + var/range = round((2 * ex_power)**DYN_EX_SCALE) + usr << "Estimated Explosive Range: (Devestation: [round(range*0.25)], Heavy: [round(range*0.5)], Light: [round(range)])" + +/client/proc/get_dynex_power() + set category = "Debug" + set name = "Get DynEx Power" + set desc = "Get the estimated required power of a bomb, to reach a specific range." + + var/ex_range = input("Light Explosion Range:") as null|num + var/power = (0.5 * ex_range)**(1/DYN_EX_SCALE) + usr << "Estimated Explosive Power: [power]" + +/client/proc/set_dynex_scale() + set category = "Debug" + set name = "Set DynEx Scale" + set desc = "Set the scale multiplier of dynex explosions. The default is 0.5." + + var/ex_scale = input("New DynEx Scale:") as null|num + if(!ex_scale) + return + DYN_EX_SCALE = ex_scale + log_admin("[key_name(usr)] has modified Dynamic Explosion Scale: [ex_scale]") + message_admins("[key_name_admin(usr)] has modified Dynamic Explosion Scale: [ex_scale]") + /client/proc/give_spell(mob/T in mob_list) set category = "Fun" set name = "Give Spell" From 443a4501ec575c27fb8a4844ca314c070513e57e Mon Sep 17 00:00:00 2001 From: phil235 Date: Mon, 12 Sep 2016 19:33:50 +0200 Subject: [PATCH 28/41] 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 16ba61919d5..e688e19691d 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 35ae80339e6..8fa869b173d 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 d3573c3e30b..18420d099e9 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 45e4e748284..f7e7e86f172 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 1713fbaec40..ad6d1b744c1 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 0db7e381bd7..4ce944db059 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 d6a019fa8e2..cc62442653f 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 a9c91450c62..de99eca0917 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 1e66100e551..fa2ad08b30b 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 39892a67e3a..a8f3703f2f7 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 509af712b90..bb0bac5d4ce 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 a7930dc8c2c..623b49723ae 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 53b7ce8a0c9..93f36820fd8 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 2bbc92c7cd4..ac42696bc56 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 838f913536f..ced66536d87 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 95c2ff9836a..f6986e8d4f1 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 ed93eb9369a..5b251a3edfa 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 ba315278a20..f9109df17c1 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 3a5dc527f09..e3ffbc868ba 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 11a8eebbe5d..626fb567c3d 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 1df55bbb9d7..20bea2da922 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 c041f2610de..57ded9abc30 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 ee19e8483a6..e3d88e8b15e 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 0a93341a63d..9b9cfb3c3d6 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 af57e091efa..6ac88edf050 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 9f75bf714e6..6213eacc75c 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 ef0611a9cd7..8162b451dc8 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 f14c1c95780..6d38a58cc47 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 1c7ce8d11a5..79c707bff04 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 ea792abe4b3..9f3df575613 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 28f3574c91c..a05c1fe0b7c 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 83477d09822..ca63657de88 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 2676bc21aea..b80a7e692ea 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 fb375070f9d..92922f8e5ba 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 08e09f57fcb..93a2cb6e18a 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 8e91c964dab..22bb549558d 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 241c16bf56e..eefbf5689f1 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 c2a7423ef01..116d910e056 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 30f7d7c10e7..d095f67df43 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 68449ba4317..56bc184a7d8 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 2310d97b66e..8fd17b07c30 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 9027a95c1ff..b67617ae380 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 b77bc2894ad..29d8e89c86b 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 6d0d742c00e..75b44b7edc9 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 870854fa3eb..4805c884929 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 82ad4e67cc8..ceb75c29c09 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 165f8e21e07..45934d85022 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 7ca75a4bb69..59bff85af25 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 224d5e23110..89e3a0ffdb4 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 e1b6209fed9..3dbeadfd33d 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 12f665fa17c..32c60b66759 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 3b9c43beb80..47f7fe8a043 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 61598ca32bc..478ef77fe6f 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 36239710c46..af916014ca2 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 6ec06406b81..37bde068e28 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 2a15a49fdac..6a04670188a 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 36bf7577bb1..a0e5d4a3dc3 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 0e978782a5d..916bd7d2cf3 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 e255f497ca2..7c0666a0c6e 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 834c3b4c7dc..b498217bb8a 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 5bac5acd991..00000000000 --- 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 e6618e62c74..bb6afc8e8ee 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 efe7edf08e1..8877f17bc51 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 a04be038af7..a79ee1e4704 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 b0be84a5209..f2932a64dd6 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 65a73271e41..dfdccf1b8d1 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 c39791c0350..e5bb68ef23c 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 d898405a1d8..5e8b75b987a 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 d133a66b612..21aab1670c9 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 66b881f09ca..8d0009c181d 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 1fd3e766c62..a7f84608ffe 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 3763799c961..5fdc8e8c197 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 4ec3541ce2f..5d11b5bdac8 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 60476753365..76536e7b21d 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 8d76fcc492a..810048f5782 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 106d91fdd73..9f93c93eca3 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 e9ca6ece91c..3f35613f442 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 24708a7829d..26513f300b5 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 07802d94a9a..e8ef7dc9402 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 f6ffe2afb1a..ab3d92007ea 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 9e5801e1667..537c4d37c78 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 906af763df6..a48395a2cab 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 67792738d2b..e597a00abca 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 82703edaa3e..289d1b6cd7d 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 1008453f85b..a229b10f337 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 2ca23434053..aece047550c 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 30adb230404..31ecea937bd 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 cb6120efe3d..659fe3f3c8d 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 1c5375434f2..19bf143a1cd 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 0bd4fff922f..5dcbeb7c63b 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 19b3ac4abfa..a2b2dbf31bc 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 0dd97c68a36..be78c4ef8b2 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 1b8e9a56612..adcd2b4762c 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 ab0aa56e1c0..7be2862b0fc 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 0e6e1ee5b03..4979cbd6c7d 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 a089a58bd77..dfdf30fb3c5 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 e5e7d511fc0..4bccb03c2d8 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 67b700b2b08..e98859b90ff 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 bd4be7c66f9..8ab505f7a9e 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 75f731b6e69..9d87f412e8d 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 229f2b52fce..f7ad95798a5 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 77f72d484a7..0aeb312ee0f 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 dc8ff6ffc1e..caf2bfe22c4 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 c8f7ce99a22..42572b1c03c 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 d9f5ef6fa98..0d934446366 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 00000000000..7857c0b565e --- /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 7583d0afaa7..6211dc83493 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 8e078e4ed7c..5f0dbd5635e 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 379500f5002..3a9e938df39 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 8da5304ff77..d16c06bea53 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 a22ab106dd4..dacd4ff7d4a 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 89acb9ab91c..98c1df7b382 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 00000000000..4f08997c40f --- /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 5f48d88c55d..5559ebffe01 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 136572fb5c5..43a2f196255 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 887cf139996..f6ceff4774a 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 00000000000..77bab6cdf04 --- /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 91bddef2cde..f0192cf2a96 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 9a531fdf956..f2382721cff 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 a1292a9c9ab..95387d85691 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 00000000000..ec3753e6979 --- /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 8175cf4e862..0198c4a1cf8 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 6a82174e41e..4de7733bd26 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 103fcbe50d7..f73ad1053c1 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 479e9459c5c..6b2e19c1959 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 00000000000..6da20373f62 --- /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 3db1d738a96..f1a2a526a7a 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 1be55c38a12..61d30f7b8e9 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 00000000000..aa49718753f --- /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 d1b085ca3b9..83bf44f8e14 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 48f191b4e74..1c7a02138df 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 b407a2881a9..00000000000 --- 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 43e4dfaae76..00000000000 --- 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 4c666a86799..00000000000 --- 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 c218fbb8445..00000000000 --- 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 f19d0567565..535f7f39ffb 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 2bccce619fa..abf9dffc00c 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 69863d41b9b..98426060462 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 cf9504df710..3283e04d22e 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 619e9a7e139..852a19fd1ab 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 9677c1b0bfc..c3e0bc205e1 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 00000000000..adcf57433c4 --- /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 cb7289a7ef5..4bbde09513d 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 2f4ca6da119..aa701d7f1b3 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 d3e541143b0..3e87fa5c1ab 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 6ae41f3c859..33cbce3edb1 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 00000000000..c3a1818b242 --- /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 b342ace1e79..b7ca5044398 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 24c9305aa15..abfe312c48b 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 05f410fafe2..dcd5b1a59b2 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 0690e8b11fd..f0fcda0dcf9 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 fc1bf88240b..10c9a2a50f8 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 f44ca1855ba..052328ac563 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 d5d566211d1..b06fef840ca 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 c7543c03ede..ee4bd6ce206 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 b19c799ee37..7cd4e02e618 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 00000000000..771a6d7c2f5 --- /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 00000000000..181a166bb54 --- /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 02fb54012b1..ebd3067bb0a 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 ea83dce7e1d..018c05e9800 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 00000000000..5cdbebfd995 --- /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 ca980e86bf5..fa94450b748 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 33f24c1dc0b..d0350a7a267 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 63fd0413051..76f8e90ef6e 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 00000000000..7fa7a720d42 --- /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 981f17a4b5e..fe2f2c5a5d1 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 00000000000..b216c04e1ab --- /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 00000000000..53dd3b50454 --- /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 4cf22a7acda..d3cc4116ffb 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 cc05c511030..63a58a5f705 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 d19ce2687a2..fa4e69cf5ee 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 8956f7872a6..1d276b2bf3b 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 fdf5215ebc3..4d92739db83 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 b9d4a7e313d..69be54689f6 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 00000000000..b39bc1bbe19 --- /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 35b363ae285..2d22e293753 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 b95e845d563..d3d99174436 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 889ab1803ca..a7a204af676 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 013a77e81d1..2f75310ff25 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 a8f7b491bc9..bedb33e3d4a 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 7f05844b296..edca0beac1d 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 44c96f7f216..0545bd03b00 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 37e60e3b93c..40d23ea638d 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 649fe0462bb..dfbe6250533 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 e1b2f760b4c..fcae203a523 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 e2cb8d95974..6ed04dbbdd3 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 fb38a3fbdd7..8062c023bc1 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 3f10566dde8..89d63ba3f06 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 a5e754cd015..434a31157a4 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 9b6f7a79297..41e77f5f886 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 107b9c68197..a3469c6b699 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 594df3bd3b6..9b50a1e4a98 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 a238c60623a..d0f8baa82ff 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 1c4616c90ed..910fe2cc89a 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 59cd030b85f..0dc198bc33a 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 c1061c57293..4a3b66ba108 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 0dadac9de80..d0f9d4bc511 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 c70c022d467..1c78b5c6f8e 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 6e2d5c607e0..3055d8733e0 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 c10c97cdaca..e65c395f7c7 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 2461aaba745..ce375b1d228 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 ff9eb7197d6..7c311d980b3 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 b3fb7d29526..7f6c1c4cbb4 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 5943577d59c..b475c752c67 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 38e316be26b..6cb48f90552 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 ca2b41ffbe7..fd73906d8bc 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 6a1604a4c26..387e56aaf9c 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 e11115c64d3..a63d91c6437 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 9a1d27ebbc7..728555db52e 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 1e13586eea8..2ebe45f2d31 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 74c8679cd78..6e4ee1d069d 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 7cacabe3a08..b6218ceaea6 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 16c742fc6fd..c3d86b5d4a2 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 4ceec195c09..9f2c6ac37c1 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 00000000000..a5cefa1a0a7 --- /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 ee324e432b4..89b070f28cc 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 982ef0d4d40..32b294a7999 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 3a00620a172..5e16b420f21 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 50c3875f258..eef8bf6dfd3 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 f1ee5ec13f6..48915fd59bd 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 7a0c9fa6718..5341c2bf09d 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 7117d276a76..fa9db1ae8ed 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 35b15432304..26e57700ae5 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 64223336da1..7e3cbf954ac 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 ac8fdaa8b6b..f21275b6fce 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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