diff --git a/code/ZAS/Airflow.dm b/code/ZAS/Airflow.dm index 01a84fdf5d9..8dd637e58f8 100644 --- a/code/ZAS/Airflow.dm +++ b/code/ZAS/Airflow.dm @@ -228,13 +228,16 @@ mob/living/carbon/human/airflow_hit(atom/A) var/b_loss = airflow_speed * vsc.airflow_damage var/blocked = run_armor_check(BP_HEAD,"melee") - apply_damage(b_loss/3, BRUTE, BP_HEAD, blocked, 0, "Airflow") + var/soaked = get_armor_soak(BP_HEAD,"melee") + apply_damage(b_loss/3, BRUTE, BP_HEAD, blocked, soaked, 0, "Airflow") blocked = run_armor_check(BP_TORSO,"melee") - apply_damage(b_loss/3, BRUTE, BP_TORSO, blocked, 0, "Airflow") + soaked = get_armor_soak(BP_TORSO,"melee") + apply_damage(b_loss/3, BRUTE, BP_TORSO, blocked, soaked, 0, "Airflow") blocked = run_armor_check(BP_GROIN,"melee") - apply_damage(b_loss/3, BRUTE, BP_GROIN, blocked, 0, "Airflow") + soaked = get_armor_soak(BP_GROIN,"melee") + apply_damage(b_loss/3, BRUTE, BP_GROIN, blocked, soaked, 0, "Airflow") if(airflow_speed > 10) Paralyse(round(airflow_speed * vsc.airflow_stun)) diff --git a/code/controllers/communications.dm b/code/controllers/communications.dm index 97d193bc5bc..796fb0b6649 100644 --- a/code/controllers/communications.dm +++ b/code/controllers/communications.dm @@ -108,6 +108,7 @@ var/const/ERT_FREQ = 1345 var/const/AI_FREQ = 1343 var/const/DTH_FREQ = 1341 var/const/SYND_FREQ = 1213 +var/const/RAID_FREQ = 1277 var/const/ENT_FREQ = 1461 //entertainment frequency. This is not a diona exclusive frequency. // department channels @@ -133,6 +134,7 @@ var/list/radiochannels = list( "Response Team" = ERT_FREQ, "Special Ops" = DTH_FREQ, "Mercenary" = SYND_FREQ, + "Raider" = RAID_FREQ, "Supply" = SUP_FREQ, "Service" = SRV_FREQ, "AI Private" = AI_FREQ, @@ -145,7 +147,7 @@ var/list/radiochannels = list( var/list/CENT_FREQS = list(ERT_FREQ, DTH_FREQ) // Antag channels, i.e. Syndicate -var/list/ANTAG_FREQS = list(SYND_FREQ) +var/list/ANTAG_FREQS = list(SYND_FREQ, RAID_FREQ) //Department channels, arranged lexically var/list/DEPT_FREQS = list(AI_FREQ, COMM_FREQ, ENG_FREQ, ENT_FREQ, MED_FREQ, SEC_FREQ, SCI_FREQ, SRV_FREQ, SUP_FREQ) diff --git a/code/datums/supplypacks/medical.dm b/code/datums/supplypacks/medical.dm index e7b29fd8d9a..13a69cfc1a1 100644 --- a/code/datums/supplypacks/medical.dm +++ b/code/datums/supplypacks/medical.dm @@ -66,6 +66,27 @@ containername = "Surgery crate" access = access_medical +/datum/supply_packs/med/deathalarm + name = "Death Alarm crate" + contains = list( + /obj/item/weapon/storage/box/cdeathalarm_kit, + /obj/item/weapon/storage/box/cdeathalarm_kit + ) + cost = 40 + containertype = "/obj/structure/closet/crate/secure" + containername = "Death Alarm crate" + access = access_medical + +/datum/supply_packs/med/clotting + name = "Clotting Medicine crate" + contains = list( + /obj/item/weapon/storage/firstaid/clotting + ) + cost = 40 + containertype = "/obj/structure/closet/crate/secure" + containername = "Clotting Medicine crate" + access = access_medical + /datum/supply_packs/med/sterile name = "Sterile equipment crate" contains = list( diff --git a/code/datums/uplink/medical.dm b/code/datums/uplink/medical.dm index 381221127df..eab9d9cd021 100644 --- a/code/datums/uplink/medical.dm +++ b/code/datums/uplink/medical.dm @@ -19,6 +19,16 @@ item_cost = 5 path = /obj/item/weapon/storage/box/ambrosia +/datum/uplink_item/item/medical/clotting + name = "Clotting Medicine injector" + item_cost = 10 + path = /obj/item/weapon/reagent_containers/hypospray/autoinjector/clotting + +/datum/uplink_item/item/medical/bonemeds + name = "Bone Repair injector" + item_cost = 10 + path = /obj/item/weapon/reagent_containers/hypospray/autoinjector/bonemed + /datum/uplink_item/item/medical/ambrosiadeusseeds name = "Box of 7x ambrosia deus seed packets" item_cost = 10 diff --git a/code/game/antagonist/antagonist_create.dm b/code/game/antagonist/antagonist_create.dm index 733ec3eda08..a53037ead3e 100644 --- a/code/game/antagonist/antagonist_create.dm +++ b/code/game/antagonist/antagonist_create.dm @@ -43,12 +43,15 @@ /datum/antagonist/proc/create_radio(var/freq, var/mob/living/carbon/human/player) var/obj/item/device/radio/R - if(freq == SYND_FREQ) - R = new/obj/item/device/radio/headset/syndicate(player) - else - R = new/obj/item/device/radio/headset(player) + switch(freq) + if(SYND_FREQ) + R = new/obj/item/device/radio/headset/syndicate(player) + if(RAID_FREQ) + R = new/obj/item/device/radio/headset/raider(player) + else + R = new/obj/item/device/radio/headset(player) + R.set_frequency(freq) - R.set_frequency(freq) player.equip_to_slot_or_del(R, slot_l_ear) return R diff --git a/code/game/antagonist/outsider/raider.dm b/code/game/antagonist/outsider/raider.dm index 1a7da8954e6..4124fc9af96 100644 --- a/code/game/antagonist/outsider/raider.dm +++ b/code/game/antagonist/outsider/raider.dm @@ -232,7 +232,7 @@ var/datum/antagonist/raider/raiders W.handle_item_insertion(id) player.equip_to_slot_or_del(W, slot_wear_id) spawn_money(rand(50,150)*10,W) - create_radio(SYND_FREQ, player) + create_radio(RAID_FREQ, player) return 1 diff --git a/code/game/machinery/computer/cloning.dm b/code/game/machinery/computer/cloning.dm index da165448dab..75ba732950a 100644 --- a/code/game/machinery/computer/cloning.dm +++ b/code/game/machinery/computer/cloning.dm @@ -305,7 +305,7 @@ if(subject.isSynthetic()) scantemp = "Error: Majority of subject is non-organic." return - if (subject.suiciding == 1) + if (subject.suiciding) scantemp = "Error: Subject's brain is not responding to scanning stimuli." return if ((!subject.ckey) || (!subject.client)) diff --git a/code/game/machinery/telecomms/broadcaster.dm b/code/game/machinery/telecomms/broadcaster.dm index 7d27c94b653..9838d807224 100644 --- a/code/game/machinery/telecomms/broadcaster.dm +++ b/code/game/machinery/telecomms/broadcaster.dm @@ -374,6 +374,8 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept blackbox.msg_deathsquad += blackbox_msg if(SYND_FREQ) blackbox.msg_syndicate += blackbox_msg + if(RAID_FREQ) + blackbox.msg_raider += blackbox_msg if(SUP_FREQ) blackbox.msg_cargo += blackbox_msg if(SRV_FREQ) @@ -554,6 +556,8 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept blackbox.msg_deathsquad += blackbox_msg if(SYND_FREQ) blackbox.msg_syndicate += blackbox_msg + if(RAID_FREQ) + blackbox.msg_raider += blackbox_msg if(SUP_FREQ) blackbox.msg_cargo += blackbox_msg if(SRV_FREQ) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 0559b626e10..4316da3c499 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -44,6 +44,7 @@ var/slowdown = 0 // How much clothing is slowing you down. Negative values speeds you up var/canremove = 1 //Mostly for Ninja code at this point but basically will not allow the item to be removed if set to 0. /N var/list/armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0) + var/list/armorsoak = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0) var/list/allowed = null //suit storage stuff. var/obj/item/device/uplink/hidden/hidden_uplink = null // All items can have an uplink hidden inside, just remember to add the triggers. var/zoomdevicename = null //name used for message when binoculars/scope is used diff --git a/code/game/objects/items/devices/radio/encryptionkey.dm b/code/game/objects/items/devices/radio/encryptionkey.dm index f08585da31d..7bec1014d7d 100644 --- a/code/game/objects/items/devices/radio/encryptionkey.dm +++ b/code/game/objects/items/devices/radio/encryptionkey.dm @@ -19,6 +19,12 @@ origin_tech = list(TECH_ILLEGAL = 3) syndie = 1//Signifies that it de-crypts Syndicate transmissions +/obj/item/device/encryptionkey/raider + icon_state = "cypherkey" + channels = list("Raider" = 1) + origin_tech = list(TECH_ILLEGAL = 2) + syndie = 1 + /obj/item/device/encryptionkey/binary icon_state = "cypherkey" translate_binary = 1 diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm index fce4ec31756..a56ea4fa988 100644 --- a/code/game/objects/items/devices/radio/headset.dm +++ b/code/game/objects/items/devices/radio/headset.dm @@ -75,6 +75,15 @@ syndie = 1 ks1type = /obj/item/device/encryptionkey/syndicate +/obj/item/device/radio/headset/raider + origin_tech = list(TECH_ILLEGAL = 2) + syndie = 1 + ks1type = /obj/item/device/encryptionkey/raider + +/obj/item/device/radio/headset/raider/initialize() + ..() + set_frequency(RAID_FREQ) + /obj/item/device/radio/headset/binary origin_tech = list(TECH_ILLEGAL = 3) ks1type = /obj/item/device/encryptionkey/binary @@ -289,6 +298,7 @@ desc = "The headset of the boss's boss." icon_state = "com_headset" item_state = "headset" + centComm = 1 // freerange = 1 ks2type = /obj/item/device/encryptionkey/ert diff --git a/code/game/objects/items/devices/radio/intercom.dm b/code/game/objects/items/devices/radio/intercom.dm index c480d2dd160..8e9a72d2038 100644 --- a/code/game/objects/items/devices/radio/intercom.dm +++ b/code/game/objects/items/devices/radio/intercom.dm @@ -27,6 +27,8 @@ /obj/item/device/radio/intercom/specops name = "\improper Spec Ops intercom" frequency = ERT_FREQ + subspace_transmission = 1 + centComm = 1 /obj/item/device/radio/intercom/department canhear_range = 5 @@ -81,6 +83,17 @@ ..() internal_channels[num2text(SYND_FREQ)] = list(access_syndicate) +/obj/item/device/radio/intercom/raider + name = "illicit intercom" + desc = "Pirate radio, but not in the usual sense of the word." + frequency = RAID_FREQ + subspace_transmission = 1 + syndie = 1 + +/obj/item/device/radio/intercom/raider/New() + ..() + internal_channels[num2text(RAID_FREQ)] = list(access_syndicate) + /obj/item/device/radio/intercom/Destroy() processing_objects -= src ..() diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index cec23e818fd..1bd7f9349ad 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -40,6 +40,7 @@ var/global/list/default_medbay_channels = list( var/list/channels = list() //see communications.dm for full list. First channel is a "default" for :h var/subspace_transmission = 0 var/syndie = 0//Holder to see if it's a syndicate encrypted radio + var/centComm = 0//Holder to see if it's a CentComm encrypted radio flags = CONDUCT slot_flags = SLOT_BELT throw_speed = 2 @@ -508,6 +509,9 @@ var/global/list/default_medbay_channels = list( if(freq in ANTAG_FREQS) if(!(src.syndie))//Checks to see if it's allowed on that frequency, based on the encryption keys return -1 + if(freq in CENT_FREQS) + if(!(src.centComm))//Checks to see if it's allowed on that frequency, based on the encryption keys + return -1 if (!on) return -1 if (!freq) //recieved on main frequency diff --git a/code/game/objects/items/weapons/implants/implant.dm b/code/game/objects/items/weapons/implants/implant.dm index c3ddb4fb39b..6554e80f8bb 100644 --- a/code/game/objects/items/weapons/implants/implant.dm +++ b/code/game/objects/items/weapons/implants/implant.dm @@ -452,23 +452,27 @@ the implant may become unstable and either pre-maturely inject the subject or si var/obj/item/device/radio/headset/a = new /obj/item/device/radio/headset/heads/captain(null) if(istype(t, /area/syndicate_station) || istype(t, /area/syndicate_mothership) || istype(t, /area/shuttle/syndicate_elite) ) //give the syndies a bit of stealth - a.autosay("[mobname] has died in Space!", "[mobname]'s Death Alarm", "Security") - a.autosay("[mobname] has died in Space!", "[mobname]'s Death Alarm", "Medical") + a.autosay("[mobname] has died in Space!", "[mobname]'s Death Alarm", "General") +// a.autosay("[mobname] has died in Space!", "[mobname]'s Death Alarm", "Security") +// a.autosay("[mobname] has died in Space!", "[mobname]'s Death Alarm", "Medical") else - a.autosay("[mobname] has died in [t.name]!", "[mobname]'s Death Alarm", "Security") - a.autosay("[mobname] has died in [t.name]!", "[mobname]'s Death Alarm", "Medical") + a.autosay("[mobname] has died in [t.name]!", "[mobname]'s Death Alarm", "General") +// a.autosay("[mobname] has died in [t.name]!", "[mobname]'s Death Alarm", "Security") +// a.autosay("[mobname] has died in [t.name]!", "[mobname]'s Death Alarm", "Medical") qdel(a) processing_objects.Remove(src) if ("emp") var/obj/item/device/radio/headset/a = new /obj/item/device/radio/headset/heads/captain(null) var/name = prob(50) ? t.name : pick(teleportlocs) - a.autosay("[mobname] has died in [name]!", "[mobname]'s Death Alarm", "Security") - a.autosay("[mobname] has died in [name]!", "[mobname]'s Death Alarm", "Medical") + a.autosay("[mobname] has died in [name]!", "[mobname]'s Death Alarm", "General") +// a.autosay("[mobname] has died in [name]!", "[mobname]'s Death Alarm", "Security") +// a.autosay("[mobname] has died in [name]!", "[mobname]'s Death Alarm", "Medical") qdel(a) else var/obj/item/device/radio/headset/a = new /obj/item/device/radio/headset/heads/captain(null) - a.autosay("[mobname] has died-zzzzt in-in-in...", "[mobname]'s Death Alarm", "Security") - a.autosay("[mobname] has died-zzzzt in-in-in...", "[mobname]'s Death Alarm", "Medical") + a.autosay("[mobname] has died-zzzzt in-in-in...", "[mobname]'s Death Alarm", "General") +// a.autosay("[mobname] has died-zzzzt in-in-in...", "[mobname]'s Death Alarm", "Security") +// a.autosay("[mobname] has died-zzzzt in-in-in...", "[mobname]'s Death Alarm", "Medical") qdel(a) processing_objects.Remove(src) diff --git a/code/game/objects/items/weapons/material/knives.dm b/code/game/objects/items/weapons/material/knives.dm index a70a253579f..8ebf5697c9c 100644 --- a/code/game/objects/items/weapons/material/knives.dm +++ b/code/game/objects/items/weapons/material/knives.dm @@ -35,6 +35,13 @@ icon_state = "switchblade" unbreakable = 1 +/obj/item/weapon/material/butterfly/boxcutter + name = "box cutter" + desc = "A thin, inexpensive razor-blade knife designed to open cardboard boxes." + icon_state = "boxcutter" + force_divisor = 0.1 // 6 when wielded with hardness 60 (steel) + thrown_force_divisor = 0.2 // 4 when thrown with weight 20 (steel) + /obj/item/weapon/material/butterfly/attack_self(mob/user) active = !active if(active) diff --git a/code/game/objects/items/weapons/material/shards.dm b/code/game/objects/items/weapons/material/shards.dm index 78ee869604a..92cb782e8a2 100644 --- a/code/game/objects/items/weapons/material/shards.dm +++ b/code/game/objects/items/weapons/material/shards.dm @@ -90,7 +90,7 @@ if(affecting.take_damage(force, 0)) H.UpdateDamageIcon() H.updatehealth() - if(affecting.can_feel_pain()) + if(affecting.organ_can_feel_pain()) H.Weaken(3) return check -= picked diff --git a/code/game/objects/items/weapons/storage/firstaid.dm b/code/game/objects/items/weapons/storage/firstaid.dm index 1c77e1f6cbf..61a9a99f96d 100644 --- a/code/game/objects/items/weapons/storage/firstaid.dm +++ b/code/game/objects/items/weapons/storage/firstaid.dm @@ -126,6 +126,7 @@ new /obj/item/weapon/storage/pill_bottle/dylovene(src) new /obj/item/weapon/storage/pill_bottle/tramadol(src) new /obj/item/weapon/storage/pill_bottle/spaceacillin(src) + new /obj/item/weapon/reagent_containers/hypospray/autoinjector/clotting(src) new /obj/item/stack/medical/splint(src) return @@ -150,6 +151,19 @@ new /obj/item/stack/medical/advanced/bruise_pack(src) return +/obj/item/weapon/storage/firstaid/clotting + name = "clotting kit" + desc = "Contains chemicals to stop bleeding." + max_storage_space = ITEMSIZE_COST_SMALL * 7 + +/obj/item/weapon/storage/firstaid/clotting/New() + ..() + if (empty) + return + for(var/i = 1 to 8) + new /obj/item/weapon/reagent_containers/hypospray/autoinjector/clotting(src) + return + /* * Pill Bottles */ diff --git a/code/game/objects/items/weapons/tools.dm b/code/game/objects/items/weapons/tools.dm index c39053b5aa5..8e039ee2dac 100644 --- a/code/game/objects/items/weapons/tools.dm +++ b/code/game/objects/items/weapons/tools.dm @@ -172,7 +172,8 @@ /obj/item/weapon/weldingtool/examine(mob/user) if(..(user, 0)) - user << text("\icon[] [] contains []/[] units of fuel!", src, src.name, get_fuel(),src.max_fuel ) + if(max_fuel) + user << text("\icon[] [] contains []/[] units of fuel!", src, src.name, get_fuel(),src.max_fuel ) /obj/item/weapon/weldingtool/attackby(obj/item/W as obj, mob/living/user as mob) @@ -234,18 +235,22 @@ /obj/item/weapon/weldingtool/afterattack(obj/O as obj, mob/user as mob, proximity) if(!proximity) return - if (istype(O, /obj/structure/reagent_dispensers/fueltank) && get_dist(src,O) <= 1 && !src.welding) - O.reagents.trans_to_obj(src, max_fuel) - user << "Welder refueled" - playsound(src.loc, 'sound/effects/refill.ogg', 50, 1, -6) - return - else if (istype(O, /obj/structure/reagent_dispensers/fueltank) && get_dist(src,O) <= 1 && src.welding) - message_admins("[key_name_admin(user)] triggered a fueltank explosion with a welding tool.") - log_game("[key_name(user)] triggered a fueltank explosion with a welding tool.") - user << "You begin welding on the fueltank and with a moment of lucidity you realize, this might not have been the smartest thing you've ever done." - var/obj/structure/reagent_dispensers/fueltank/tank = O - tank.explode() - return + if (istype(O, /obj/structure/reagent_dispensers/fueltank) && get_dist(src,O) <= 1 && !welding) + if(!welding && max_fuel) + O.reagents.trans_to_obj(src, max_fuel) + user << "Welder refueled" + playsound(src.loc, 'sound/effects/refill.ogg', 50, 1, -6) + return + else if(!welding) + user << "[src] doesn't use fuel." + return + else + message_admins("[key_name_admin(user)] triggered a fueltank explosion with a welding tool.") + log_game("[key_name(user)] triggered a fueltank explosion with a welding tool.") + user << "You begin welding on the fueltank and with a moment of lucidity you realize, this might not have been the smartest thing you've ever done." + var/obj/structure/reagent_dispensers/fueltank/tank = O + tank.explode() + return if (src.welding) remove_fuel(1) var/turf/location = get_turf(user) @@ -286,7 +291,7 @@ /obj/item/weapon/weldingtool/update_icon() ..() - icon_state = welding ? "welder1" : "welder" + icon_state = welding ? "[icon_state]1" : "[initial(icon_state)]" var/mob/M = loc if(istype(M)) M.update_inv_l_hand() @@ -313,7 +318,8 @@ processing_objects |= src else if(M) - M << "You need more welding fuel to complete this task." + var/msg = max_fuel ? "welding fuel" : "charge" + M << "You need more [msg] to complete this task." return //Otherwise else if(!set_welding && welding) @@ -370,7 +376,6 @@ user.disabilities &= ~NEARSIGHTED return - /obj/item/weapon/weldingtool/largetank name = "industrial welding tool" max_fuel = 40 @@ -405,6 +410,108 @@ if(get_fuel() < max_fuel && nextrefueltick < world.time) nextrefueltick = world.time + 10 reagents.add_reagent("fuel", 1) + +/* + * Electric/Arc Welder + */ + +/obj/item/weapon/weldingtool/electric //AND HIS WELDING WAS ELECTRIC + name = "electric welding tool" + icon_state = "arcwelder" + max_fuel = 0 //We'll handle the consumption later. + var/obj/item/weapon/cell/power_supply //What type of power cell this uses + var/charge_cost = 24 //The rough equivalent of 1 unit of fuel, based on us wanting 10 welds per battery + var/cell_type = null + var/use_external_power = 0 //If in a borg or hardsuit, this needs to = 1 + +/obj/item/weapon/weldingtool/electric/New() + ..() + if(cell_type) + power_supply = new cell_type(src) + else + power_supply = new /obj/item/weapon/cell/device(src) + update_icon() + +/obj/item/weapon/weldingtool/electric/examine(mob/user) + ..() + if(power_supply) + user << text("\icon[] [] has [] charge left.", src, src.name, get_fuel()) + else + user << text("\icon[] [] has power for no power cell!", src, src.name) + +/obj/item/weapon/weldingtool/electric/get_fuel() + if(use_external_power) + var/obj/item/weapon/cell/external = get_external_power_supply() + return external.charge + else if(power_supply) + return power_supply.charge + else + return 0 + +/obj/item/weapon/weldingtool/electric/remove_fuel(var/amount = 1, var/mob/M = null) + if(!welding) + return 0 + if(get_fuel() >= amount) + power_supply.checked_use(charge_cost) + if(use_external_power) + var/obj/item/weapon/cell/external = get_external_power_supply() + if(!external || !external.use(charge_cost)) //Take power from the borg... + power_supply.give(charge_cost) //Give it back to the cell. + if(M) + eyecheck(M) + return 1 + else + if(M) + M << "You need more energy to complete this task." + return 0 + +/obj/item/weapon/weldingtool/electric/attack_hand(mob/user as mob) + if(user.get_inactive_hand() == src) + if(power_supply) + power_supply.update_icon() + user.put_in_hands(power_supply) + power_supply = null + user << "You remove the cell from the [src]." + setWelding(0) + update_icon() + return + ..() + else + return ..() + +/obj/item/weapon/weldingtool/electric/attackby(obj/item/weapon/W, mob/user as mob) + if(istype(W, /obj/item/weapon/cell)) + if(istype(W, /obj/item/weapon/cell/device)) + if(!power_supply) + user.drop_item() + W.loc = src + power_supply = W + user << "You install a cell in \the [src]." + update_icon() + else + user << "\The [src] already has a cell." + else + user << "\The [src] cannot use that type of cell." + else + ..() + +/obj/item/weapon/weldingtool/electric/proc/get_external_power_supply() + if(isrobot(src.loc)) + var/mob/living/silicon/robot/R = src.loc + return R.cell + if(istype(src.loc, /obj/item/rig_module)) + var/obj/item/rig_module/module = src.loc + if(module.holder && module.holder.wearer) + var/mob/living/carbon/human/H = module.holder.wearer + if(istype(H) && H.back) + var/obj/item/weapon/rig/suit = H.back + if(istype(suit)) + return suit.cell + return null + +/obj/item/weapon/weldingtool/electric/mounted + use_external_power = 1 + /* * Crowbar */ diff --git a/code/game/objects/items/weapons/traps.dm b/code/game/objects/items/weapons/traps.dm index e5a655d7f97..cd11af34000 100644 --- a/code/game/objects/items/weapons/traps.dm +++ b/code/game/objects/items/weapons/traps.dm @@ -77,11 +77,15 @@ //armour var/blocked = L.run_armor_check(target_zone, "melee") + var/soaked = L.get_armor_soak(target_zone, "melee") if(blocked >= 100) return - if(!L.apply_damage(30, BRUTE, target_zone, blocked, used_weapon=src)) + if(soaked >= 30) + return + + if(!L.apply_damage(30, BRUTE, target_zone, blocked, soaked, used_weapon=src)) return 0 //trap the victim in place diff --git a/code/game/objects/structures.dm b/code/game/objects/structures.dm index f4e7f4d0569..928246b2b5c 100644 --- a/code/game/objects/structures.dm +++ b/code/game/objects/structures.dm @@ -174,7 +174,7 @@ return 0 if (user.stat || user.paralysis || user.sleeping || user.lying || user.weakened) return 0 - if (issilicon(user)) + if (isAI(user)) user << "You need hands for this." return 0 return 1 diff --git a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm index ae4fe4d7401..0e6064785d7 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm @@ -150,20 +150,22 @@ var/def_zone = ran_zone() var/blocked = occupant.run_armor_check(def_zone, "melee") + var/soaked = occupant.get_armor_soak(def_zone, "melee") occupant.throw_at(A, 3, propelled) occupant.apply_effect(6, STUN, blocked) occupant.apply_effect(6, WEAKEN, blocked) occupant.apply_effect(6, STUTTER, blocked) - occupant.apply_damage(10, BRUTE, def_zone, blocked) + occupant.apply_damage(10, BRUTE, def_zone, blocked, soaked) playsound(src.loc, 'sound/weapons/punch1.ogg', 50, 1, -1) if(istype(A, /mob/living)) var/mob/living/victim = A def_zone = ran_zone() blocked = victim.run_armor_check(def_zone, "melee") + soaked = victim.get_armor_soak(def_zone, "melee") victim.apply_effect(6, STUN, blocked) victim.apply_effect(6, WEAKEN, blocked) victim.apply_effect(6, STUTTER, blocked) - victim.apply_damage(10, BRUTE, def_zone, blocked) + victim.apply_damage(10, BRUTE, def_zone, blocked, soaked) occupant.visible_message("[occupant] crashed into \the [A]!") /obj/structure/bed/chair/office/light diff --git a/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm b/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm index 2bcbf8aa878..9ae19769eb1 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm @@ -149,20 +149,22 @@ var/def_zone = ran_zone() var/blocked = occupant.run_armor_check(def_zone, "melee") + var/soaked = occupant.get_armor_soak(def_zone, "melee") occupant.throw_at(A, 3, propelled) occupant.apply_effect(6, STUN, blocked) occupant.apply_effect(6, WEAKEN, blocked) occupant.apply_effect(6, STUTTER, blocked) - occupant.apply_damage(10, BRUTE, def_zone) + occupant.apply_damage(10, BRUTE, def_zone, soaked) playsound(src.loc, 'sound/weapons/punch1.ogg', 50, 1, -1) if(istype(A, /mob/living)) var/mob/living/victim = A def_zone = ran_zone() blocked = victim.run_armor_check(def_zone, "melee") + soaked = victim.get_armor_soak(def_zone, "melee") victim.apply_effect(6, STUN, blocked) victim.apply_effect(6, WEAKEN, blocked) victim.apply_effect(6, STUTTER, blocked) - victim.apply_damage(10, BRUTE, def_zone) + victim.apply_damage(10, BRUTE, def_zone, soaked) if(pulling) occupant.visible_message("[pulling] has thrusted \the [name] into \the [A], throwing \the [occupant] out of it!") diff --git a/code/game/turfs/simulated.dm b/code/game/turfs/simulated.dm index 08da1a66dd7..25ad0ce9cdb 100644 --- a/code/game/turfs/simulated.dm +++ b/code/game/turfs/simulated.dm @@ -178,3 +178,5 @@ this.blood_DNA["UNKNOWN BLOOD"] = "X*" else if( istype(M, /mob/living/silicon/robot )) new /obj/effect/decal/cleanable/blood/oil(src) + else if(ishuman(M)) + add_blood(M) \ No newline at end of file diff --git a/code/game/verbs/suicide.dm b/code/game/verbs/suicide.dm index 874b6f3998b..ec84ee42329 100644 --- a/code/game/verbs/suicide.dm +++ b/code/game/verbs/suicide.dm @@ -26,7 +26,7 @@ if(!canmove || restrained()) //just while I finish up the new 'fun' suiciding verb. This is to prevent metagaming via suicide src << "You can't commit suicide whilst restrained! ((You can type Ghost instead however.))" return - suiciding = 1 + suiciding = 15 does_not_breathe = 0 //Prevents ling-suicide zombies, or something var/obj/item/held_item = get_active_hand() if(held_item) @@ -73,10 +73,16 @@ return log_and_message_admins("[key_name(src)] commited suicide") - viewers(src) << pick("[src] is attempting to bite \his tongue off! It looks like \he's trying to commit suicide.", \ + + var/suicidemsg + suicidemsg = pick("[src] is attempting to bite \his tongue off! It looks like \he's trying to commit suicide.", \ "[src] is jamming \his thumbs into \his eye sockets! It looks like \he's trying to commit suicide.", \ "[src] is twisting \his own neck! It looks like \he's trying to commit suicide.", \ "[src] is holding \his breath! It looks like \he's trying to commit suicide.") + if(isSynthetic()) + suicidemsg = "[src] is attempting to switch \his power off! It looks like \he's trying to commit suicide." + visible_message(suicidemsg) + adjustOxyLoss(max(175 - getToxLoss() - getFireLoss() - getBruteLoss() - getOxyLoss(), 0)) updatehealth() @@ -172,7 +178,7 @@ var/confirm = alert("Are you sure you want to commit suicide?", "Confirm Suicide", "Yes", "No") if(confirm == "Yes") - suiciding = 1 + suiciding = 30 setOxyLoss(100) adjustBruteLoss(100 - getBruteLoss()) setToxLoss(100) diff --git a/code/modules/clothing/spacesuits/rig/modules/utility.dm b/code/modules/clothing/spacesuits/rig/modules/utility.dm index bcd81638538..820543f082f 100644 --- a/code/modules/clothing/spacesuits/rig/modules/utility.dm +++ b/code/modules/clothing/spacesuits/rig/modules/utility.dm @@ -157,6 +157,7 @@ list("antibiotics", "spaceacillin", 0, 20), list("antitoxins", "anti_toxin", 0, 20), list("nutrients", "glucose", 0, 80), + list("clotting agent", "myelamine", 0, 80), list("hyronalin", "hyronalin", 0, 20), list("radium", "radium", 0, 20) ) @@ -246,6 +247,7 @@ list("hyperzine", "hyperzine", 0, 30), list("oxycodone", "oxycodone", 0, 30), list("nutrients", "glucose", 0, 80), + list("clotting agent", "myelamine", 0, 80) ) interface_name = "combat chem dispenser" @@ -263,6 +265,20 @@ interface_name = "mounted chem injector" interface_desc = "Dispenses loaded chemicals via an arm-mounted injector." +/obj/item/rig_module/chem_dispenser/injector/advanced + + charges = list( + list("tricordrazine", "tricordrazine", 0, 80), + list("tramadol", "tramadol", 0, 80), + list("dexalin plus", "dexalinp", 0, 80), + list("antibiotics", "spaceacillin", 0, 80), + list("antitoxins", "anti_toxin", 0, 80), + list("nutrients", "glucose", 0, 80), + list("hyronalin", "hyronalin", 0, 80), + list("radium", "radium", 0, 80), + list("clotting agent", "myelamine", 0, 80) + ) + /obj/item/rig_module/voice name = "hardsuit voice synthesiser" diff --git a/code/modules/clothing/spacesuits/rig/rig.dm b/code/modules/clothing/spacesuits/rig/rig.dm index 0bd14ef9d16..855aa49c7e4 100644 --- a/code/modules/clothing/spacesuits/rig/rig.dm +++ b/code/modules/clothing/spacesuits/rig/rig.dm @@ -161,6 +161,7 @@ piece.permeability_coefficient = permeability_coefficient piece.unacidable = unacidable if(islist(armor)) piece.armor = armor.Copy() + if(islist(armorsoak)) piece.armorsoak = armorsoak.Copy() update_icon(1) diff --git a/code/modules/clothing/spacesuits/rig/suits/ert.dm b/code/modules/clothing/spacesuits/rig/suits/ert.dm index 8b13a57c8d5..5d0dd4cb8fc 100644 --- a/code/modules/clothing/spacesuits/rig/suits/ert.dm +++ b/code/modules/clothing/spacesuits/rig/suits/ert.dm @@ -49,7 +49,7 @@ /obj/item/rig_module/ai_container, /obj/item/rig_module/maneuvering_jets, /obj/item/rig_module/device/healthscanner, - /obj/item/rig_module/chem_dispenser/injector + /obj/item/rig_module/chem_dispenser/injector/advanced ) /obj/item/weapon/rig/ert/security diff --git a/code/modules/food/recipes_microwave.dm b/code/modules/food/recipes_microwave.dm index 3d63261a959..756aab62e4c 100644 --- a/code/modules/food/recipes_microwave.dm +++ b/code/modules/food/recipes_microwave.dm @@ -105,7 +105,7 @@ I said no! /datum/recipe/xenoburger items = list( /obj/item/weapon/reagent_containers/food/snacks/bun, - /obj/item/weapon/reagent_containers/food/snacks/xenomeat + /obj/item/weapon/reagent_containers/food/snacks/spidermeat // /obj/item/weapon/reagent_containers/food/snacks/xenomeat ) result = /obj/item/weapon/reagent_containers/food/snacks/xenoburger @@ -224,9 +224,9 @@ I said no! /obj/item/weapon/reagent_containers/food/snacks/dough, /obj/item/weapon/reagent_containers/food/snacks/dough, /obj/item/weapon/reagent_containers/food/snacks/dough, - /obj/item/weapon/reagent_containers/food/snacks/xenomeat, - /obj/item/weapon/reagent_containers/food/snacks/xenomeat, - /obj/item/weapon/reagent_containers/food/snacks/xenomeat, + /obj/item/weapon/reagent_containers/food/snacks/spidermeat, //xenomeat, + /obj/item/weapon/reagent_containers/food/snacks/spidermeat, //xenomeat, + /obj/item/weapon/reagent_containers/food/snacks/spidermeat, //xenomeat, /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, /obj/item/weapon/reagent_containers/food/snacks/cheesewedge, diff --git a/code/modules/hydroponics/seed.dm b/code/modules/hydroponics/seed.dm index f6388e0190e..1d92705deca 100644 --- a/code/modules/hydroponics/seed.dm +++ b/code/modules/hydroponics/seed.dm @@ -114,8 +114,11 @@ if(!target_limb) target_limb = pick(BP_ALL) var/blocked = target.run_armor_check(target_limb, "melee") + var/soaked = target.get_armor_soak(target_limb, "melee") + if(blocked >= 100) return + var/obj/item/organ/external/affecting = target.get_organ(target_limb) var/damage = 0 var/has_edge = 0 @@ -125,7 +128,7 @@ if(affecting) to_chat(target, "\The [fruit]'s thorns pierce your [affecting.name] greedily!") - target.apply_damage(damage, BRUTE, target_limb, blocked, "Thorns", sharp=1, edge=has_edge) + target.apply_damage(damage, BRUTE, target_limb, blocked, soaked, "Thorns", sharp=1, edge=has_edge) else to_chat(target, "\The [fruit]'s thorns pierce your flesh greedily!") target.adjustBruteLoss(damage) diff --git a/code/modules/mob/living/carbon/brain/life.dm b/code/modules/mob/living/carbon/brain/life.dm index cb889b570f1..3f41f21ce55 100644 --- a/code/modules/mob/living/carbon/brain/life.dm +++ b/code/modules/mob/living/carbon/brain/life.dm @@ -71,15 +71,11 @@ /mob/living/carbon/brain/handle_chemicals_in_body() chem_effects.Cut() - analgesic = 0 if(touching) touching.metabolize() if(ingested) ingested.metabolize() if(bloodstr) bloodstr.metabolize() - if(CE_PAINKILLER in chem_effects) - analgesic = chem_effects[CE_PAINKILLER] - confused = max(0, confused - 1) // decrement dizziness counter, clamped to 0 if(resting) diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index db59f6bc832..66ba7ecd514 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -4,7 +4,7 @@ return null ..() -/mob/living/carbon/standard_weapon_hit_effects(obj/item/I, mob/living/user, var/effective_force, var/blocked, var/hit_zone) +/mob/living/carbon/standard_weapon_hit_effects(obj/item/I, mob/living/user, var/effective_force, var/blocked, var/soaked, var/hit_zone) if(!effective_force || blocked >= 100) return 0 @@ -12,6 +12,10 @@ if(HULK in user.mutations) effective_force *= 2 + //If the armor soaks all of the damage, it just skips the rest of the checks + if(effective_force <= soaked) + return 0 + //Apply weapon damage var/weapon_sharp = is_sharp(I) var/weapon_edge = has_edge(I) diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm index d6deb9b9649..532b2daa7c0 100644 --- a/code/modules/mob/living/carbon/carbon_defines.dm +++ b/code/modules/mob/living/carbon/carbon_defines.dm @@ -7,8 +7,7 @@ var/last_eating = 0 //Not sure what this does... I found it hidden in food.dm var/life_tick = 0 // The amount of life ticks that have processed on this mob. - var/analgesic = 0 // when this is set, the mob isn't affected by shock or pain - // life should decrease this by 1 every tick + // total amount of wounds on mob, used to spread out healing and the like over all wounds var/number_wounds = 0 var/obj/item/handcuffed = null //Whether or not the mob is handcuffed diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index fb18cd2df2d..fad3c7de1b7 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1050,7 +1050,7 @@ "A spike of pain jolts your [organ.name] as you bump [O] inside.", \ "Your movement jostles [O] in your [organ.name] painfully.", \ "Your movement jostles [O] in your [organ.name] painfully.") - src << msg + custom_pain(msg, 40) organ.take_damage(rand(1,3), 0, 0) if(!(organ.robotic >= ORGAN_ROBOT) && (should_have_organ(O_HEART))) //There is no blood in protheses. @@ -1489,7 +1489,7 @@ if(check_organ) if(!istype(check_organ)) return 0 - return check_organ.can_feel_pain() + return check_organ.organ_can_feel_pain() return !(species.flags & NO_PAIN) /mob/living/carbon/human/is_muzzled() diff --git a/code/modules/mob/living/carbon/human/human_attackhand.dm b/code/modules/mob/living/carbon/human/human_attackhand.dm index fccf6afbf68..01005b031b9 100644 --- a/code/modules/mob/living/carbon/human/human_attackhand.dm +++ b/code/modules/mob/living/carbon/human/human_attackhand.dm @@ -43,6 +43,7 @@ return 0 var/obj/item/organ/external/affecting = get_organ(ran_zone(H.zone_sel.selecting)) var/armor_block = run_armor_check(affecting, "melee") + var/armor_soak = get_armor_soak(affecting, "melee") if(HULK in H.mutations) damage += 5 @@ -51,7 +52,10 @@ visible_message("\red [H] has punched [src]!") - apply_damage(damage, HALLOSS, affecting, armor_block) + if(armor_soak >= damage) + return + + apply_damage(damage, HALLOSS, affecting, armor_block, armor_soak) if(damage >= 9) visible_message("\red [H] has weakened [src]!") apply_effect(4, WEAKEN, armor_block) @@ -245,11 +249,12 @@ real_damage = max(1, real_damage) var/armour = run_armor_check(affecting, "melee") + var/soaked = get_armor_soak(affecting, "melee") // Apply additional unarmed effects. attack.apply_effects(H, src, armour, rand_damage, hit_zone) // Finally, apply damage to target - apply_damage(real_damage, (attack.deal_halloss ? HALLOSS : BRUTE), affecting, armour, sharp=attack.sharp, edge=attack.edge) + apply_damage(real_damage, (attack.deal_halloss ? HALLOSS : BRUTE), affecting, armour, soaked, sharp=attack.sharp, edge=attack.edge) if(I_DISARM) M.attack_log += text("\[[time_stamp()]\] Disarmed [src.name] ([src.ckey])") @@ -325,7 +330,8 @@ var/dam_zone = pick(organs_by_name) var/obj/item/organ/external/affecting = get_organ(ran_zone(dam_zone)) var/armor_block = run_armor_check(affecting, "melee") - apply_damage(damage, BRUTE, affecting, armor_block) + var/armor_soak = get_armor_soak(affecting, "melee") + apply_damage(damage, BRUTE, affecting, armor_block, armor_soak) updatehealth() return 1 diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm index 50b2732eeb5..fa3d19ebabe 100644 --- a/code/modules/mob/living/carbon/human/human_damage.dm +++ b/code/modules/mob/living/carbon/human/human_damage.dm @@ -376,7 +376,7 @@ This function restores all organs. if((damagetype != BRUTE) && (damagetype != BURN)) if(damagetype == HALLOSS) if((damage > 25 && prob(20)) || (damage > 50 && prob(60))) - if(organ && organ.can_feel_pain()) + if(organ && organ.organ_can_feel_pain()) emote("scream") ..(damage, damagetype, def_zone, blocked) return 1 diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index a6471c4aeb4..86bbdebc15e 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -67,7 +67,7 @@ emp_act emote("me", 1, "drops what they were holding, their [affected.name] malfunctioning!") else var/emote_scream = pick("screams in pain and ", "lets out a sharp cry and ", "cries out and ") - emote("me", 1, "[affected.can_feel_pain() ? "" : emote_scream]drops what they were holding in their [affected.name]!") + emote("me", 1, "[affected.organ_can_feel_pain() ? "" : emote_scream] drops what they were holding in their [affected.name]!") ..(stun_amount, agony_amount, def_zone) @@ -93,6 +93,29 @@ emp_act total += weight return (armorval/max(total, 1)) +//Like getarmor, but the value it returns will be numerical damage reduction +/mob/living/carbon/human/getsoak(var/def_zone, var/type) + var/soakval = 0 + var/total = 0 + + if(def_zone) + if(isorgan(def_zone)) + return getsoak_organ(def_zone, type) + var/obj/item/organ/external/affecting = get_organ(def_zone) + if(affecting) + return getsoak_organ(affecting, type) + //If a specific bodypart is targetted, check how that bodypart is protected and return the value. + + //If you don't specify a bodypart, it checks ALL your bodyparts for protection, and averages out the values + for(var/organ_name in organs_by_name) + if (organ_name in organ_rel_size) + var/obj/item/organ/external/organ = organs_by_name[organ_name] + if(organ) + var/weight = organ_rel_size[organ_name] + soakval += getsoak_organ(organ, type) * weight + total += weight + return (soakval/max(total, 1)) + //this proc returns the Siemens coefficient of electrical resistivity for a particular external organ. /mob/living/carbon/human/proc/get_siemens_coefficient_organ(var/obj/item/organ/external/def_zone) if (!def_zone) @@ -119,6 +142,17 @@ emp_act protection += C.armor[type] return protection +/mob/living/carbon/human/proc/getsoak_organ(var/obj/item/organ/external/def_zone, var/type) + if(!type || !def_zone) return 0 + var/soaked = 0 + var/list/protective_gear = list(head, wear_mask, wear_suit, w_uniform, gloves, shoes) + for(var/gear in protective_gear) + if(gear && istype(gear ,/obj/item/clothing)) + var/obj/item/clothing/C = gear + if(istype(C) && C.body_parts_covered & def_zone.body_part) + soaked += C.armorsoak[type] + return soaked + /mob/living/carbon/human/proc/check_head_coverage() var/list/body_parts = list(head, wear_mask, wear_suit, w_uniform) @@ -195,25 +229,35 @@ emp_act visible_message("[src] has been [I.attack_verb.len? pick(I.attack_verb) : "attacked"] in the [affecting.name] with [I.name] by [user]!") + var/soaked = get_armor_soak(hit_zone, "melee", I.armor_penetration) + + if(soaked >= effective_force) + src << "Your armor absorbs the force of [I.name]!" + return + var/blocked = run_armor_check(hit_zone, "melee", I.armor_penetration, "Your armor has protected your [affecting.name].", "Your armor has softened the blow to your [affecting.name].") - standard_weapon_hit_effects(I, user, effective_force, blocked, hit_zone) + + standard_weapon_hit_effects(I, user, effective_force, blocked, soaked, hit_zone) return blocked -/mob/living/carbon/human/standard_weapon_hit_effects(obj/item/I, mob/living/user, var/effective_force, var/blocked, var/hit_zone) +/mob/living/carbon/human/standard_weapon_hit_effects(obj/item/I, mob/living/user, var/effective_force, var/blocked, var/soaked, var/hit_zone) var/obj/item/organ/external/affecting = get_organ(hit_zone) if(!affecting) return 0 + if(soaked >= effective_force) + return 0 + // Handle striking to cripple. if(user.a_intent == I_DISARM) effective_force *= 0.5 //reduced effective force... - if(!..(I, user, effective_force, blocked, hit_zone)) + if(!..(I, user, effective_force, blocked, soaked, hit_zone)) return 0 //set the dislocate mult less than the effective force mult so that //dislocating limbs on disarm is a bit easier than breaking limbs on harm - attack_joint(affecting, I, effective_force, 0.75, blocked) //...but can dislocate joints + attack_joint(affecting, I, effective_force, 0.75, blocked, soaked) //...but can dislocate joints else if(!..()) return 0 @@ -243,7 +287,7 @@ emp_act switch(hit_zone) if("head")//Harder to score a stun but if you do it lasts a bit longer if(prob(effective_force)) - apply_effect(20, PARALYZE, blocked) + apply_effect(20, PARALYZE, blocked, soaked) visible_message("\The [src] has been knocked unconscious!") if(bloody)//Apply blood if(wear_mask) @@ -257,15 +301,15 @@ emp_act update_inv_glasses(0) if("chest")//Easier to score a stun but lasts less time if(prob(effective_force + 10)) - apply_effect(6, WEAKEN, blocked) + apply_effect(6, WEAKEN, blocked, soaked) visible_message("\The [src] has been knocked down!") if(bloody) bloody_body(src) return 1 -/mob/living/carbon/human/proc/attack_joint(var/obj/item/organ/external/organ, var/obj/item/W, var/effective_force, var/dislocate_mult, var/blocked) - if(!organ || (organ.dislocated == 2) || (organ.dislocated == -1) || blocked >= 100) +/mob/living/carbon/human/proc/attack_joint(var/obj/item/organ/external/organ, var/obj/item/W, var/effective_force, var/dislocate_mult, var/blocked, var/soaked) + if(!organ || (organ.dislocated == 2) || (organ.dislocated == -1) || blocked >= 100 || soaked > effective_force) return 0 if(W.damtype != BRUTE) @@ -338,10 +382,6 @@ emp_act var/hit_area = affecting.name src.visible_message("\red [src] has been hit in the [hit_area] by [O].") - var/armor = run_armor_check(affecting, "melee", O.armor_penetration, "Your armor has protected your [hit_area].", "Your armor has softened hit to your [hit_area].") //I guess "melee" is the best fit here - - if(armor < 100) - apply_damage(throw_damage, dtype, zone, armor, is_sharp(O), has_edge(O), O) if(ismob(O.thrower)) var/mob/M = O.thrower @@ -352,12 +392,25 @@ emp_act if(!istype(src,/mob/living/simple_animal/mouse)) msg_admin_attack("[src.name] ([src.ckey]) was hit by a [O], thrown by [M.name] ([assailant.ckey]) (JMP)") + //If the armor absorbs all of the damage, skip the rest of the calculations + var/soaked = get_armor_soak(affecting, "melee", O.armor_penetration) + if(soaked >= throw_damage) + src << "Your armor absorbs the force of [O.name]!" + return + + var/armor = run_armor_check(affecting, "melee", O.armor_penetration, "Your armor has protected your [hit_area].", "Your armor has softened hit to your [hit_area].") //I guess "melee" is the best fit here + if(armor < 100) + apply_damage(throw_damage, dtype, zone, armor, soaked, is_sharp(O), has_edge(O), O) + + //thrown weapon embedded object code. if(dtype == BRUTE && istype(O,/obj/item)) var/obj/item/I = O if (!is_robot_module(I)) var/sharp = is_sharp(I) var/damage = throw_damage + if (soaked) + damage -= soaked if (armor) damage /= armor+1 diff --git a/code/modules/mob/living/carbon/human/human_organs.dm b/code/modules/mob/living/carbon/human/human_organs.dm index 0338876627b..7c4e38730f6 100644 --- a/code/modules/mob/living/carbon/human/human_organs.dm +++ b/code/modules/mob/living/carbon/human/human_organs.dm @@ -56,7 +56,7 @@ if (!lying && !buckled && world.time - l_move_time < 15) //Moving around with fractured ribs won't do you any good - if (prob(10) && !stat && can_feel_pain() && analgesic < 50 && E.is_broken() && E.internal_organs.len) + if (prob(10) && !stat && can_feel_pain() && chem_effects[CE_PAINKILLER] < 50 && E.is_broken() && E.internal_organs.len) custom_pain("Pain jolts through your broken [E.encased ? E.encased : E.name], staggering you!", 50) drop_item(loc) Stun(2) @@ -100,7 +100,7 @@ else if (E.is_dislocated()) stance_damage += 0.5 - if(E) limb_pain = E.can_feel_pain() + if(E) limb_pain = E.organ_can_feel_pain() // Canes and crutches help you stand (if the latter is ever added) // One cane mitigates a broken leg+foot, or a missing foot. @@ -159,7 +159,7 @@ drop_from_inventory(r_hand) var/emote_scream = pick("screams in pain and ", "lets out a sharp cry and ", "cries out and ") - emote("me", 1, "[(E.can_feel_pain()) ? "" : emote_scream ]drops what they were holding in their [E.name]!") + emote("me", 1, "[(can_feel_pain()) ? "" : emote_scream ]drops what they were holding in their [E.name]!") else if(E.is_malfunctioning()) switch(E.body_part) diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index 014ba7eb0d1..7ecf8cd8eff 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -186,7 +186,7 @@ var/rn = rand(0, 200) if(getBrainLoss() >= 5) if(0 <= rn && rn <= 3) - custom_pain("Your head feels numb and painful.") + custom_pain("Your head feels numb and painful.", 10) if(getBrainLoss() >= 15) if(4 <= rn && rn <= 6) if(eye_blurry <= 0) src << "It becomes hard to see for some reason." @@ -328,17 +328,20 @@ if(status_flags & GODMODE) return + if(suiciding) + failed_last_breath = 1 + adjustOxyLoss(2)//If you are suiciding, you should die a little bit faster + oxygen_alert = max(oxygen_alert, 1) + suiciding -- + return 0 + if(does_not_breathe) failed_last_breath = 0 adjustOxyLoss(-5) return - if(!breath || (breath.total_moles == 0) || suiciding) + if(!breath || (breath.total_moles == 0)) failed_last_breath = 1 - if(suiciding) - adjustOxyLoss(2)//If you are suiciding, you should die a little bit faster - oxygen_alert = max(oxygen_alert, 1) - return 0 if(health > config.health_threshold_crit) adjustOxyLoss(HUMAN_MAX_OXYLOSS) else @@ -350,8 +353,11 @@ rupture_lung() if(should_have_organ("brain")) + var/brainOxPercent = 0.02 //Default2% of your current oxyloss is applied as brain damage, 50 oxyloss is 1 brain damage + if(CE_STABLE in chem_effects) + brainOxPercent = 0.01 //Halved in effect if(prob(5)) - adjustBrainLoss(0.02 * oxyloss) //2% of your current oxyloss is applied as brain damage, 50 oxyloss is 1 brain damage + adjustBrainLoss(brainOxPercent * oxyloss) oxygen_alert = max(oxygen_alert, 1) @@ -794,7 +800,6 @@ if(reagents) chem_effects.Cut() - analgesic = 0 if(!isSynthetic()) @@ -802,9 +807,6 @@ if(ingested) ingested.metabolize() if(bloodstr) bloodstr.metabolize() - if(CE_PAINKILLER in chem_effects) - analgesic = chem_effects[CE_PAINKILLER] - var/total_phoronloss = 0 for(var/obj/item/I in src) if(I.contaminated) @@ -1155,7 +1157,7 @@ see_invisible = SEE_INVISIBLE_LIVING if(healths) - if (analgesic > 100) + if (chem_effects[CE_PAINKILLER] > 100) healths.icon_state = "health_numb" else // Generate a by-limb health display. @@ -1437,8 +1439,11 @@ shock_stage = max(shock_stage-1, 0) return + if(stat) + return 0 + if(shock_stage == 10) - src << "[pick("It hurts so much", "You really need some painkillers", "Dear god, the pain")]!" + custom_pain("[pick("It hurts so much", "You really need some painkillers", "Dear god, the pain")]!", 40) if(shock_stage >= 30) if(shock_stage == 30) emote("me",1,"is having trouble keeping their eyes open.") diff --git a/code/modules/mob/living/carbon/human/unarmed_attack.dm b/code/modules/mob/living/carbon/human/unarmed_attack.dm index af3e65b0913..2de060887f0 100644 --- a/code/modules/mob/living/carbon/human/unarmed_attack.dm +++ b/code/modules/mob/living/carbon/human/unarmed_attack.dm @@ -97,7 +97,7 @@ var/global/list/sparring_attack_cache = list() if(eyes) eyes.take_damage(rand(3,4), 1) user.visible_message("[user] presses \his [eye_attack_text] into [target]'s [eyes.name]!") - var/eye_pain = eyes.can_feel_pain() + var/eye_pain = eyes.organ_can_feel_pain() target << "You experience[(eye_pain) ? "" : " immense pain as you feel" ] [eye_attack_text_victim] being pressed into your [eyes.name][(eye_pain)? "." : "!"]" return user.visible_message("[user] attempts to press \his [eye_attack_text] into [target]'s eyes, but they don't have any!") diff --git a/code/modules/mob/living/carbon/metroid/life.dm b/code/modules/mob/living/carbon/metroid/life.dm index 69ddb590380..7bbc4110dde 100644 --- a/code/modules/mob/living/carbon/metroid/life.dm +++ b/code/modules/mob/living/carbon/metroid/life.dm @@ -67,15 +67,11 @@ /mob/living/carbon/slime/handle_chemicals_in_body() chem_effects.Cut() - analgesic = 0 if(touching) touching.metabolize() if(ingested) ingested.metabolize() if(bloodstr) bloodstr.metabolize() - if(CE_PAINKILLER in chem_effects) - analgesic = chem_effects[CE_PAINKILLER] - src.updatehealth() return //TODO: DEFERRED diff --git a/code/modules/mob/living/carbon/metroid/powers.dm b/code/modules/mob/living/carbon/metroid/powers.dm index 2e1cc295950..933596ef5e2 100644 --- a/code/modules/mob/living/carbon/metroid/powers.dm +++ b/code/modules/mob/living/carbon/metroid/powers.dm @@ -60,7 +60,7 @@ var/painMes = pick("You can feel your body becoming weak!", "You feel like you're about to die!", "You feel every part of your body screaming in agony!", "A low, rolling pain passes through your body!", "Your body feels as if it's falling apart!", "You feel extremely weak!", "A sharp, deep pain bathes every inch of your body!") if (ishuman(M)) var/mob/living/carbon/human/H = M - H.custom_pain(painMes) + H.custom_pain(painMes, 100) else if (istype(M, /mob/living/carbon)) var/mob/living/carbon/C = M if (C.can_feel_pain()) diff --git a/code/modules/mob/living/carbon/shock.dm b/code/modules/mob/living/carbon/shock.dm index a742bc8959d..894a0a98b02 100644 --- a/code/modules/mob/living/carbon/shock.dm +++ b/code/modules/mob/living/carbon/shock.dm @@ -14,7 +14,7 @@ 1.2 * src.getShockBruteLoss() + \ 1.7 * src.getCloneLoss() + \ 2 * src.halloss + \ - -1 * src.analgesic + -1 * src.chem_effects[CE_PAINKILLER] if(src.slurring) src.traumatic_shock -= 20 diff --git a/code/modules/mob/living/damage_procs.dm b/code/modules/mob/living/damage_procs.dm index f09eb3741f8..552319e6fe4 100644 --- a/code/modules/mob/living/damage_procs.dm +++ b/code/modules/mob/living/damage_procs.dm @@ -8,11 +8,13 @@ Returns standard 0 if fail */ -/mob/living/proc/apply_damage(var/damage = 0,var/damagetype = BRUTE, var/def_zone = null, var/blocked = 0, var/used_weapon = null, var/sharp = 0, var/edge = 0) +/mob/living/proc/apply_damage(var/damage = 0,var/damagetype = BRUTE, var/def_zone = null, var/blocked = 0, var/soaked = 0, var/used_weapon = null, var/sharp = 0, var/edge = 0) if(Debug2) world.log << "## DEBUG: apply_damage() was called on [src], with [damage] damage, and an armor value of [blocked]." - if(!damage || (blocked >= 100)) + if(!damage || (blocked >= 100) || soaked >= damage) return 0 + if(soaked) + damage -= soaked blocked = (100-blocked)/100 switch(damagetype) if(BRUTE) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 7680b6e163c..dfe57c55b2d 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -716,11 +716,20 @@ default behaviour is: src << "You feel like you are about to throw up!" sleep(100) //and you have 10 more for mad dash to the bucket + //Damaged livers cause you to vomit blood. + if(!blood_vomit) + if(ishuman(src)) + var/mob/living/carbon/human/H = src + if(!H.isSynthetic()) + var/obj/item/organ/internal/liver/L = H.internal_organs_by_name["liver"] + if(L.is_broken()) + blood_vomit = 1 + Stun(5) src.visible_message("[src] throws up!","You throw up!") playsound(loc, 'sound/effects/splat.ogg', 50, 1) - var/turf/simulated/T = get_turf(src) + var/turf/simulated/T = get_turf(src) //TODO: Make add_blood_floor remove blood from human mobs if(istype(T)) if(blood_vomit) T.add_blood_floor(src) diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 17eff101bb4..c52311820e3 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -77,10 +77,20 @@ return 0 */ +//Certain pieces of armor actually absorb flat amounts of damage from income attacks +/mob/living/proc/get_armor_soak(var/def_zone = null, var/attack_flag = "melee", var/armour_pen = 0) + var/soaked = getsoak(def_zone, attack_flag) + //5 points of armor pen negate one point of soak + if(armour_pen) + soaked = max(soaked - (armour_pen/5), 0) + return soaked + //if null is passed for def_zone, then this should return something appropriate for all zones (e.g. area effect damage) /mob/living/proc/getarmor(var/def_zone, var/type) return 0 +/mob/living/proc/getsoak(var/def_zone, var/type) + return 0 /mob/living/bullet_act(var/obj/item/projectile/P, var/def_zone) @@ -93,6 +103,7 @@ signaler.signal() //Armor + var/soaked = get_armor_soak(def_zone, P.check_armour, P.armor_penetration) var/absorb = run_armor_check(def_zone, P.check_armour, P.armor_penetration) var/proj_sharp = is_sharp(P) var/proj_edge = has_edge(P) @@ -105,13 +116,13 @@ stun_effect_act(0, P.agony, def_zone, P) src <<"\red You have been hit by [P]!" if(!P.nodamage) - apply_damage(P.damage, P.damage_type, def_zone, absorb, 0, P, sharp=proj_sharp, edge=proj_edge) + apply_damage(P.damage, P.damage_type, def_zone, absorb, soaked, 0, P, sharp=proj_sharp, edge=proj_edge) qdel(P) return if(!P.nodamage) - apply_damage(P.damage, P.damage_type, def_zone, absorb, 0, P, sharp=proj_sharp, edge=proj_edge) - P.on_hit(src, absorb, def_zone) + apply_damage(P.damage, P.damage_type, def_zone, absorb, soaked, 0, P, sharp=proj_sharp, edge=proj_edge) + P.on_hit(src, absorb, soaked, def_zone) if(absorb == 100) return 2 @@ -153,17 +164,21 @@ /mob/living/proc/hit_with_weapon(obj/item/I, mob/living/user, var/effective_force, var/hit_zone) visible_message("[src] has been [I.attack_verb.len? pick(I.attack_verb) : "attacked"] with [I.name] by [user]!") + var/soaked = get_armor_soak(hit_zone, "melee") var/blocked = run_armor_check(hit_zone, "melee") - standard_weapon_hit_effects(I, user, effective_force, blocked, hit_zone) - if(I.damtype == BRUTE && prob(33)) // Added blood for whacking non-humans too - var/turf/simulated/location = get_turf(src) - if(istype(location)) location.add_blood_floor(src) + //If the armor absorbs all of the damage, skip the damage calculation and the blood + if(!soaked > effective_force) + standard_weapon_hit_effects(I, user, effective_force, blocked, soaked, hit_zone) + + if(I.damtype == BRUTE && prob(33)) // Added blood for whacking non-humans too + var/turf/simulated/location = get_turf(src) + if(istype(location)) location.add_blood_floor(src) return blocked //returns 0 if the effects failed to apply for some reason, 1 otherwise. -/mob/living/proc/standard_weapon_hit_effects(obj/item/I, mob/living/user, var/effective_force, var/blocked, var/hit_zone) +/mob/living/proc/standard_weapon_hit_effects(obj/item/I, mob/living/user, var/effective_force, var/blocked, var/soaked, var/hit_zone) if(!effective_force || blocked >= 100) return 0 @@ -171,6 +186,10 @@ if(HULK in user.mutations) effective_force *= 2 + //Armor soak + if(soaked >= effective_force) + return 0 + //Apply weapon damage var/weapon_sharp = is_sharp(I) var/weapon_edge = has_edge(I) @@ -178,7 +197,7 @@ weapon_sharp = 0 weapon_edge = 0 - apply_damage(effective_force, I.damtype, hit_zone, blocked, sharp=weapon_sharp, edge=weapon_edge, used_weapon=I) + apply_damage(effective_force, I.damtype, hit_zone, blocked, soaked, sharp=weapon_sharp, edge=weapon_edge, used_weapon=I) return 1 @@ -200,8 +219,10 @@ src.visible_message("\red [src] has been hit by [O].") var/armor = run_armor_check(null, "melee") + var/soaked = get_armor_soak(null, "melee") - apply_damage(throw_damage, dtype, null, armor, is_sharp(O), has_edge(O), O) + + apply_damage(throw_damage, dtype, null, armor, soaked, is_sharp(O), has_edge(O), O) O.throwing = 0 //it hit, so stop moving @@ -230,6 +251,9 @@ if(!O || !src) return if(O.sharp) //Projectile is suitable for pinning. + if(soaked >= throw_damage) //Don't embed if it didn't actually damage + return + //Handles embedding for non-humans and simple_animals. embed(O) diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index c7856f5082f..fd4f706b153 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -11,6 +11,7 @@ var/list/department_radio_keys = list( ":s" = "Security", ".s" = "Security", ":w" = "whisper", ".w" = "whisper", ":t" = "Mercenary", ".t" = "Mercenary", + ":x" = "Raider", ".x" = "Raider", ":u" = "Supply", ".u" = "Supply", ":v" = "Service", ".v" = "Service", ":p" = "AI Private", ".p" = "AI Private", @@ -26,6 +27,7 @@ var/list/department_radio_keys = list( ":S" = "Security", ".S" = "Security", ":W" = "whisper", ".W" = "whisper", ":T" = "Mercenary", ".T" = "Mercenary", + ":X" = "Raider", ".X" = "Raider", ":U" = "Supply", ".U" = "Supply", ":V" = "Service", ".V" = "Service", ":P" = "AI Private", ".P" = "AI Private", diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm index f16ead995dd..ccfd19e8aa7 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -347,7 +347,7 @@ var/global/list/robot_modules = list( src.modules += new /obj/item/weapon/rcd/borg(src) src.modules += new /obj/item/weapon/screwdriver(src) src.modules += new /obj/item/weapon/wrench(src) - src.modules += new /obj/item/weapon/weldingtool/largetank(src) + src.modules += new /obj/item/weapon/weldingtool/electric/mounted(src) src.modules += new /obj/item/weapon/pickaxe/plasmacutter(src) src.modules += new /obj/item/device/pipe_painter(src) src.modules += new /obj/item/device/floor_painter(src) @@ -383,7 +383,7 @@ var/global/list/robot_modules = list( /obj/item/weapon/robot_module/robot/engineering/general/New() ..() src.modules += new /obj/item/borg/sight/meson(src) - src.modules += new /obj/item/weapon/weldingtool/largetank(src) + src.modules += new /obj/item/weapon/weldingtool/electric/mounted(src) src.modules += new /obj/item/weapon/screwdriver(src) src.modules += new /obj/item/weapon/wrench(src) src.modules += new /obj/item/weapon/wirecutters(src) @@ -680,7 +680,7 @@ var/global/list/robot_modules = list( src.modules += new /obj/item/weapon/gripper/no_use/loader(src) src.modules += new /obj/item/device/robotanalyzer(src) src.modules += new /obj/item/weapon/card/robot(src) - src.modules += new /obj/item/weapon/weldingtool/largetank(src) + src.modules += new /obj/item/weapon/weldingtool/electric/mounted(src) src.modules += new /obj/item/weapon/screwdriver(src) src.modules += new /obj/item/weapon/wrench(src) src.modules += new /obj/item/weapon/wirecutters(src) @@ -776,7 +776,8 @@ var/global/list/robot_modules = list( /obj/item/weapon/robot_module/drone/New(var/mob/living/silicon/robot/robot) ..() - src.modules += new /obj/item/weapon/weldingtool(src) + src.modules += new /obj/item/borg/sight/meson(src) + src.modules += new /obj/item/weapon/weldingtool/electric/mounted(src) src.modules += new /obj/item/weapon/screwdriver(src) src.modules += new /obj/item/weapon/wrench(src) src.modules += new /obj/item/weapon/crowbar(src) diff --git a/code/modules/mob/living/simple_animal/animals/bear.dm b/code/modules/mob/living/simple_animal/animals/bear.dm index 9d1da5e08b8..228e92e5b77 100644 --- a/code/modules/mob/living/simple_animal/animals/bear.dm +++ b/code/modules/mob/living/simple_animal/animals/bear.dm @@ -1,125 +1,125 @@ -//Space bears! -/mob/living/simple_animal/hostile/bear - name = "space bear" - desc = "RawrRawr!!" - icon_state = "bear" - icon_living = "bear" - icon_dead = "bear_dead" - icon_gib = "bear_gib" - - faction = "russian" - cooperative = 1 - - maxHealth = 60 - health = 60 - turns_per_move = 5 - see_in_dark = 6 - stop_when_pulled = 0 - - response_help = "pets" - response_disarm = "gently pushes aside" - response_harm = "pokes" - - melee_damage_lower = 20 - melee_damage_upper = 30 - - //Space bears aren't affected by atmos. - min_oxy = 0 - max_oxy = 0 - min_tox = 0 - max_tox = 0 - min_co2 = 0 - max_co2 = 0 - min_n2 = 0 - max_n2 = 0 - minbodytemp = 0 - - speak_chance = 1 - speak = list("RAWR!","Rawr!","GRR!","Growl!") - speak_emote = list("growls", "roars") - emote_hear = list("rawrs","grumbles","grawls") - emote_see = list("stares ferociously", "stomps") - - meat_type = /obj/item/weapon/reagent_containers/food/snacks/bearmeat - - var/stance_step = 0 - -/mob/living/simple_animal/hostile/bear/handle_stance() - switch(stance) - if(STANCE_TIRED) - stop_automated_movement = 1 - stance_step++ - if(stance_step >= 10) //rests for 10 ticks - if(target_mob && target_mob in ListTargets(10)) - handle_stance(STANCE_ATTACK) //If the mob he was chasing is still nearby, resume the attack, otherwise go idle. - else - handle_stance(STANCE_IDLE) - - if(STANCE_ALERT) - stop_automated_movement = 1 - var/found_mob = 0 - if(target_mob && target_mob in ListTargets(10)) - if(!(SA_attackable(target_mob))) - stance_step = max(0, stance_step) //If we have not seen a mob in a while, the stance_step will be negative, we need to reset it to 0 as soon as we see a mob again. - stance_step++ - found_mob = 1 - src.set_dir(get_dir(src,target_mob)) //Keep staring at the mob - - if(stance_step in list(1,4,7)) //every 3 ticks - var/action = pick( list( "growls at [target_mob]", "stares angrily at [target_mob]", "prepares to attack [target_mob]", "closely watches [target_mob]" ) ) - if(action) - custom_emote(1,action) - if(!found_mob) - stance_step-- - - if(stance_step <= -20) //If we have not found a mob for 20-ish ticks, revert to idle mode - handle_stance(STANCE_IDLE) - if(stance_step >= 7) //If we have been staring at a mob for 7 ticks, - handle_stance(STANCE_ATTACK) - - if(STANCE_ATTACKING) - if(stance_step >= 20) //attacks for 20 ticks, then it gets tired and needs to rest - custom_emote(1, "is worn out and needs to rest." ) - handle_stance(STANCE_TIRED) - stance_step = 0 - walk(src, 0) //This stops the bear's walking - return - else - ..() - -/mob/living/simple_animal/hostile/bear/update_icons() - ..() - if(!stat) - if(loc && istype(loc,/turf/space)) - icon_state = "bear" - else - icon_state = "bearfloor" - -/mob/living/simple_animal/hostile/bear/Process_Spacemove(var/check_drift = 0) - return - -/mob/living/simple_animal/hostile/bear/FindTarget() - . = ..() - if(.) - custom_emote(1,"stares alertly at [.]") - handle_stance(STANCE_ALERT) - -/mob/living/simple_animal/hostile/bear/PunchTarget() - if(!Adjacent(target_mob)) - return - custom_emote(1, pick( list("slashes at [target_mob]", "bites [target_mob]") ) ) - - var/damage = rand(melee_damage_lower, melee_damage_upper) - - if(ishuman(target_mob)) - var/mob/living/carbon/human/H = target_mob - var/dam_zone = pick(BP_TORSO, BP_L_HAND, BP_R_HAND, BP_L_LEG, BP_R_LEG) - var/obj/item/organ/external/affecting = H.get_organ(ran_zone(dam_zone)) - H.apply_damage(damage, BRUTE, affecting, H.run_armor_check(affecting, "melee"), sharp=1, edge=1) - return H - else if(isliving(target_mob)) - var/mob/living/L = target_mob - L.adjustBruteLoss(damage) - return L - else - ..() +//Space bears! +/mob/living/simple_animal/hostile/bear + name = "space bear" + desc = "RawrRawr!!" + icon_state = "bear" + icon_living = "bear" + icon_dead = "bear_dead" + icon_gib = "bear_gib" + + faction = "russian" + cooperative = 1 + + maxHealth = 60 + health = 60 + turns_per_move = 5 + see_in_dark = 6 + stop_when_pulled = 0 + + response_help = "pets" + response_disarm = "gently pushes aside" + response_harm = "pokes" + + melee_damage_lower = 20 + melee_damage_upper = 30 + + //Space bears aren't affected by atmos. + min_oxy = 0 + max_oxy = 0 + min_tox = 0 + max_tox = 0 + min_co2 = 0 + max_co2 = 0 + min_n2 = 0 + max_n2 = 0 + minbodytemp = 0 + + speak_chance = 1 + speak = list("RAWR!","Rawr!","GRR!","Growl!") + speak_emote = list("growls", "roars") + emote_hear = list("rawrs","grumbles","grawls") + emote_see = list("stares ferociously", "stomps") + + meat_type = /obj/item/weapon/reagent_containers/food/snacks/bearmeat + + var/stance_step = 0 + +/mob/living/simple_animal/hostile/bear/handle_stance() + switch(stance) + if(STANCE_TIRED) + stop_automated_movement = 1 + stance_step++ + if(stance_step >= 10) //rests for 10 ticks + if(target_mob && target_mob in ListTargets(10)) + handle_stance(STANCE_ATTACK) //If the mob he was chasing is still nearby, resume the attack, otherwise go idle. + else + handle_stance(STANCE_IDLE) + + if(STANCE_ALERT) + stop_automated_movement = 1 + var/found_mob = 0 + if(target_mob && target_mob in ListTargets(10)) + if(!(SA_attackable(target_mob))) + stance_step = max(0, stance_step) //If we have not seen a mob in a while, the stance_step will be negative, we need to reset it to 0 as soon as we see a mob again. + stance_step++ + found_mob = 1 + src.set_dir(get_dir(src,target_mob)) //Keep staring at the mob + + if(stance_step in list(1,4,7)) //every 3 ticks + var/action = pick( list( "growls at [target_mob]", "stares angrily at [target_mob]", "prepares to attack [target_mob]", "closely watches [target_mob]" ) ) + if(action) + custom_emote(1,action) + if(!found_mob) + stance_step-- + + if(stance_step <= -20) //If we have not found a mob for 20-ish ticks, revert to idle mode + handle_stance(STANCE_IDLE) + if(stance_step >= 7) //If we have been staring at a mob for 7 ticks, + handle_stance(STANCE_ATTACK) + + if(STANCE_ATTACKING) + if(stance_step >= 20) //attacks for 20 ticks, then it gets tired and needs to rest + custom_emote(1, "is worn out and needs to rest." ) + handle_stance(STANCE_TIRED) + stance_step = 0 + walk(src, 0) //This stops the bear's walking + return + else + ..() + +/mob/living/simple_animal/hostile/bear/update_icons() + ..() + if(!stat) + if(loc && istype(loc,/turf/space)) + icon_state = "bear" + else + icon_state = "bearfloor" + +/mob/living/simple_animal/hostile/bear/Process_Spacemove(var/check_drift = 0) + return + +/mob/living/simple_animal/hostile/bear/FindTarget() + . = ..() + if(.) + custom_emote(1,"stares alertly at [.]") + handle_stance(STANCE_ALERT) + +/mob/living/simple_animal/hostile/bear/PunchTarget() + if(!Adjacent(target_mob)) + return + custom_emote(1, pick( list("slashes at [target_mob]", "bites [target_mob]") ) ) + + var/damage = rand(melee_damage_lower, melee_damage_upper) + + if(ishuman(target_mob)) + var/mob/living/carbon/human/H = target_mob + var/dam_zone = pick(BP_TORSO, BP_L_HAND, BP_R_HAND, BP_L_LEG, BP_R_LEG) + var/obj/item/organ/external/affecting = H.get_organ(ran_zone(dam_zone)) + H.apply_damage(damage, BRUTE, affecting, H.run_armor_check(affecting, "melee"), H.get_armor_soak(affecting, "melee"), sharp=1, edge=1) + return H + else if(isliving(target_mob)) + var/mob/living/L = target_mob + L.adjustBruteLoss(damage) + return L + else + ..() diff --git a/code/modules/mob/living/simple_animal/animals/giant_spider.dm b/code/modules/mob/living/simple_animal/animals/giant_spider.dm index ed692ab237f..acb1d7a1b79 100644 --- a/code/modules/mob/living/simple_animal/animals/giant_spider.dm +++ b/code/modules/mob/living/simple_animal/animals/giant_spider.dm @@ -36,7 +36,7 @@ speak_emote = list("chitters") emote_hear = list("chitters") - meat_type = /obj/item/weapon/reagent_containers/food/snacks/xenomeat + meat_type = /obj/item/weapon/reagent_containers/food/snacks/spidermeat var/busy = 0 var/poison_per_bite = 5 diff --git a/code/modules/mob/living/simple_animal/animals/parrot.dm b/code/modules/mob/living/simple_animal/animals/parrot.dm index d388939fcdd..03f0261688d 100644 --- a/code/modules/mob/living/simple_animal/animals/parrot.dm +++ b/code/modules/mob/living/simple_animal/animals/parrot.dm @@ -1,761 +1,761 @@ -/* Parrots! - * Contains - * Defines - * Inventory (headset stuff) - * Attack responces - * AI - * Procs / Verbs (usable by players) - * Sub-types - */ - -/* - * Defines - */ - -//Parrot is too snowflake for me to rewrite right now, someone should make it use the new -//simple_animal movement stuff. -Aro - -//Only a maximum of one action and one intent should be active at any given time. -//Actions -#define PARROT_PERCH 1 //Sitting/sleeping, not moving -#define PARROT_SWOOP 2 //Moving towards or away from a target -#define PARROT_WANDER 4 //Moving without a specific target in mind - -//Intents -#define PARROT_STEAL 8 //Flying towards a target to steal it/from it -#define PARROT_ATTACK 16 //Flying towards a target to attack it -#define PARROT_RETURN 32 //Flying towards its perch -#define PARROT_FLEE 64 //Flying away from its attacker - - -/mob/living/simple_animal/parrot - name = "\improper Parrot" - desc = "The parrot squaks, \"It's a Parrot! BAWWK!\"" - icon = 'icons/mob/animal.dmi' - icon_state = "parrot_fly" - icon_living = "parrot_fly" - icon_dead = "parrot_dead" - - turns_per_move = 5 - pass_flags = PASSTABLE - mob_size = MOB_SMALL - - response_help = "pets" - response_disarm = "gently moves aside" - response_harm = "swats" - stop_automated_movement = 1 - universal_speak = 1 - - speak_chance = 2 - speak = list("Hi","Hello!","Cracker?","BAWWWWK george mellons griffing me") - speak_emote = list("squawks","says","yells") - emote_hear = list("squawks","bawks") - emote_see = list("flutters its wings") - - meat_type = /obj/item/weapon/reagent_containers/food/snacks/cracker - - var/parrot_state = PARROT_WANDER //Hunt for a perch when created - var/parrot_sleep_max = 25 //The time the parrot sits while perched before looking around. Mosly a way to avoid the parrot's AI in life() being run every single tick. - var/parrot_sleep_dur = 25 //Same as above, this is the var that physically counts down - var/parrot_dam_zone = list(BP_TORSO, BP_HEAD, BP_L_ARM, BP_R_ARM, BP_L_LEG, BP_R_LEG) //For humans, select a bodypart to attack - - var/parrot_speed = 5 //"Delay in world ticks between movement." according to byond. Yeah, that's BS but it does directly affect movement. Higher number = slower. - var/parrot_been_shot = 0 //Parrots get a speed bonus after being shot. This will deincrement every Life() and at 0 the parrot will return to regular speed. - - var/list/speech_buffer = list() - var/list/available_channels = list() - - //Headset for Poly to yell at engineers :) - var/obj/item/device/radio/headset/ears = null - - //The thing the parrot is currently interested in. This gets used for items the parrot wants to pick up, mobs it wants to steal from, - //mobs it wants to attack or mobs that have attacked it - var/atom/movable/parrot_interest = null - - //Parrots will generally sit on their pertch unless something catches their eye. - //These vars store their preffered perch and if they dont have one, what they can use as a perch - var/obj/parrot_perch = null - var/obj/desired_perches = list(/obj/structure/frame, /obj/structure/displaycase, \ - /obj/structure/filingcabinet, /obj/machinery/teleport, \ - /obj/machinery/computer, /obj/machinery/clonepod, \ - /obj/machinery/dna_scannernew, /obj/machinery/telecomms, \ - /obj/machinery/nuclearbomb, /obj/machinery/particle_accelerator, \ - /obj/machinery/recharge_station, /obj/machinery/smartfridge, \ - /obj/machinery/suit_storage_unit) - - //Parrots are kleptomaniacs. This variable ... stores the item a parrot is holding. - var/obj/item/held_item = null - - -/mob/living/simple_animal/parrot/New() - ..() - if(!ears) - var/headset = pick(/obj/item/device/radio/headset/headset_sec, \ - /obj/item/device/radio/headset/headset_eng, \ - /obj/item/device/radio/headset/headset_med, \ - /obj/item/device/radio/headset/headset_sci, \ - /obj/item/device/radio/headset/headset_cargo) - ears = new headset(src) - - parrot_sleep_dur = parrot_sleep_max //In case someone decides to change the max without changing the duration var - - verbs.Add(/mob/living/simple_animal/parrot/proc/steal_from_ground, \ - /mob/living/simple_animal/parrot/proc/steal_from_mob, \ - /mob/living/simple_animal/parrot/verb/drop_held_item_player, \ - /mob/living/simple_animal/parrot/proc/perch_player) - - -/mob/living/simple_animal/parrot/death() - if(held_item) - held_item.forceMove(src.loc) - held_item = null - walk(src,0) - ..() - -/mob/living/simple_animal/parrot/Stat() - ..() - stat("Held Item", held_item) - -/* - * Inventory - */ -/mob/living/simple_animal/parrot/show_inv(mob/user as mob) - user.set_machine(src) - if(user.stat) return - - var/dat = "
Inventory of [name]

" - if(ears) - dat += "
Headset: [ears] (Remove)" - else - dat += "
Headset: Nothing" - - user << browse(dat, text("window=mob[];size=325x500", name)) - onclose(user, "mob[real_name]") - return - -/mob/living/simple_animal/parrot/Topic(href, href_list) - - //Can the usr physically do this? - if(!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr)) - return - - //Is the usr's mob type able to do this? - if(ishuman(usr) || issmall(usr) || isrobot(usr)) - - //Removing from inventory - if(href_list["remove_inv"]) - var/remove_from = href_list["remove_inv"] - switch(remove_from) - if("ears") - if(ears) - if(available_channels.len) - src.say("[pick(available_channels)] BAWWWWWK LEAVE THE HEADSET BAWKKKKK!") - else - src.say("BAWWWWWK LEAVE THE HEADSET BAWKKKKK!") - ears.forceMove(src.loc) - ears = null - for(var/possible_phrase in speak) - if(copytext(possible_phrase,1,3) in department_radio_keys) - possible_phrase = copytext(possible_phrase,3,length(possible_phrase)) - else - usr << "\red There is nothing to remove from its [remove_from]." - return - - //Adding things to inventory - else if(href_list["add_inv"]) - var/add_to = href_list["add_inv"] - if(!usr.get_active_hand()) - usr << "\red You have nothing in your hand to put on its [add_to]." - return - switch(add_to) - if("ears") - if(ears) - usr << "\red It's already wearing something." - return - else - var/obj/item/item_to_add = usr.get_active_hand() - if(!item_to_add) - return - - if( !istype(item_to_add, /obj/item/device/radio/headset) ) - usr << "\red This object won't fit." - return - - var/obj/item/device/radio/headset/headset_to_add = item_to_add - - usr.drop_item() - headset_to_add.forceMove(src) - src.ears = headset_to_add - usr << "You fit the headset onto [src]." - - clearlist(available_channels) - for(var/ch in headset_to_add.channels) - switch(ch) - if("Engineering") - available_channels.Add(":e") - if("Command") - available_channels.Add(":c") - if("Security") - available_channels.Add(":s") - if("Science") - available_channels.Add(":n") - if("Medical") - available_channels.Add(":m") - if("Mining") - available_channels.Add(":d") - if("Cargo") - available_channels.Add(":q") - - if(headset_to_add.translate_binary) - available_channels.Add(":b") - else - ..() - - -/* - * Attack responces - */ -//Humans, monkeys, aliens -/mob/living/simple_animal/parrot/attack_hand(mob/living/carbon/M as mob) - ..() - if(client) return - if(!stat && M.a_intent == I_HURT) - - icon_state = "parrot_fly" //It is going to be flying regardless of whether it flees or attacks - - if(parrot_state == PARROT_PERCH) - parrot_sleep_dur = parrot_sleep_max //Reset it's sleep timer if it was perched - - parrot_interest = M - parrot_state = PARROT_SWOOP //The parrot just got hit, it WILL move, now to pick a direction.. - - if(M.health < 50) //Weakened mob? Fight back! - parrot_state |= PARROT_ATTACK - else - parrot_state |= PARROT_FLEE //Otherwise, fly like a bat out of hell! - drop_held_item(0) - return - -//Mobs with objects -/mob/living/simple_animal/parrot/attackby(var/obj/item/O as obj, var/mob/user as mob) - ..() - if(!stat && !client && !istype(O, /obj/item/stack/medical)) - if(O.force) - if(parrot_state == PARROT_PERCH) - parrot_sleep_dur = parrot_sleep_max //Reset it's sleep timer if it was perched - - parrot_interest = user - parrot_state = PARROT_SWOOP | PARROT_FLEE - icon_state = "parrot_fly" - drop_held_item(0) - return - -//Bullets -/mob/living/simple_animal/parrot/bullet_act(var/obj/item/projectile/Proj) - ..() - if(!stat && !client) - if(parrot_state == PARROT_PERCH) - parrot_sleep_dur = parrot_sleep_max //Reset it's sleep timer if it was perched - - parrot_interest = null - parrot_state = PARROT_WANDER //OWFUCK, Been shot! RUN LIKE HELL! - parrot_been_shot += 5 - icon_state = "parrot_fly" - drop_held_item(0) - return - - -/* - * AI - Not really intelligent, but I'm calling it AI anyway. - */ -/mob/living/simple_animal/parrot/Life() - ..() - - //Sprite and AI update for when a parrot gets pulled - if(pulledby && stat == CONSCIOUS) - icon_state = "parrot_fly" - if(!client) - parrot_state = PARROT_WANDER - return - - if(client || stat) - return //Lets not force players or dead/incap parrots to move - - if(!isturf(src.loc) || !canmove || buckled) - return //If it can't move, dont let it move. (The buckled check probably isn't necessary thanks to canmove) - - -//-----SPEECH - /* Parrot speech mimickry! - Phrases that the parrot hears in mob/living/say() get added to speach_buffer. - Every once in a while, the parrot picks one of the lines from the buffer and replaces an element of the 'speech' list. - Then it clears the buffer to make sure they dont magically remember something from hours ago. */ - if(speech_buffer.len && prob(10)) - if(speak.len) - speak.Remove(pick(speak)) - - speak.Add(pick(speech_buffer)) - clearlist(speech_buffer) - - -//-----SLEEPING - if(parrot_state == PARROT_PERCH) - if(parrot_perch && parrot_perch.loc != src.loc) //Make sure someone hasnt moved our perch on us - if(parrot_perch in view(src)) - parrot_state = PARROT_SWOOP | PARROT_RETURN - icon_state = "parrot_fly" - return - else - parrot_state = PARROT_WANDER - icon_state = "parrot_fly" - return - - if(--parrot_sleep_dur) //Zzz - return - - else - //This way we only call the stuff below once every [sleep_max] ticks. - parrot_sleep_dur = parrot_sleep_max - - //Cycle through message modes for the headset - if(speak.len) - var/list/newspeak = list() - - if(available_channels.len && src.ears) - for(var/possible_phrase in speak) - - //50/50 chance to not use the radio at all - var/useradio = 0 - if(prob(50)) - useradio = 1 - - if(copytext(possible_phrase,1,3) in department_radio_keys) - possible_phrase = "[useradio?pick(available_channels):""] [copytext(possible_phrase,3,length(possible_phrase)+1)]" //crop out the channel prefix - else - possible_phrase = "[useradio?pick(available_channels):""] [possible_phrase]" - - newspeak.Add(possible_phrase) - - else //If we have no headset or channels to use, dont try to use any! - for(var/possible_phrase in speak) - if(copytext(possible_phrase,1,3) in department_radio_keys) - possible_phrase = "[copytext(possible_phrase,3,length(possible_phrase)+1)]" //crop out the channel prefix - newspeak.Add(possible_phrase) - speak = newspeak - - //Search for item to steal - parrot_interest = search_for_item() - if(parrot_interest) - visible_emote("looks in [parrot_interest]'s direction and takes flight") - parrot_state = PARROT_SWOOP | PARROT_STEAL - icon_state = "parrot_fly" - return - -//-----WANDERING - This is basically a 'I dont know what to do yet' state - else if(parrot_state == PARROT_WANDER) - //Stop movement, we'll set it later - walk(src, 0) - parrot_interest = null - - //Wander around aimlessly. This will help keep the loops from searches down - //and possibly move the mob into a new are in view of something they can use - if(prob(90)) - step(src, pick(cardinal)) - return - - if(!held_item && !parrot_perch) //If we've got nothing to do.. look for something to do. - var/atom/movable/AM = search_for_perch_and_item() //This handles checking through lists so we know it's either a perch or stealable item - if(AM) - if(istype(AM, /obj/item) || isliving(AM)) //If stealable item - parrot_interest = AM - visible_emote("turns and flies towards [parrot_interest]") - parrot_state = PARROT_SWOOP | PARROT_STEAL - return - else //Else it's a perch - parrot_perch = AM - parrot_state = PARROT_SWOOP | PARROT_RETURN - return - return - - if(parrot_interest && parrot_interest in view(src)) - parrot_state = PARROT_SWOOP | PARROT_STEAL - return - - if(parrot_perch && parrot_perch in view(src)) - parrot_state = PARROT_SWOOP | PARROT_RETURN - return - - else //Have an item but no perch? Find one! - parrot_perch = search_for_perch() - if(parrot_perch) - parrot_state = PARROT_SWOOP | PARROT_RETURN - return -//-----STEALING - else if(parrot_state == (PARROT_SWOOP | PARROT_STEAL)) - walk(src,0) - if(!parrot_interest || held_item) - parrot_state = PARROT_SWOOP | PARROT_RETURN - return - - if(!(parrot_interest in view(src))) - parrot_state = PARROT_SWOOP | PARROT_RETURN - return - - if(in_range(src, parrot_interest)) - - if(isliving(parrot_interest)) - steal_from_mob() - - else //This should ensure that we only grab the item we want, and make sure it's not already collected on our perch - if(!parrot_perch || parrot_interest.loc != parrot_perch.loc) - held_item = parrot_interest - parrot_interest.forceMove(src) - visible_message("[src] grabs the [held_item]!", "\blue You grab the [held_item]!", "You hear the sounds of wings flapping furiously.") - - parrot_interest = null - parrot_state = PARROT_SWOOP | PARROT_RETURN - return - - walk_to(src, parrot_interest, 1, parrot_speed) - return - -//-----RETURNING TO PERCH - else if(parrot_state == (PARROT_SWOOP | PARROT_RETURN)) - walk(src, 0) - if(!parrot_perch || !isturf(parrot_perch.loc)) //Make sure the perch exists and somehow isnt inside of something else. - parrot_perch = null - parrot_state = PARROT_WANDER - return - - if(in_range(src, parrot_perch)) - src.forceMove(parrot_perch.loc) - drop_held_item() - parrot_state = PARROT_PERCH - icon_state = "parrot_sit" - return - - walk_to(src, parrot_perch, 1, parrot_speed) - return - -//-----FLEEING - else if(parrot_state == (PARROT_SWOOP | PARROT_FLEE)) - walk(src,0) - if(!parrot_interest || !isliving(parrot_interest)) //Sanity - parrot_state = PARROT_WANDER - - walk_away(src, parrot_interest, 1, parrot_speed-parrot_been_shot) - parrot_been_shot-- - return - -//-----ATTACKING - else if(parrot_state == (PARROT_SWOOP | PARROT_ATTACK)) - - //If we're attacking a nothing, an object, a turf or a ghost for some stupid reason, switch to wander - if(!parrot_interest || !isliving(parrot_interest)) - parrot_interest = null - parrot_state = PARROT_WANDER - return - - var/mob/living/L = parrot_interest - - //If the mob is close enough to interact with - if(in_range(src, parrot_interest)) - - //If the mob we've been chasing/attacking dies or falls into crit, check for loot! - if(L.stat) - parrot_interest = null - if(!held_item) - held_item = steal_from_ground() - if(!held_item) - held_item = steal_from_mob() //Apparently it's possible for dead mobs to hang onto items in certain circumstances. - if(parrot_perch in view(src)) //If we have a home nearby, go to it, otherwise find a new home - parrot_state = PARROT_SWOOP | PARROT_RETURN - else - parrot_state = PARROT_WANDER - return - - //Time for the hurt to begin! - var/damage = rand(5,10) - - if(ishuman(parrot_interest)) - var/mob/living/carbon/human/H = parrot_interest - var/obj/item/organ/external/affecting = H.get_organ(ran_zone(pick(parrot_dam_zone))) - - H.apply_damage(damage, BRUTE, affecting, H.run_armor_check(affecting, "melee"), sharp=1) - visible_emote(pick("pecks [H]'s [affecting].", "cuts [H]'s [affecting] with its talons.")) - - else - L.adjustBruteLoss(damage) - visible_emote(pick("pecks at [L].", "claws [L].")) - return - - //Otherwise, fly towards the mob! - else - walk_to(src, parrot_interest, 1, parrot_speed) - return -//-----STATE MISHAP - else //This should not happen. If it does lets reset everything and try again - walk(src,0) - parrot_interest = null - parrot_perch = null - drop_held_item() - parrot_state = PARROT_WANDER - return - -/* - * Procs - */ - -/mob/living/simple_animal/parrot/movement_delay() - if(client && stat == CONSCIOUS && parrot_state != "parrot_fly") - icon_state = "parrot_fly" - ..() - -/mob/living/simple_animal/parrot/proc/search_for_item() - for(var/atom/movable/AM in view(src)) - //Skip items we already stole or are wearing or are too big - if(parrot_perch && AM.loc == parrot_perch.loc || AM.loc == src) - continue - - if(istype(AM, /obj/item)) - var/obj/item/I = AM - if(I.w_class < ITEMSIZE_SMALL) - return I - - if(iscarbon(AM)) - var/mob/living/carbon/C = AM - if((C.l_hand && C.l_hand.w_class <= ITEMSIZE_SMALL) || (C.r_hand && C.r_hand.w_class <= ITEMSIZE_SMALL)) - return C - return null - -/mob/living/simple_animal/parrot/proc/search_for_perch() - for(var/obj/O in view(src)) - for(var/path in desired_perches) - if(istype(O, path)) - return O - return null - -//This proc was made to save on doing two 'in view' loops seperatly -/mob/living/simple_animal/parrot/proc/search_for_perch_and_item() - for(var/atom/movable/AM in view(src)) - for(var/perch_path in desired_perches) - if(istype(AM, perch_path)) - return AM - - //Skip items we already stole or are wearing or are too big - if(parrot_perch && AM.loc == parrot_perch.loc || AM.loc == src) - continue - - if(istype(AM, /obj/item)) - var/obj/item/I = AM - if(I.w_class <= ITEMSIZE_SMALL) - return I - - if(iscarbon(AM)) - var/mob/living/carbon/C = AM - if(C.l_hand && C.l_hand.w_class <= ITEMSIZE_SMALL || C.r_hand && C.r_hand.w_class <= ITEMSIZE_SMALL) - return C - return null - - -/* - * Verbs - These are actually procs, but can be used as verbs by player-controlled parrots. - */ -/mob/living/simple_animal/parrot/proc/steal_from_ground() - set name = "Steal from ground" - set category = "Parrot" - set desc = "Grabs a nearby item." - - if(stat) - return -1 - - if(held_item) - src << "\red You are already holding the [held_item]" - return 1 - - for(var/obj/item/I in view(1,src)) - //Make sure we're not already holding it and it's small enough - if(I.loc != src && I.w_class <= ITEMSIZE_SMALL) - - //If we have a perch and the item is sitting on it, continue - if(!client && parrot_perch && I.loc == parrot_perch.loc) - continue - - held_item = I - I.forceMove(src) - visible_message("[src] grabs the [held_item]!", "\blue You grab the [held_item]!", "You hear the sounds of wings flapping furiously.") - return held_item - - src << "\red There is nothing of interest to take." - return 0 - -/mob/living/simple_animal/parrot/proc/steal_from_mob() - set name = "Steal from mob" - set category = "Parrot" - set desc = "Steals an item right out of a person's hand!" - - if(stat) - return -1 - - if(held_item) - src << "\red You are already holding the [held_item]" - return 1 - - 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 <= ITEMSIZE_SMALL) - stolen_item = C.l_hand - - if(C.r_hand && C.r_hand.w_class <= ITEMSIZE_SMALL) - stolen_item = C.r_hand - - if(stolen_item) - C.remove_from_mob(stolen_item) - held_item = stolen_item - stolen_item.forceMove(src) - visible_message("[src] grabs the [held_item] out of [C]'s hand!", "\blue You snag the [held_item] out of [C]'s hand!", "You hear the sounds of wings flapping furiously.") - return held_item - - src << "\red There is nothing of interest to take." - return 0 - -/mob/living/simple_animal/parrot/verb/drop_held_item_player() - set name = "Drop held item" - set category = "Parrot" - set desc = "Drop the item you're holding." - - if(stat) - return - - src.drop_held_item() - - return - -/mob/living/simple_animal/parrot/proc/drop_held_item(var/drop_gently = 1) - set name = "Drop held item" - set category = "Parrot" - set desc = "Drop the item you're holding." - - if(stat) - return -1 - - if(!held_item) - usr << "\red You have nothing to drop!" - return 0 - - if(!drop_gently) - if(istype(held_item, /obj/item/weapon/grenade)) - var/obj/item/weapon/grenade/G = held_item - G.forceMove(src.loc) - G.prime() - src << "You let go of the [held_item]!" - held_item = null - return 1 - - src << "You drop the [held_item]." - - held_item.forceMove(src.loc) - held_item = null - return 1 - -/mob/living/simple_animal/parrot/proc/perch_player() - set name = "Sit" - set category = "Parrot" - set desc = "Sit on a nice comfy perch." - - if(stat || !client) - return - - if(icon_state == "parrot_fly") - for(var/atom/movable/AM in view(src,1)) - for(var/perch_path in desired_perches) - if(istype(AM, perch_path)) - src.forceMove(AM.loc) - icon_state = "parrot_sit" - return - src << "\red There is no perch nearby to sit on." - return - -/* - * Sub-types - */ -/mob/living/simple_animal/parrot/Poly - name = "Poly" - desc = "Poly the Parrot. An expert on quantum cracker theory." - speak = list("Poly wanna cracker!", ":e Check the singlo, you chucklefucks!",":e Wire the solars, you lazy bums!",":e WHO TOOK THE DAMN HARDSUITS?",":e OH GOD ITS FREE CALL THE SHUTTLE") - -/mob/living/simple_animal/parrot/Poly/New() - ears = new /obj/item/device/radio/headset/headset_eng(src) - available_channels = list(":e") - ..() - -/mob/living/simple_animal/parrot/say(var/message) - - if(stat) - return - - var/verb = "says" - if(speak_emote.len) - verb = pick(speak_emote) - - - var/message_mode="" - if(copytext(message,1,2) == ";") - message_mode = "headset" - message = copytext(message,2) - - if(length(message) >= 2) - var/channel_prefix = copytext(message, 1 ,3) - message_mode = department_radio_keys[channel_prefix] - - if(copytext(message,1,2) == ":") - var/positioncut = 3 - message = trim(copytext(message,positioncut)) - - message = capitalize(trim_left(message)) - - if(message_mode) - if(message_mode in radiochannels) - if(ears && istype(ears,/obj/item/device/radio)) - ears.talk_into(src,sanitize(message), message_mode, verb, null) - - - ..(message) - - -/mob/living/simple_animal/parrot/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/alt_name = "",var/italics = 0, var/mob/speaker = null) - if(prob(50)) - parrot_hear(message) - ..(message,verb,language,alt_name,italics,speaker) - - - -/mob/living/simple_animal/parrot/hear_radio(var/message, var/verb="says", var/datum/language/language=null, var/part_a, var/part_b, var/part_c, var/mob/speaker = null, var/hard_to_hear = 0) - if(prob(50)) - parrot_hear("[pick(available_channels)] [message]") - ..(message,verb,language,part_a,part_b,speaker,hard_to_hear) - - -/mob/living/simple_animal/parrot/proc/parrot_hear(var/message="") - if(!message || stat) - return - speech_buffer.Add(message) - -/mob/living/simple_animal/parrot/attack_generic(var/mob/user, var/damage, var/attack_message) - - var/success = ..() - - if(client) - return success - - if(parrot_state == PARROT_PERCH) - parrot_sleep_dur = parrot_sleep_max //Reset it's sleep timer if it was perched - - if(!success) - return 0 - - parrot_interest = user - parrot_state = PARROT_SWOOP | PARROT_ATTACK //Attack other animals regardless - icon_state = "parrot_fly" +/* Parrots! + * Contains + * Defines + * Inventory (headset stuff) + * Attack responces + * AI + * Procs / Verbs (usable by players) + * Sub-types + */ + +/* + * Defines + */ + +//Parrot is too snowflake for me to rewrite right now, someone should make it use the new +//simple_animal movement stuff. -Aro + +//Only a maximum of one action and one intent should be active at any given time. +//Actions +#define PARROT_PERCH 1 //Sitting/sleeping, not moving +#define PARROT_SWOOP 2 //Moving towards or away from a target +#define PARROT_WANDER 4 //Moving without a specific target in mind + +//Intents +#define PARROT_STEAL 8 //Flying towards a target to steal it/from it +#define PARROT_ATTACK 16 //Flying towards a target to attack it +#define PARROT_RETURN 32 //Flying towards its perch +#define PARROT_FLEE 64 //Flying away from its attacker + + +/mob/living/simple_animal/parrot + name = "\improper Parrot" + desc = "The parrot squaks, \"It's a Parrot! BAWWK!\"" + icon = 'icons/mob/animal.dmi' + icon_state = "parrot_fly" + icon_living = "parrot_fly" + icon_dead = "parrot_dead" + + turns_per_move = 5 + pass_flags = PASSTABLE + mob_size = MOB_SMALL + + response_help = "pets" + response_disarm = "gently moves aside" + response_harm = "swats" + stop_automated_movement = 1 + universal_speak = 1 + + speak_chance = 2 + speak = list("Hi","Hello!","Cracker?","BAWWWWK george mellons griffing me") + speak_emote = list("squawks","says","yells") + emote_hear = list("squawks","bawks") + emote_see = list("flutters its wings") + + meat_type = /obj/item/weapon/reagent_containers/food/snacks/cracker + + var/parrot_state = PARROT_WANDER //Hunt for a perch when created + var/parrot_sleep_max = 25 //The time the parrot sits while perched before looking around. Mosly a way to avoid the parrot's AI in life() being run every single tick. + var/parrot_sleep_dur = 25 //Same as above, this is the var that physically counts down + var/parrot_dam_zone = list(BP_TORSO, BP_HEAD, BP_L_ARM, BP_R_ARM, BP_L_LEG, BP_R_LEG) //For humans, select a bodypart to attack + + var/parrot_speed = 5 //"Delay in world ticks between movement." according to byond. Yeah, that's BS but it does directly affect movement. Higher number = slower. + var/parrot_been_shot = 0 //Parrots get a speed bonus after being shot. This will deincrement every Life() and at 0 the parrot will return to regular speed. + + var/list/speech_buffer = list() + var/list/available_channels = list() + + //Headset for Poly to yell at engineers :) + var/obj/item/device/radio/headset/ears = null + + //The thing the parrot is currently interested in. This gets used for items the parrot wants to pick up, mobs it wants to steal from, + //mobs it wants to attack or mobs that have attacked it + var/atom/movable/parrot_interest = null + + //Parrots will generally sit on their pertch unless something catches their eye. + //These vars store their preffered perch and if they dont have one, what they can use as a perch + var/obj/parrot_perch = null + var/obj/desired_perches = list(/obj/structure/frame, /obj/structure/displaycase, \ + /obj/structure/filingcabinet, /obj/machinery/teleport, \ + /obj/machinery/computer, /obj/machinery/clonepod, \ + /obj/machinery/dna_scannernew, /obj/machinery/telecomms, \ + /obj/machinery/nuclearbomb, /obj/machinery/particle_accelerator, \ + /obj/machinery/recharge_station, /obj/machinery/smartfridge, \ + /obj/machinery/suit_storage_unit) + + //Parrots are kleptomaniacs. This variable ... stores the item a parrot is holding. + var/obj/item/held_item = null + + +/mob/living/simple_animal/parrot/New() + ..() + if(!ears) + var/headset = pick(/obj/item/device/radio/headset/headset_sec, \ + /obj/item/device/radio/headset/headset_eng, \ + /obj/item/device/radio/headset/headset_med, \ + /obj/item/device/radio/headset/headset_sci, \ + /obj/item/device/radio/headset/headset_cargo) + ears = new headset(src) + + parrot_sleep_dur = parrot_sleep_max //In case someone decides to change the max without changing the duration var + + verbs.Add(/mob/living/simple_animal/parrot/proc/steal_from_ground, \ + /mob/living/simple_animal/parrot/proc/steal_from_mob, \ + /mob/living/simple_animal/parrot/verb/drop_held_item_player, \ + /mob/living/simple_animal/parrot/proc/perch_player) + + +/mob/living/simple_animal/parrot/death() + if(held_item) + held_item.forceMove(src.loc) + held_item = null + walk(src,0) + ..() + +/mob/living/simple_animal/parrot/Stat() + ..() + stat("Held Item", held_item) + +/* + * Inventory + */ +/mob/living/simple_animal/parrot/show_inv(mob/user as mob) + user.set_machine(src) + if(user.stat) return + + var/dat = "

Inventory of [name]

" + if(ears) + dat += "
Headset: [ears] (Remove)" + else + dat += "
Headset: Nothing" + + user << browse(dat, text("window=mob[];size=325x500", name)) + onclose(user, "mob[real_name]") + return + +/mob/living/simple_animal/parrot/Topic(href, href_list) + + //Can the usr physically do this? + if(!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr)) + return + + //Is the usr's mob type able to do this? + if(ishuman(usr) || issmall(usr) || isrobot(usr)) + + //Removing from inventory + if(href_list["remove_inv"]) + var/remove_from = href_list["remove_inv"] + switch(remove_from) + if("ears") + if(ears) + if(available_channels.len) + src.say("[pick(available_channels)] BAWWWWWK LEAVE THE HEADSET BAWKKKKK!") + else + src.say("BAWWWWWK LEAVE THE HEADSET BAWKKKKK!") + ears.forceMove(src.loc) + ears = null + for(var/possible_phrase in speak) + if(copytext(possible_phrase,1,3) in department_radio_keys) + possible_phrase = copytext(possible_phrase,3,length(possible_phrase)) + else + usr << "\red There is nothing to remove from its [remove_from]." + return + + //Adding things to inventory + else if(href_list["add_inv"]) + var/add_to = href_list["add_inv"] + if(!usr.get_active_hand()) + usr << "\red You have nothing in your hand to put on its [add_to]." + return + switch(add_to) + if("ears") + if(ears) + usr << "\red It's already wearing something." + return + else + var/obj/item/item_to_add = usr.get_active_hand() + if(!item_to_add) + return + + if( !istype(item_to_add, /obj/item/device/radio/headset) ) + usr << "\red This object won't fit." + return + + var/obj/item/device/radio/headset/headset_to_add = item_to_add + + usr.drop_item() + headset_to_add.forceMove(src) + src.ears = headset_to_add + usr << "You fit the headset onto [src]." + + clearlist(available_channels) + for(var/ch in headset_to_add.channels) + switch(ch) + if("Engineering") + available_channels.Add(":e") + if("Command") + available_channels.Add(":c") + if("Security") + available_channels.Add(":s") + if("Science") + available_channels.Add(":n") + if("Medical") + available_channels.Add(":m") + if("Mining") + available_channels.Add(":d") + if("Cargo") + available_channels.Add(":q") + + if(headset_to_add.translate_binary) + available_channels.Add(":b") + else + ..() + + +/* + * Attack responces + */ +//Humans, monkeys, aliens +/mob/living/simple_animal/parrot/attack_hand(mob/living/carbon/M as mob) + ..() + if(client) return + if(!stat && M.a_intent == I_HURT) + + icon_state = "parrot_fly" //It is going to be flying regardless of whether it flees or attacks + + if(parrot_state == PARROT_PERCH) + parrot_sleep_dur = parrot_sleep_max //Reset it's sleep timer if it was perched + + parrot_interest = M + parrot_state = PARROT_SWOOP //The parrot just got hit, it WILL move, now to pick a direction.. + + if(M.health < 50) //Weakened mob? Fight back! + parrot_state |= PARROT_ATTACK + else + parrot_state |= PARROT_FLEE //Otherwise, fly like a bat out of hell! + drop_held_item(0) + return + +//Mobs with objects +/mob/living/simple_animal/parrot/attackby(var/obj/item/O as obj, var/mob/user as mob) + ..() + if(!stat && !client && !istype(O, /obj/item/stack/medical)) + if(O.force) + if(parrot_state == PARROT_PERCH) + parrot_sleep_dur = parrot_sleep_max //Reset it's sleep timer if it was perched + + parrot_interest = user + parrot_state = PARROT_SWOOP | PARROT_FLEE + icon_state = "parrot_fly" + drop_held_item(0) + return + +//Bullets +/mob/living/simple_animal/parrot/bullet_act(var/obj/item/projectile/Proj) + ..() + if(!stat && !client) + if(parrot_state == PARROT_PERCH) + parrot_sleep_dur = parrot_sleep_max //Reset it's sleep timer if it was perched + + parrot_interest = null + parrot_state = PARROT_WANDER //OWFUCK, Been shot! RUN LIKE HELL! + parrot_been_shot += 5 + icon_state = "parrot_fly" + drop_held_item(0) + return + + +/* + * AI - Not really intelligent, but I'm calling it AI anyway. + */ +/mob/living/simple_animal/parrot/Life() + ..() + + //Sprite and AI update for when a parrot gets pulled + if(pulledby && stat == CONSCIOUS) + icon_state = "parrot_fly" + if(!client) + parrot_state = PARROT_WANDER + return + + if(client || stat) + return //Lets not force players or dead/incap parrots to move + + if(!isturf(src.loc) || !canmove || buckled) + return //If it can't move, dont let it move. (The buckled check probably isn't necessary thanks to canmove) + + +//-----SPEECH + /* Parrot speech mimickry! + Phrases that the parrot hears in mob/living/say() get added to speach_buffer. + Every once in a while, the parrot picks one of the lines from the buffer and replaces an element of the 'speech' list. + Then it clears the buffer to make sure they dont magically remember something from hours ago. */ + if(speech_buffer.len && prob(10)) + if(speak.len) + speak.Remove(pick(speak)) + + speak.Add(pick(speech_buffer)) + clearlist(speech_buffer) + + +//-----SLEEPING + if(parrot_state == PARROT_PERCH) + if(parrot_perch && parrot_perch.loc != src.loc) //Make sure someone hasnt moved our perch on us + if(parrot_perch in view(src)) + parrot_state = PARROT_SWOOP | PARROT_RETURN + icon_state = "parrot_fly" + return + else + parrot_state = PARROT_WANDER + icon_state = "parrot_fly" + return + + if(--parrot_sleep_dur) //Zzz + return + + else + //This way we only call the stuff below once every [sleep_max] ticks. + parrot_sleep_dur = parrot_sleep_max + + //Cycle through message modes for the headset + if(speak.len) + var/list/newspeak = list() + + if(available_channels.len && src.ears) + for(var/possible_phrase in speak) + + //50/50 chance to not use the radio at all + var/useradio = 0 + if(prob(50)) + useradio = 1 + + if(copytext(possible_phrase,1,3) in department_radio_keys) + possible_phrase = "[useradio?pick(available_channels):""] [copytext(possible_phrase,3,length(possible_phrase)+1)]" //crop out the channel prefix + else + possible_phrase = "[useradio?pick(available_channels):""] [possible_phrase]" + + newspeak.Add(possible_phrase) + + else //If we have no headset or channels to use, dont try to use any! + for(var/possible_phrase in speak) + if(copytext(possible_phrase,1,3) in department_radio_keys) + possible_phrase = "[copytext(possible_phrase,3,length(possible_phrase)+1)]" //crop out the channel prefix + newspeak.Add(possible_phrase) + speak = newspeak + + //Search for item to steal + parrot_interest = search_for_item() + if(parrot_interest) + visible_emote("looks in [parrot_interest]'s direction and takes flight") + parrot_state = PARROT_SWOOP | PARROT_STEAL + icon_state = "parrot_fly" + return + +//-----WANDERING - This is basically a 'I dont know what to do yet' state + else if(parrot_state == PARROT_WANDER) + //Stop movement, we'll set it later + walk(src, 0) + parrot_interest = null + + //Wander around aimlessly. This will help keep the loops from searches down + //and possibly move the mob into a new are in view of something they can use + if(prob(90)) + step(src, pick(cardinal)) + return + + if(!held_item && !parrot_perch) //If we've got nothing to do.. look for something to do. + var/atom/movable/AM = search_for_perch_and_item() //This handles checking through lists so we know it's either a perch or stealable item + if(AM) + if(istype(AM, /obj/item) || isliving(AM)) //If stealable item + parrot_interest = AM + visible_emote("turns and flies towards [parrot_interest]") + parrot_state = PARROT_SWOOP | PARROT_STEAL + return + else //Else it's a perch + parrot_perch = AM + parrot_state = PARROT_SWOOP | PARROT_RETURN + return + return + + if(parrot_interest && parrot_interest in view(src)) + parrot_state = PARROT_SWOOP | PARROT_STEAL + return + + if(parrot_perch && parrot_perch in view(src)) + parrot_state = PARROT_SWOOP | PARROT_RETURN + return + + else //Have an item but no perch? Find one! + parrot_perch = search_for_perch() + if(parrot_perch) + parrot_state = PARROT_SWOOP | PARROT_RETURN + return +//-----STEALING + else if(parrot_state == (PARROT_SWOOP | PARROT_STEAL)) + walk(src,0) + if(!parrot_interest || held_item) + parrot_state = PARROT_SWOOP | PARROT_RETURN + return + + if(!(parrot_interest in view(src))) + parrot_state = PARROT_SWOOP | PARROT_RETURN + return + + if(in_range(src, parrot_interest)) + + if(isliving(parrot_interest)) + steal_from_mob() + + else //This should ensure that we only grab the item we want, and make sure it's not already collected on our perch + if(!parrot_perch || parrot_interest.loc != parrot_perch.loc) + held_item = parrot_interest + parrot_interest.forceMove(src) + visible_message("[src] grabs the [held_item]!", "\blue You grab the [held_item]!", "You hear the sounds of wings flapping furiously.") + + parrot_interest = null + parrot_state = PARROT_SWOOP | PARROT_RETURN + return + + walk_to(src, parrot_interest, 1, parrot_speed) + return + +//-----RETURNING TO PERCH + else if(parrot_state == (PARROT_SWOOP | PARROT_RETURN)) + walk(src, 0) + if(!parrot_perch || !isturf(parrot_perch.loc)) //Make sure the perch exists and somehow isnt inside of something else. + parrot_perch = null + parrot_state = PARROT_WANDER + return + + if(in_range(src, parrot_perch)) + src.forceMove(parrot_perch.loc) + drop_held_item() + parrot_state = PARROT_PERCH + icon_state = "parrot_sit" + return + + walk_to(src, parrot_perch, 1, parrot_speed) + return + +//-----FLEEING + else if(parrot_state == (PARROT_SWOOP | PARROT_FLEE)) + walk(src,0) + if(!parrot_interest || !isliving(parrot_interest)) //Sanity + parrot_state = PARROT_WANDER + + walk_away(src, parrot_interest, 1, parrot_speed-parrot_been_shot) + parrot_been_shot-- + return + +//-----ATTACKING + else if(parrot_state == (PARROT_SWOOP | PARROT_ATTACK)) + + //If we're attacking a nothing, an object, a turf or a ghost for some stupid reason, switch to wander + if(!parrot_interest || !isliving(parrot_interest)) + parrot_interest = null + parrot_state = PARROT_WANDER + return + + var/mob/living/L = parrot_interest + + //If the mob is close enough to interact with + if(in_range(src, parrot_interest)) + + //If the mob we've been chasing/attacking dies or falls into crit, check for loot! + if(L.stat) + parrot_interest = null + if(!held_item) + held_item = steal_from_ground() + if(!held_item) + held_item = steal_from_mob() //Apparently it's possible for dead mobs to hang onto items in certain circumstances. + if(parrot_perch in view(src)) //If we have a home nearby, go to it, otherwise find a new home + parrot_state = PARROT_SWOOP | PARROT_RETURN + else + parrot_state = PARROT_WANDER + return + + //Time for the hurt to begin! + var/damage = rand(5,10) + + if(ishuman(parrot_interest)) + var/mob/living/carbon/human/H = parrot_interest + var/obj/item/organ/external/affecting = H.get_organ(ran_zone(pick(parrot_dam_zone))) + + H.apply_damage(damage, BRUTE, affecting, H.run_armor_check(affecting, "melee"), H.get_armor_soak(affecting, "melee"), sharp=1) + visible_emote(pick("pecks [H]'s [affecting].", "cuts [H]'s [affecting] with its talons.")) + + else + L.adjustBruteLoss(damage) + visible_emote(pick("pecks at [L].", "claws [L].")) + return + + //Otherwise, fly towards the mob! + else + walk_to(src, parrot_interest, 1, parrot_speed) + return +//-----STATE MISHAP + else //This should not happen. If it does lets reset everything and try again + walk(src,0) + parrot_interest = null + parrot_perch = null + drop_held_item() + parrot_state = PARROT_WANDER + return + +/* + * Procs + */ + +/mob/living/simple_animal/parrot/movement_delay() + if(client && stat == CONSCIOUS && parrot_state != "parrot_fly") + icon_state = "parrot_fly" + ..() + +/mob/living/simple_animal/parrot/proc/search_for_item() + for(var/atom/movable/AM in view(src)) + //Skip items we already stole or are wearing or are too big + if(parrot_perch && AM.loc == parrot_perch.loc || AM.loc == src) + continue + + if(istype(AM, /obj/item)) + var/obj/item/I = AM + if(I.w_class < ITEMSIZE_SMALL) + return I + + if(iscarbon(AM)) + var/mob/living/carbon/C = AM + if((C.l_hand && C.l_hand.w_class <= ITEMSIZE_SMALL) || (C.r_hand && C.r_hand.w_class <= ITEMSIZE_SMALL)) + return C + return null + +/mob/living/simple_animal/parrot/proc/search_for_perch() + for(var/obj/O in view(src)) + for(var/path in desired_perches) + if(istype(O, path)) + return O + return null + +//This proc was made to save on doing two 'in view' loops seperatly +/mob/living/simple_animal/parrot/proc/search_for_perch_and_item() + for(var/atom/movable/AM in view(src)) + for(var/perch_path in desired_perches) + if(istype(AM, perch_path)) + return AM + + //Skip items we already stole or are wearing or are too big + if(parrot_perch && AM.loc == parrot_perch.loc || AM.loc == src) + continue + + if(istype(AM, /obj/item)) + var/obj/item/I = AM + if(I.w_class <= ITEMSIZE_SMALL) + return I + + if(iscarbon(AM)) + var/mob/living/carbon/C = AM + if(C.l_hand && C.l_hand.w_class <= ITEMSIZE_SMALL || C.r_hand && C.r_hand.w_class <= ITEMSIZE_SMALL) + return C + return null + + +/* + * Verbs - These are actually procs, but can be used as verbs by player-controlled parrots. + */ +/mob/living/simple_animal/parrot/proc/steal_from_ground() + set name = "Steal from ground" + set category = "Parrot" + set desc = "Grabs a nearby item." + + if(stat) + return -1 + + if(held_item) + src << "\red You are already holding the [held_item]" + return 1 + + for(var/obj/item/I in view(1,src)) + //Make sure we're not already holding it and it's small enough + if(I.loc != src && I.w_class <= ITEMSIZE_SMALL) + + //If we have a perch and the item is sitting on it, continue + if(!client && parrot_perch && I.loc == parrot_perch.loc) + continue + + held_item = I + I.forceMove(src) + visible_message("[src] grabs the [held_item]!", "\blue You grab the [held_item]!", "You hear the sounds of wings flapping furiously.") + return held_item + + src << "\red There is nothing of interest to take." + return 0 + +/mob/living/simple_animal/parrot/proc/steal_from_mob() + set name = "Steal from mob" + set category = "Parrot" + set desc = "Steals an item right out of a person's hand!" + + if(stat) + return -1 + + if(held_item) + src << "\red You are already holding the [held_item]" + return 1 + + 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 <= ITEMSIZE_SMALL) + stolen_item = C.l_hand + + if(C.r_hand && C.r_hand.w_class <= ITEMSIZE_SMALL) + stolen_item = C.r_hand + + if(stolen_item) + C.remove_from_mob(stolen_item) + held_item = stolen_item + stolen_item.forceMove(src) + visible_message("[src] grabs the [held_item] out of [C]'s hand!", "\blue You snag the [held_item] out of [C]'s hand!", "You hear the sounds of wings flapping furiously.") + return held_item + + src << "\red There is nothing of interest to take." + return 0 + +/mob/living/simple_animal/parrot/verb/drop_held_item_player() + set name = "Drop held item" + set category = "Parrot" + set desc = "Drop the item you're holding." + + if(stat) + return + + src.drop_held_item() + + return + +/mob/living/simple_animal/parrot/proc/drop_held_item(var/drop_gently = 1) + set name = "Drop held item" + set category = "Parrot" + set desc = "Drop the item you're holding." + + if(stat) + return -1 + + if(!held_item) + usr << "\red You have nothing to drop!" + return 0 + + if(!drop_gently) + if(istype(held_item, /obj/item/weapon/grenade)) + var/obj/item/weapon/grenade/G = held_item + G.forceMove(src.loc) + G.prime() + src << "You let go of the [held_item]!" + held_item = null + return 1 + + src << "You drop the [held_item]." + + held_item.forceMove(src.loc) + held_item = null + return 1 + +/mob/living/simple_animal/parrot/proc/perch_player() + set name = "Sit" + set category = "Parrot" + set desc = "Sit on a nice comfy perch." + + if(stat || !client) + return + + if(icon_state == "parrot_fly") + for(var/atom/movable/AM in view(src,1)) + for(var/perch_path in desired_perches) + if(istype(AM, perch_path)) + src.forceMove(AM.loc) + icon_state = "parrot_sit" + return + src << "\red There is no perch nearby to sit on." + return + +/* + * Sub-types + */ +/mob/living/simple_animal/parrot/Poly + name = "Poly" + desc = "Poly the Parrot. An expert on quantum cracker theory." + speak = list("Poly wanna cracker!", ":e Check the singlo, you chucklefucks!",":e Wire the solars, you lazy bums!",":e WHO TOOK THE DAMN HARDSUITS?",":e OH GOD ITS FREE CALL THE SHUTTLE") + +/mob/living/simple_animal/parrot/Poly/New() + ears = new /obj/item/device/radio/headset/headset_eng(src) + available_channels = list(":e") + ..() + +/mob/living/simple_animal/parrot/say(var/message) + + if(stat) + return + + var/verb = "says" + if(speak_emote.len) + verb = pick(speak_emote) + + + var/message_mode="" + if(copytext(message,1,2) == ";") + message_mode = "headset" + message = copytext(message,2) + + if(length(message) >= 2) + var/channel_prefix = copytext(message, 1 ,3) + message_mode = department_radio_keys[channel_prefix] + + if(copytext(message,1,2) == ":") + var/positioncut = 3 + message = trim(copytext(message,positioncut)) + + message = capitalize(trim_left(message)) + + if(message_mode) + if(message_mode in radiochannels) + if(ears && istype(ears,/obj/item/device/radio)) + ears.talk_into(src,sanitize(message), message_mode, verb, null) + + + ..(message) + + +/mob/living/simple_animal/parrot/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/alt_name = "",var/italics = 0, var/mob/speaker = null) + if(prob(50)) + parrot_hear(message) + ..(message,verb,language,alt_name,italics,speaker) + + + +/mob/living/simple_animal/parrot/hear_radio(var/message, var/verb="says", var/datum/language/language=null, var/part_a, var/part_b, var/part_c, var/mob/speaker = null, var/hard_to_hear = 0) + if(prob(50)) + parrot_hear("[pick(available_channels)] [message]") + ..(message,verb,language,part_a,part_b,speaker,hard_to_hear) + + +/mob/living/simple_animal/parrot/proc/parrot_hear(var/message="") + if(!message || stat) + return + speech_buffer.Add(message) + +/mob/living/simple_animal/parrot/attack_generic(var/mob/user, var/damage, var/attack_message) + + var/success = ..() + + if(client) + return success + + if(parrot_state == PARROT_PERCH) + parrot_sleep_dur = parrot_sleep_max //Reset it's sleep timer if it was perched + + if(!success) + return 0 + + parrot_interest = user + parrot_state = PARROT_SWOOP | PARROT_ATTACK //Attack other animals regardless + icon_state = "parrot_fly" return success \ No newline at end of file diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index a161062f1ef..f27a73f4040 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -903,7 +903,7 @@ mob/proc/yank_out_object() if(prob(selection.w_class * 5) && (affected.robotic < ORGAN_ROBOT)) //I'M SO ANEMIC I COULD JUST -DIE-. var/datum/wound/internal_bleeding/I = new (min(selection.w_class * 5, 15)) affected.wounds += I - H.custom_pain("Something tears wetly in your [affected] as [selection] is pulled free!", 1) + H.custom_pain("Something tears wetly in your [affected] as [selection] is pulled free!", 50) if (ishuman(U)) var/mob/living/carbon/human/human_user = U diff --git a/code/modules/mob/mob_grab_specials.dm b/code/modules/mob/mob_grab_specials.dm index e7b75a2e5de..735d35fe7c3 100644 --- a/code/modules/mob/mob_grab_specials.dm +++ b/code/modules/mob/mob_grab_specials.dm @@ -20,7 +20,7 @@ user << "You must stand still to feel [E] for fractures." else if(E.status & ORGAN_BROKEN) user << "The [E.encased ? E.encased : "bone in the [E.name]"] moves slightly when you poke it!" - H.custom_pain("Your [E.name] hurts where it's poked.") + H.custom_pain("Your [E.name] hurts where it's poked.", 40) else user << "The [E.encased ? E.encased : "bones in the [E.name]"] seem to be fine." @@ -56,7 +56,8 @@ return var/armor = target.run_armor_check(target, "melee") - if(armor < 60) + var/soaked = target.get_armor_soak(target, "melee") + if(armor + soaked < 60) target << "You feel extreme pain!" var/max_halloss = round(target.species.total_health * 0.8) //up to 80% of passing out @@ -100,8 +101,9 @@ damage += hat.force * 3 var/armor = target.run_armor_check(BP_HEAD, "melee") - target.apply_damage(damage, BRUTE, BP_HEAD, armor) - attacker.apply_damage(10, BRUTE, BP_HEAD, attacker.run_armor_check(BP_HEAD, "melee")) + var/soaked = target.get_armor_soak(BP_HEAD, "melee") + target.apply_damage(damage, BRUTE, BP_HEAD, armor, soaked) + attacker.apply_damage(10, BRUTE, BP_HEAD, attacker.run_armor_check(BP_HEAD), attacker.get_armor_soak(BP_HEAD), "melee") if(!armor && target.headcheck(BP_HEAD) && prob(damage)) target.apply_effect(20, PARALYZE) diff --git a/code/modules/organs/blood.dm b/code/modules/organs/blood.dm index 2c4b378cde9..0f5ea190f26 100644 --- a/code/modules/organs/blood.dm +++ b/code/modules/organs/blood.dm @@ -6,6 +6,7 @@ var/const/BLOOD_VOLUME_SAFE = 85 var/const/BLOOD_VOLUME_OKAY = 75 var/const/BLOOD_VOLUME_BAD = 60 var/const/BLOOD_VOLUME_SURVIVE = 40 +var/const/CE_STABLE_THRESHOLD = 0.5 /mob/living/carbon/human/var/datum/reagents/vessel // Container for blood and BLOOD ONLY. Do not transfer other chems here. /mob/living/carbon/human/var/var/pale = 0 // Should affect how mob sprite is drawn, but currently doesn't. @@ -68,14 +69,24 @@ var/const/BLOOD_VOLUME_SURVIVE = 40 if(!heart) blood_volume = 0 - else if(heart.damage > 1 && heart.damage < heart.min_bruised_damage) - blood_volume *= 0.8 - else if(heart.damage >= heart.min_bruised_damage && heart.damage < heart.min_broken_damage) - blood_volume *= 0.6 - else if(heart.damage >= heart.min_broken_damage && heart.damage < INFINITY) + else if(heart.is_broken()) blood_volume *= 0.3 + else if(heart.is_bruised()) + blood_volume *= 0.7 + else if(heart.damage) + blood_volume *= 0.8 //Effects of bloodloss + var/dmg_coef = 1 //Lower means less damage taken + var/threshold_coef = 1 //Lower means the damage caps off lower + + if(CE_STABLE in chem_effects) + dmg_coef = 0.5 + threshold_coef = 0.75 +// These are Bay bits, do some sort of calculation. +// dmg_coef = min(1, 10/chem_effects[CE_STABLE]) //TODO: add effect for increased damage +// threshold_coef = min(dmg_coef / CE_STABLE_THRESHOLD, 1) + if(blood_volume >= BLOOD_VOLUME_SAFE) if(pale) pale = 0 @@ -89,23 +100,23 @@ var/const/BLOOD_VOLUME_SURVIVE = 40 if(prob(1)) var/word = pick("dizzy","woosey","faint") src << "\red You feel [word]" - if(oxyloss < 20) - oxyloss += 3 + if(getOxyLoss() < 20 * threshold_coef) + adjustOxyLoss(3 * dmg_coef) else if(blood_volume >= BLOOD_VOLUME_BAD) if(!pale) pale = 1 update_body() eye_blurry = max(eye_blurry,6) - if(oxyloss < 50) - oxyloss += 10 - oxyloss += 1 + if(getOxyLoss() < 50 * threshold_coef) + adjustOxyLoss(10 * dmg_coef) + adjustOxyLoss(1 * dmg_coef) if(prob(15)) Paralyse(rand(1,3)) var/word = pick("dizzy","woosey","faint") src << "\red You feel extremely [word]" else if(blood_volume >= BLOOD_VOLUME_SURVIVE) - oxyloss += 5 - toxloss += 3 + adjustOxyLoss(5 * dmg_coef) + adjustToxLoss(3 * dmg_coef) if(prob(15)) var/word = pick("dizzy","woosey","faint") src << "\red You feel extremely [word]" @@ -115,8 +126,8 @@ var/const/BLOOD_VOLUME_SURVIVE = 40 update_body() eye_blurry = max(eye_blurry,6) Paralyse(3) - toxloss += 3 - oxyloss += 75 // 15 more than dexp fixes (also more than dex+dexp+tricord) + adjustToxLoss(3 * dmg_coef) + adjustOxyLoss(75 * dmg_coef) // 15 more than dexp fixes (also more than dex+dexp+tricord) // Without enough blood you slowly go hungry. if(blood_volume < BLOOD_VOLUME_SAFE) @@ -144,6 +155,8 @@ var/const/BLOOD_VOLUME_SURVIVE = 40 blood_loss_divisor += 5 else if((temp.organ_tag == BP_L_HAND) || (temp.organ_tag == BP_R_HAND) || (temp.organ_tag == BP_L_FOOT) || (temp.organ_tag == BP_R_FOOT)) blood_loss_divisor += 10 + if(CE_STABLE in chem_effects) //Inaprov slows bloodloss + blood_loss_divisor += 10 if(temp.applied_pressure) if(ishuman(temp.applied_pressure)) var/mob/living/carbon/human/H = temp.applied_pressure diff --git a/code/modules/organs/internal/lungs.dm b/code/modules/organs/internal/lungs.dm index 6e4c15f7525..c00d5df7a83 100644 --- a/code/modules/organs/internal/lungs.dm +++ b/code/modules/organs/internal/lungs.dm @@ -24,7 +24,7 @@ /obj/item/organ/internal/lungs/proc/rupture() var/obj/item/organ/external/parent = owner.get_organ(parent_organ) if(istype(parent)) - owner.custom_pain("You feel a stabbing pain in your [parent.name]!", 1) + owner.custom_pain("You feel a stabbing pain in your [parent.name]!", 50) bruise() /obj/item/organ/internal/lungs/handle_germ_effects() diff --git a/code/modules/organs/organ.dm b/code/modules/organs/organ.dm index 30a80b6599b..4639369c7c8 100644 --- a/code/modules/organs/organ.dm +++ b/code/modules/organs/organ.dm @@ -256,7 +256,7 @@ var/list/organ_cache = list() if(owner && parent_organ && amount > 0) var/obj/item/organ/external/parent = owner.get_organ(parent_organ) if(parent && !silent) - owner.custom_pain("Something inside your [parent.name] hurts a lot.", 1) + owner.custom_pain("Something inside your [parent.name] hurts a lot.", amount) /obj/item/organ/proc/bruise() damage = max(damage, min_bruised_damage) @@ -372,5 +372,11 @@ var/list/organ_cache = list() bitten(user) return -/obj/item/organ/proc/can_feel_pain() - return !(robotic >= (ORGAN_ROBOT|ORGAN_DESTROYED)) && !(species.flags & NO_PAIN) +/obj/item/organ/proc/organ_can_feel_pain() + if(species.flags & NO_PAIN) + return 0 + if(status & ORGAN_DESTROYED) + return 0 + if(robotic && robotic < ORGAN_LIFELIKE) //Super fancy humanlike robotics probably have sensors, or something? + return 0 + return 1 \ No newline at end of file diff --git a/code/modules/organs/organ_external.dm b/code/modules/organs/organ_external.dm index b746f1be6f4..359aebe776d 100644 --- a/code/modules/organs/organ_external.dm +++ b/code/modules/organs/organ_external.dm @@ -267,7 +267,7 @@ if(status & ORGAN_BROKEN && brute) jostle_bone(brute) - if(can_feel_pain() && prob(40)) + if(organ_can_feel_pain() && prob(40)) owner.emote("scream") //getting hit on broken hand hurts if(used_weapon) add_autopsy_data("[used_weapon]", brute + burn) @@ -487,7 +487,7 @@ This function completely restores a damaged organ to perfect condition. if((damage > 15) && (type != BURN) && (local_damage > 30) && prob(damage) && (robotic < ORGAN_ROBOT)) var/datum/wound/internal_bleeding/I = new (min(damage - 15, 15)) wounds += I - owner.custom_pain("You feel something rip in your [name]!", 1) + owner.custom_pain("You feel something rip in your [name]!", 50) //Burn damage can cause fluid loss due to blistering and cook-off if((damage > 5 || damage + burn_dam >= 15) && type == BURN && (robotic < ORGAN_ROBOT)) @@ -705,7 +705,7 @@ Note that amputating the affected organ does in fact remove the infection from t owner.vessel.remove_reagent("blood", wound_update_accuracy * W.damage/40) //line should possibly be moved to handle_blood, so all the bleeding stuff is in one place. if(prob(1 * wound_update_accuracy)) - owner.custom_pain("You feel a stabbing pain in your [name]!",1) + owner.custom_pain("You feel a stabbing pain in your [name]!", 50) // slow healing var/heal_amt = 0 @@ -1010,7 +1010,7 @@ Note that amputating the affected organ does in fact remove the infection from t "Something feels like it shattered in your [name]!",\ "You hear a sickening crack.") jostle_bone() - if(can_feel_pain()) + if(organ_can_feel_pain()) owner.emote("scream") playsound(src.loc, "fracture", 10, 1, -2) diff --git a/code/modules/organs/organ_internal.dm b/code/modules/organs/organ_internal.dm index 6975e747d02..244c0b79719 100644 --- a/code/modules/organs/organ_internal.dm +++ b/code/modules/organs/organ_internal.dm @@ -248,20 +248,23 @@ if(inflamed == 1) if(prob(5)) - owner << "You feel a stinging pain in your abdomen!" - owner.emote("me", 1, "winces slightly.") + if(owner.can_feel_pain()) + owner.custom_pain("You feel a stinging pain in your abdomen!", 25) if(inflamed > 1) if(prob(3)) - owner << "You feel a stabbing pain in your abdomen!" - owner.emote("me", 1, "winces painfully.") + if(owner.can_feel_pain()) + owner.custom_pain("You feel a stabbing pain in your abdomen!", 50) owner.adjustToxLoss(1) if(inflamed > 2) if(prob(1)) owner.vomit() + if(owner.can_feel_pain()) + owner.custom_pain("You feel a horrible pain in your abdomen!", 70) if(inflamed > 3) if(prob(1)) - owner << "Your abdomen is a world of pain!" - owner.Weaken(10) + if(owner.can_feel_pain()) + owner.custom_pain("You feel a stinging pain in your abdomen!", 100) + owner.Weaken(10) var/obj/item/organ/external/groin = owner.get_organ(BP_GROIN) var/datum/wound/W = new /datum/wound/internal_bleeding(20) diff --git a/code/modules/organs/pain.dm b/code/modules/organs/pain.dm index ea9499fc436..5f3980d608c 100644 --- a/code/modules/organs/pain.dm +++ b/code/modules/organs/pain.dm @@ -5,118 +5,73 @@ mob/var/list/pain_stored = list() mob/var/last_pain_message = "" mob/var/next_pain_time = 0 -// partname is the name of a body part -// amount is a num from 1 to 100 -mob/living/carbon/proc/pain(var/partname, var/amount, var/force, var/burning = 0) - if(stat >= 1) - return - if(!can_feel_pain()) - return - if(analgesic > 40) - return - if(world.time < next_pain_time && !force) - return - if(amount > 10 && istype(src,/mob/living/carbon/human)) - if(src:paralysis) - src:paralysis = max(0, src:paralysis-round(amount/10)) - if(amount > 50 && prob(amount / 5)) - src:drop_item() - var/msg - if(burning) - switch(amount) - if(1 to 10) - msg = "Your [partname] burns." - if(11 to 90) - flash_weak_pain() - msg = "Your [partname] burns badly!" - if(91 to 10000) - flash_pain() - msg = "OH GOD! Your [partname] is on fire!" - else - switch(amount) - if(1 to 10) - msg = "Your [partname] hurts." - if(11 to 90) - flash_weak_pain() - msg = "Your [partname] hurts badly." - if(91 to 10000) - flash_pain() - msg = "OH GOD! Your [partname] is hurting terribly!" - if(msg && (msg != last_pain_message || prob(10))) - last_pain_message = msg - src << msg - next_pain_time = world.time + (100 - amount) - - // message is the custom message to be displayed -// flash_strength is 0 for weak pain flash, 1 for strong pain flash -mob/living/carbon/human/proc/custom_pain(var/message, var/flash_strength) - if(stat >= 1) - return - if(!can_feel_pain()) - return - if(reagents.has_reagent("tramadol")) - return - if(reagents.has_reagent("oxycodone")) - return - if(analgesic) - return - var/msg = "[message]" - if(flash_strength >= 1) - msg = "[message]" +// power decides how much painkillers will stop the message +// force means it ignores anti-spam timer +mob/living/carbon/proc/custom_pain(message, power, force) + if(!message || stat || !can_feel_pain() || chem_effects[CE_PAINKILLER] > power) + return 0 + message = "[message]" + if(power >= 50) + message = "[message]" // Anti message spam checks - if(msg && ((msg != last_pain_message) || (world.time >= next_pain_time))) - last_pain_message = msg - src << msg - next_pain_time = world.time + 100 + if(force || (message != last_pain_message) || (world.time >= next_pain_time)) + last_pain_message = message + src << message + next_pain_time = world.time + (100-power) mob/living/carbon/human/proc/handle_pain() - // not when sleeping + if(stat) + return - if(!can_feel_pain()) return + if(!can_feel_pain()) + return - if(stat >= 2) return - if(analgesic > 70) + if(world.time < next_pain_time) return var/maxdam = 0 var/obj/item/organ/external/damaged_organ = null for(var/obj/item/organ/external/E in organs) - if((E.status & ORGAN_DEAD) || E.robotic >= ORGAN_ROBOT) continue + if(!E.organ_can_feel_pain()) continue var/dam = E.get_damage() // make the choice of the organ depend on damage, // but also sometimes use one of the less damaged ones if(dam > maxdam && (maxdam == 0 || prob(70)) ) damaged_organ = E maxdam = dam - if(damaged_organ) - pain(damaged_organ.name, maxdam, 0) + if(damaged_organ && chem_effects[CE_PAINKILLER] < maxdam) + if(maxdam > 10 && paralysis) + paralysis = max(0, paralysis - round(maxdam/10)) + if(maxdam > 50 && prob(maxdam / 5)) + drop_item() + var/burning = damaged_organ.burn_dam > damaged_organ.brute_dam + var/msg + switch(maxdam) + if(1 to 10) + msg = "Your [damaged_organ.name] [burning ? "burns" : "hurts"]." + if(11 to 90) + flash_weak_pain() + msg = "Your [damaged_organ.name] [burning ? "burns" : "hurts"] badly!" + if(91 to 10000) + flash_pain() + msg = "OH GOD! Your [damaged_organ.name] is [burning ? "on fire" : "hurting terribly"]!" + custom_pain(msg, maxdam, prob(10)) // Damage to internal organs hurts a lot. for(var/obj/item/organ/I in internal_organs) if((I.status & ORGAN_DEAD) || I.robotic >= ORGAN_ROBOT) continue if(I.damage > 2) if(prob(2)) var/obj/item/organ/external/parent = get_organ(I.parent_organ) - src.custom_pain("You feel a sharp pain in your [parent.name]", 1) + src.custom_pain("You feel a sharp pain in your [parent.name]", 50) - var/toxDamageMessage = null - var/toxMessageProb = 1 - switch(getToxLoss()) - if(1 to 5) - toxMessageProb = 1 - toxDamageMessage = "Your body stings slightly." - if(6 to 10) - toxMessageProb = 2 - toxDamageMessage = "Your whole body hurts a little." - if(11 to 15) - toxMessageProb = 2 - toxDamageMessage = "Your whole body hurts." - if(15 to 25) - toxMessageProb = 3 - toxDamageMessage = "Your whole body hurts badly." - if(26 to INFINITY) - toxMessageProb = 5 - toxDamageMessage = "Your body aches all over, it's driving you mad." - - if(toxDamageMessage && prob(toxMessageProb)) - src.custom_pain(toxDamageMessage, getToxLoss() >= 15) \ No newline at end of file + if(prob(2)) + switch(getToxLoss()) + if(1 to 10) + custom_pain("Your body stings slightly.", getToxLoss()) + if(11 to 30) + custom_pain("Your body hurts a little.", getToxLoss()) + if(31 to 60) + custom_pain("Your whole body hurts badly.", getToxLoss()) + if(61 to INFINITY) + custom_pain("Your body aches all over, it's driving you mad.", getToxLoss()) \ No newline at end of file diff --git a/code/modules/planet/weather.dm b/code/modules/planet/weather.dm index 14318a1d7f0..c98383a2425 100644 --- a/code/modules/planet/weather.dm +++ b/code/modules/planet/weather.dm @@ -265,11 +265,15 @@ var/target_zone = pick(BP_ALL) var/amount_blocked = L.run_armor_check(target_zone, "melee") + var/amount_soaked = L.get_armor_soak(target_zone, "melee") if(amount_blocked >= 100) return // No need to apply damage. - L.apply_damage(rand(5, 10), BRUTE, target_zone, amount_blocked, used_weapon = "hail") + if(amount_soaked >= 10) + return // No need to apply damage. + + L.apply_damage(rand(5, 10), BRUTE, target_zone, amount_blocked, amount_soaked, used_weapon = "hail") to_chat(L, "The hail raining down on you [L.can_feel_pain() ? "hurts" : "damages you"]!") /datum/weather/sif/blood_moon diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Dispenser.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Dispenser.dm index 44ad6f24a2b..091842663d2 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Dispenser.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Dispenser.dm @@ -349,7 +349,7 @@ if(affecting.take_damage(0, removed * power * 0.1)) H.UpdateDamageIcon() if(prob(100 * removed / meltdose)) // Applies disfigurement - if (affecting.can_feel_pain()) + if (affecting.organ_can_feel_pain()) H.emote("scream") H.status_flags |= DISFIGURED else diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Medicine.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Medicine.dm index c049f3c0e94..3712baa895d 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Medicine.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Medicine.dm @@ -14,8 +14,8 @@ /datum/reagent/inaprovaline/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) if(alien != IS_DIONA) - M.add_chemical_effect(CE_STABLE) - M.add_chemical_effect(CE_PAINKILLER, 25) + M.add_chemical_effect(CE_STABLE, 15) + M.add_chemical_effect(CE_PAINKILLER, 10) /datum/reagent/bicaridine name = "Bicaridine" @@ -76,6 +76,29 @@ M.hallucination = max(0, M.hallucination - 9 * removed) M.adjustToxLoss(-4 * removed) +/datum/reagent/carthatoline + name = "carthatoline" + id = "carthatoline" + description = "Carthatoline is strong evacuant used to treat severe poisoning." + reagent_state = LIQUID + color = "#225722" + scannable = 1 + +/datum/reagent/carthatoline/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_DIONA) + return + if(M.getToxLoss() && prob(10)) + M.vomit(1) + M.adjustToxLoss(-8 * removed) + if(ishuman(M)) + var/mob/living/carbon/human/H = M + var/obj/item/organ/internal/liver/L = H.internal_organs_by_name[O_LIVER] + if(istype(L)) + if(L.robotic >= ORGAN_ROBOT) + return + if(L.damage > 0) + L.damage = max(L.damage - 2 * removed, 0) + /datum/reagent/dexalin name = "Dexalin" id = "dexalin" @@ -109,7 +132,7 @@ if(alien == IS_VOX) M.adjustToxLoss(removed * 9) else if(alien != IS_DIONA) - M.adjustOxyLoss(-300 * removed) + M.adjustOxyLoss(-150 * removed) holder.remove_reagent("lexorin", 3 * removed) @@ -179,7 +202,7 @@ mrate_static = TRUE /datum/reagent/paracetamol/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) - M.add_chemical_effect(CE_PAINKILLER, 50) + M.add_chemical_effect(CE_PAINKILLER, 25) /datum/reagent/paracetamol/overdose(var/mob/living/carbon/M, var/alien) ..() @@ -217,6 +240,8 @@ /datum/reagent/oxycodone/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) M.add_chemical_effect(CE_PAINKILLER, 200) + M.eye_blurry += 10 + M.confused += 5 /datum/reagent/oxycodone/overdose(var/mob/living/carbon/M, var/alien) ..() @@ -246,7 +271,7 @@ holder.remove_reagent("mindbreaker", 5) M.hallucination = max(0, M.hallucination - 10) M.adjustToxLoss(5 * removed) // It used to be incredibly deadly due to an oversight. Not anymore! - M.add_chemical_effect(CE_PAINKILLER, 40) + M.add_chemical_effect(CE_PAINKILLER, 20) /datum/reagent/alkysine name = "Alkysine" @@ -307,9 +332,60 @@ continue if(I.damage > 0) //Peridaxon heals only non-robotic organs I.damage = max(I.damage - removed, 0) + H.confused += 5 if(I.damage <= 5 && I.organ_tag == O_EYES) + H.eye_blurry += 10 //Eyes need to reset, or something H.sdisabilities &= ~BLIND +/datum/reagent/osteodaxon + name = "Osteodaxon" + id = "osteodaxon" + description = "An experimental drug used to heal bone fractures." + reagent_state = LIQUID + color = "#C9BCE3" + metabolism = REM * 0.5 + overdose = REAGENTS_OVERDOSE * 0.5 + scannable = 1 + +/datum/reagent/osteodaxon/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_DIONA) + return + M.heal_organ_damage(3 * removed, 0) //Gives the bones a chance to set properly even without other meds + if(ishuman(M)) + var/mob/living/carbon/human/H = M + for(var/obj/item/organ/external/O in H.bad_external_organs) + if(O.status & ORGAN_BROKEN) + O.mend_fracture() //Only works if the bone won't rebreak, as usual + H.custom_pain("You feel a terrible agony tear through your bones!",60) + H.AdjustWeakened(1) //Bones being regrown will knock you over + +/datum/reagent/myelamine + name = "Myelamine" + id = "myelamine" + description = "Used to rapidly clot internal hemorrhages by increasing the effectiveness of platelets." + reagent_state = LIQUID + color = "#4246C7" + metabolism = REM * 0.5 + overdose = REAGENTS_OVERDOSE * 0.5 + scannable = 1 + +/datum/reagent/myelamine/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_DIONA) + return + M.eye_blurry += (3 * removed) + if(ishuman(M)) + var/mob/living/carbon/human/H = M + for(var/obj/item/organ/external/O in H.bad_external_organs) + for(var/datum/wound/W in O.wounds) + if(W.bleeding()) + W.damage = max(W.damage - removed, 0) + if(W.damage <= 0) + O.wounds -= W + if(W.internal) + W.damage = max(W.damage - removed, 0) + if(W.damage <= 0) + O.wounds -= W + /datum/reagent/ryetalyn name = "Ryetalyn" id = "ryetalyn" @@ -364,6 +440,8 @@ scannable = 1 /datum/reagent/hyronalin/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_DIONA) + return M.radiation = max(M.radiation - 30 * removed, 0) /datum/reagent/arithrazine @@ -378,6 +456,8 @@ scannable = 1 /datum/reagent/arithrazine/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_DIONA) + return M.radiation = max(M.radiation - 70 * removed, 0) M.adjustToxLoss(-10 * removed) if(prob(60)) @@ -432,11 +512,35 @@ scannable = 1 /datum/reagent/leporazine/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_DIONA) + return if(M.bodytemperature > 310) M.bodytemperature = max(310, M.bodytemperature - (40 * TEMPERATURE_DAMAGE_COEFFICIENT)) else if(M.bodytemperature < 311) M.bodytemperature = min(310, M.bodytemperature + (40 * TEMPERATURE_DAMAGE_COEFFICIENT)) +/datum/reagent/rezadone + name = "Rezadone" + id = "rezadone" + description = "A powder with almost magical properties, this substance can effectively treat genetic damage in humanoids, though excessive consumption has side effects." + reagent_state = SOLID + color = "#669900" + overdose = REAGENTS_OVERDOSE + scannable = 1 + +/datum/reagent/rezadone/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) + if(alien == IS_DIONA) + return + M.adjustCloneLoss(-20 * removed) + M.adjustOxyLoss(-2 * removed) + M.heal_organ_damage(20 * removed, 20 * removed) + M.adjustToxLoss(-20 * removed) + if(dose > 3) + M.status_flags &= ~DISFIGURED + if(dose > 10) + M.make_dizzy(5) + M.make_jittery(5) + /* Antidepressants */ #define ANTIDEPRESSANT_MESSAGE_DELAY 5*60*10 diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm index 15ff2e4f80e..e13a73dd298 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm @@ -43,6 +43,13 @@ color = "#003333" strength = 10 +/datum/reagent/toxin/spidertoxin + name = "Spidertoxin" + id = "spidertoxin" + description = "A liquifying toxin produced by giant spiders." + color = "#2CE893" + strength = 5 + /datum/reagent/toxin/phoron name = "Phoron" id = "phoron" diff --git a/code/modules/reagents/Chemistry-Recipes.dm b/code/modules/reagents/Chemistry-Recipes.dm index 9a3b324b30c..dbe8ca528f1 100644 --- a/code/modules/reagents/Chemistry-Recipes.dm +++ b/code/modules/reagents/Chemistry-Recipes.dm @@ -160,6 +160,14 @@ required_reagents = list("silicon" = 1, "potassium" = 1, "nitrogen" = 1) result_amount = 3 +/datum/chemical_reaction/carthatoline + name = "Carthatoline" + id = "carthatoline" + result = "carthatoline" + required_reagents = list("dylovene" = 1, "carbon" = 2, "phoron" = 0.1) + catalysts = list("phoron" = 1) + result_amount = 2 + /datum/chemical_reaction/tramadol name = "Tramadol" id = "tramadol" @@ -282,6 +290,15 @@ catalysts = list("phoron" = 5) result_amount = 2 +/datum/chemical_reaction/osteodaxon + name = "Osteodaxon" + id = "osteodaxon" + result = "osteodaxon" + required_reagents = list("bicaridine" = 2, "phoron" = 0.1, "carpotoxin" = 1) + catalysts = list("phoron" = 5) + inhibitors = list("clonexadone" = 1) // Messes with cryox + result_amount = 2 + /datum/chemical_reaction/virus_food name = "Virus Food" id = "virusfood" @@ -349,6 +366,13 @@ inhibitors = list("sugar" = 1) // Messes up with inaprovaline result_amount = 2 +/datum/chemical_reaction/myelamine + name = "Myelamine" + id = "myelamine" + result = "myelamine" + required_reagents = list("bicaridine" = 1, "iron" = 2, "spidertoxin" = 1) + result_amount = 2 + /datum/chemical_reaction/hyperzine name = "Hyperzine" id = "hyperzine" diff --git a/code/modules/reagents/reagent_containers/food/snacks.dm b/code/modules/reagents/reagent_containers/food/snacks.dm index 64b05fe0d3d..5ea23727314 100644 --- a/code/modules/reagents/reagent_containers/food/snacks.dm +++ b/code/modules/reagents/reagent_containers/food/snacks.dm @@ -734,6 +734,19 @@ reagents.add_reagent("pacid",6) src.bitesize = 6 +/obj/item/weapon/reagent_containers/food/snacks/spidermeat + name = "meat" + desc = "A slab of green meat." + icon_state = "xenomeat" + filling_color = "#43DE18" + center_of_mass = list("x"=16, "y"=10) + +/obj/item/weapon/reagent_containers/food/snacks/spidermeat/New() + ..() + reagents.add_reagent("protein", 6) + reagents.add_reagent("spidertoxin",6) + src.bitesize = 6 + /obj/item/weapon/reagent_containers/food/snacks/meatball name = "meatball" desc = "A great meal all round." diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm index 771ce4cc274..e9e3c62dada 100644 --- a/code/modules/reagents/reagent_containers/hypospray.dm +++ b/code/modules/reagents/reagent_containers/hypospray.dm @@ -88,3 +88,33 @@ user << "It is currently loaded." else user << "It is spent." + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/clotting + name = "clotting agent" + desc = "A rapid and safe way to administer clotting drugs by untrained or trained personnel." + icon_state = "autoinjector" + item_state = "autoinjector" + amount_per_transfer_from_this = 10 + volume = 10 + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/clotting/New() + ..() + reagents.remove_reagent("inaprovaline", 5) + reagents.add_reagent("myelamine", 10) + update_icon() + return + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/bonemed + name = "bone repair injector" + desc = "A rapid and safe way to administer advanced drugs by untrained or trained personnel." + icon_state = "autoinjector" + item_state = "autoinjector" + amount_per_transfer_from_this = 10 + volume = 10 + +/obj/item/weapon/reagent_containers/hypospray/autoinjector/bonemed/New() + ..() + reagents.remove_reagent("inaprovaline", 5) + reagents.add_reagent("osteodaxon", 10) + update_icon() + return \ No newline at end of file diff --git a/code/modules/research/message_server.dm b/code/modules/research/message_server.dm index f89e8a20cd0..53d534a619f 100644 --- a/code/modules/research/message_server.dm +++ b/code/modules/research/message_server.dm @@ -242,6 +242,7 @@ var/obj/machinery/blackbox_recorder/blackbox var/list/msg_security = list() var/list/msg_deathsquad = list() var/list/msg_syndicate = list() + var/list/msg_raider = list() var/list/msg_cargo = list() var/list/msg_service = list() diff --git a/code/modules/supermatter/supermatter.dm b/code/modules/supermatter/supermatter.dm index 7457b7790d8..df9c900d384 100644 --- a/code/modules/supermatter/supermatter.dm +++ b/code/modules/supermatter/supermatter.dm @@ -50,7 +50,7 @@ var/public_alert = 0 //Stick to Engineering frequency except for big warnings when integrity bad var/warning_point = 100 var/warning_alert = "Danger! Crystal hyperstructure instability!" - var/emergency_point = 700 + var/emergency_point = 500 var/emergency_alert = "CRYSTAL DELAMINATION IMMINENT." var/explosion_point = 1000 diff --git a/code/modules/surgery/bones.dm b/code/modules/surgery/bones.dm index 015661351fd..80a7a1f8209 100644 --- a/code/modules/surgery/bones.dm +++ b/code/modules/surgery/bones.dm @@ -25,7 +25,7 @@ if (affected.stage == 0) user.visible_message("[user] starts applying medication to the damaged bones in [target]'s [affected.name] with \the [tool]." , \ "You start applying medication to the damaged bones in [target]'s [affected.name] with \the [tool].") - target.custom_pain("Something in your [affected.name] is causing you a lot of pain!",1) + target.custom_pain("Something in your [affected.name] is causing you a lot of pain!", 50) ..() end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) @@ -58,7 +58,7 @@ var/obj/item/organ/external/affected = target.get_organ(target_zone) user.visible_message("[user] is beginning to set the bone in [target]'s [affected.name] in place with \the [tool]." , \ "You are beginning to set the bone in [target]'s [affected.name] in place with \the [tool].") - target.custom_pain("The pain in your [affected.name] is going to make you pass out!",1) + target.custom_pain("The pain in your [affected.name] is going to make you pass out!", 50) ..() end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) diff --git a/code/modules/surgery/encased.dm b/code/modules/surgery/encased.dm index 51200b52bf5..abcc0621dac 100644 --- a/code/modules/surgery/encased.dm +++ b/code/modules/surgery/encased.dm @@ -38,7 +38,7 @@ user.visible_message("[user] begins to cut through [target]'s [affected.encased] with \the [tool].", \ "You begin to cut through [target]'s [affected.encased] with \the [tool].") - target.custom_pain("Something hurts horribly in your [affected.name]!",1) + target.custom_pain("Something hurts horribly in your [affected.name]!", 60) ..() end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) @@ -88,7 +88,7 @@ var/msg = "[user] starts to force open the [affected.encased] in [target]'s [affected.name] with \the [tool]." var/self_msg = "You start to force open the [affected.encased] in [target]'s [affected.name] with \the [tool]." user.visible_message(msg, self_msg) - target.custom_pain("Something hurts horribly in your [affected.name]!",1) + target.custom_pain("Something hurts horribly in your [affected.name]!", 40) ..() end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) @@ -145,7 +145,7 @@ var/msg = "[user] starts bending [target]'s [affected.encased] back into place with \the [tool]." var/self_msg = "You start bending [target]'s [affected.encased] back into place with \the [tool]." user.visible_message(msg, self_msg) - target.custom_pain("Something hurts horribly in your [affected.name]!",1) + target.custom_pain("Something hurts horribly in your [affected.name]!", 100) ..() end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) @@ -202,7 +202,7 @@ var/msg = "[user] starts applying \the [tool] to [target]'s [affected.encased]." var/self_msg = "You start applying \the [tool] to [target]'s [affected.encased]." user.visible_message(msg, self_msg) - target.custom_pain("Something hurts horribly in your [affected.name]!",1) + target.custom_pain("Something hurts horribly in your [affected.name]!", 100) ..() end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) diff --git a/code/modules/surgery/generic.dm b/code/modules/surgery/generic.dm index 81a105a5443..513b6096dc9 100644 --- a/code/modules/surgery/generic.dm +++ b/code/modules/surgery/generic.dm @@ -42,7 +42,7 @@ var/obj/item/organ/external/affected = target.get_organ(target_zone) user.visible_message("[user] starts the bloodless incision on [target]'s [affected.name] with \the [tool].", \ "You start the bloodless incision on [target]'s [affected.name] with \the [tool].") - target.custom_pain("You feel a horrible, searing pain in your [affected.name]!",1) + target.custom_pain("You feel a horrible, searing pain in your [affected.name]!", 50) ..() end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) @@ -81,7 +81,7 @@ var/obj/item/organ/external/affected = target.get_organ(target_zone) user.visible_message("[user] starts to construct a prepared incision on and within [target]'s [affected.name] with \the [tool].", \ "You start to construct a prepared incision on and within [target]'s [affected.name] with \the [tool].") - target.custom_pain("You feel a horrible, searing pain in your [affected.name] as it is pushed apart!",1) + target.custom_pain("You feel a horrible, searing pain in your [affected.name] as it is pushed apart!", 50) ..() end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) @@ -124,7 +124,7 @@ var/obj/item/organ/external/affected = target.get_organ(target_zone) user.visible_message("[user] starts the incision on [target]'s [affected.name] with \the [tool].", \ "You start the incision on [target]'s [affected.name] with \the [tool].") - target.custom_pain("You feel a horrible pain as if from a sharp knife in your [affected.name]!",1) + target.custom_pain("You feel a horrible pain as if from a sharp knife in your [affected.name]!", 40) ..() end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) @@ -163,7 +163,7 @@ var/obj/item/organ/external/affected = target.get_organ(target_zone) user.visible_message("[user] starts clamping bleeders in [target]'s [affected.name] with \the [tool].", \ "You start clamping bleeders in [target]'s [affected.name] with \the [tool].") - target.custom_pain("The pain in your [affected.name] is maddening!",1) + target.custom_pain("The pain in your [affected.name] is maddening!", 40) ..() end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) @@ -205,7 +205,7 @@ msg = "[user] starts to pry open the incision and rearrange the organs in [target]'s lower abdomen with \the [tool]." self_msg = "You start to pry open the incision and rearrange the organs in [target]'s lower abdomen with \the [tool]." user.visible_message(msg, self_msg) - target.custom_pain("It feels like the skin on your [affected.name] is on fire!",1) + target.custom_pain("It feels like the skin on your [affected.name] is on fire!", 40) ..() end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) @@ -254,7 +254,7 @@ var/obj/item/organ/external/affected = target.get_organ(target_zone) user.visible_message("[user] is beginning to cauterize the incision on [target]'s [affected.name] with \the [tool]." , \ "You are beginning to cauterize the incision on [target]'s [affected.name] with \the [tool].") - target.custom_pain("Your [affected.name] is being burned!",1) + target.custom_pain("Your [affected.name] is being burned!", 40) ..() end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) @@ -295,7 +295,7 @@ var/obj/item/organ/external/affected = target.get_organ(target_zone) user.visible_message("[user] is beginning to amputate [target]'s [affected.name] with \the [tool]." , \ "You are beginning to cut through [target]'s [affected.amputation_point] with \the [tool].") - target.custom_pain("Your [affected.amputation_point] is being ripped apart!",1) + target.custom_pain("Your [affected.amputation_point] is being ripped apart!", 100) ..() end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) diff --git a/code/modules/surgery/organs_internal.dm b/code/modules/surgery/organs_internal.dm index 6abe4c36460..205089773d5 100644 --- a/code/modules/surgery/organs_internal.dm +++ b/code/modules/surgery/organs_internal.dm @@ -56,7 +56,7 @@ user.visible_message("[user] starts treating damage to [target]'s [I.name] with [tool_name].", \ "You start treating damage to [target]'s [I.name] with [tool_name]." ) - target.custom_pain("The pain in your [affected.name] is living hell!",1) + target.custom_pain("The pain in your [affected.name] is living hell!", 100) ..() end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) @@ -146,7 +146,7 @@ user.visible_message("[user] starts to separate [target]'s [target.op_stage.current_organ] with \the [tool].", \ "You start to separate [target]'s [target.op_stage.current_organ] with \the [tool]." ) - target.custom_pain("The pain in your [affected.name] is living hell!",1) + target.custom_pain("The pain in your [affected.name] is living hell!", 100) ..() end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) @@ -197,7 +197,7 @@ begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) user.visible_message("[user] starts removing [target]'s [target.op_stage.current_organ] with \the [tool].", \ "You start removing [target]'s [target.op_stage.current_organ] with \the [tool].") - target.custom_pain("Someone's ripping out your [target.op_stage.current_organ]!",1) + target.custom_pain("Someone's ripping out your [target.op_stage.current_organ]!", 100) ..() end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) @@ -271,7 +271,7 @@ var/obj/item/organ/external/affected = target.get_organ(target_zone) user.visible_message("[user] starts transplanting \the [tool] into [target]'s [affected.name].", \ "You start transplanting \the [tool] into [target]'s [affected.name].") - target.custom_pain("Someone's rooting around in your [affected.name]!",1) + target.custom_pain("Someone's rooting around in your [affected.name]!", 100) ..() end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) @@ -322,7 +322,7 @@ begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) user.visible_message("[user] begins reattaching [target]'s [target.op_stage.current_organ] with \the [tool].", \ "You start reattaching [target]'s [target.op_stage.current_organ] with \the [tool].") - target.custom_pain("Someone's digging needles into your [target.op_stage.current_organ]!",1) + target.custom_pain("Someone's digging needles into your [target.op_stage.current_organ]!", 100) ..() end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) diff --git a/code/modules/surgery/other.dm b/code/modules/surgery/other.dm index 2b931391118..176724290fb 100644 --- a/code/modules/surgery/other.dm +++ b/code/modules/surgery/other.dm @@ -33,7 +33,7 @@ var/obj/item/organ/external/affected = target.get_organ(target_zone) user.visible_message("[user] starts patching the damaged vein in [target]'s [affected.name] with \the [tool]." , \ "You start patching the damaged vein in [target]'s [affected.name] with \the [tool].") - target.custom_pain("The pain in [affected.name] is unbearable!",1) + target.custom_pain("The pain in [affected.name] is unbearable!", 100) ..() end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) @@ -81,7 +81,7 @@ var/obj/item/organ/external/affected = target.get_organ(target_zone) user.visible_message("[user] starts cutting away necrotic tissue in [target]'s [affected.name] with \the [tool]." , \ "You start cutting away necrotic tissue in [target]'s [affected.name] with \the [tool].") - target.custom_pain("The pain in [affected.name] is unbearable!",1) + target.custom_pain("The pain in [affected.name] is unbearable!", 100) ..() end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) @@ -133,7 +133,7 @@ var/obj/item/organ/external/affected = target.get_organ(target_zone) user.visible_message("[user] starts applying medication to the affected tissue in [target]'s [affected.name] with \the [tool]." , \ "You start applying medication to the affected tissue in [target]'s [affected.name] with \the [tool].") - target.custom_pain("Something in your [affected.name] is causing you a lot of pain!",1) + target.custom_pain("Something in your [affected.name] is causing you a lot of pain!", 50) ..() end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) diff --git a/code/modules/virus2/effect.dm b/code/modules/virus2/effect.dm index 8ca82b96a17..5243bae35f6 100644 --- a/code/modules/virus2/effect.dm +++ b/code/modules/virus2/effect.dm @@ -121,13 +121,11 @@ stage = 4 badness = 3 activate(var/mob/living/carbon/mob,var/multiplier) - mob.suiciding = 1 + mob.suiciding = 30 //instead of killing them instantly, just put them at -175 health and let 'em gasp for a while viewers(mob) << "\red [mob.name] is holding \his breath. It looks like \he's trying to commit suicide." mob.adjustOxyLoss(175 - mob.getToxLoss() - mob.getFireLoss() - mob.getBruteLoss() - mob.getOxyLoss()) mob.updatehealth() - spawn(200) //in case they get revived by cryo chamber or something stupid like that, let them suicide again in 20 seconds - mob.suiciding = 0 /datum/disease2/effect/killertoxins name = "Toxification Syndrome" diff --git a/html/changelogs/Anewbe - Medical.yml b/html/changelogs/Anewbe - Medical.yml new file mode 100644 index 00000000000..758042ae691 --- /dev/null +++ b/html/changelogs/Anewbe - Medical.yml @@ -0,0 +1,49 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# wip (For works in progress) +# tweak +# soundadd +# sounddel +# rscadd (general adding of nice things) +# rscdel (general deleting of nice things) +# imageadd +# imagedel +# maptweak +# spellcheck (typo fixes) +# experiment +################################# + +# Your name. +author: Anewbe + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. +# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. +changes: + - rscadd: "Added a changelog editing system that should cause fewer conflicts and more accurate timestamps." + - rscadd: "Added Myelamine, a blood clotting chemical. This is available to antags, and can be ordered from cargo or mixed." + - rscadd: "Added Osteodaxon, a bone fixing medicine. This is available to antags, and can be mixed." + - rscadd: "Added Carthatoline, a stronger anti-toxin." + - rscadd: "Added Spidertoxin, which comes from spiders (duh), and is used in making Myelamine." + - rscadd: "Death Alarms can now be ordered from cargo." + - rscdel: "Dexalin Plus is half as strong (still pretty strong, though). + - rscadd: "Ninja, Merc, and ERT-M Hardsuits can now inject myelamine." + - tweak: "Inaprovaline now decreases the effects of bloodloss, and lessens brain damage taken from OxyLoss." + - tweak: "Prosthetic organs now take randomised damage when emp'd, this should roughly average out to the old values." + - tweak: "The effects of heart damage have been tweaked, should be slightly easier to survive now." + - tweak: "Some of the stronger chems have side effects, like confusion or blurry vision. These should be fairly minor, and we may be tweaking them in the future." + - tweak: "The suiciding var now wears off, making it possible to save suicide victims if quick action is taken." + - tweak: "Death Alarms now announce on General comms again." \ No newline at end of file diff --git a/html/changelogs/Anewbe - Tables.yml b/html/changelogs/Anewbe - Tables.yml new file mode 100644 index 00000000000..b99569b5784 --- /dev/null +++ b/html/changelogs/Anewbe - Tables.yml @@ -0,0 +1,36 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# wip (For works in progress) +# tweak +# soundadd +# sounddel +# rscadd (general adding of nice things) +# rscdel (general deleting of nice things) +# imageadd +# imagedel +# maptweak +# spellcheck (typo fixes) +# experiment +################################# + +# Your name. +author: Anewbe + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. +# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. +changes: + - rscadd: "Borgs can climb tables." diff --git a/icons/mob/items/lefthand.dmi b/icons/mob/items/lefthand.dmi index ad160c72475..975ddbe3b12 100644 Binary files a/icons/mob/items/lefthand.dmi and b/icons/mob/items/lefthand.dmi differ diff --git a/icons/mob/items/lefthand_material.dmi b/icons/mob/items/lefthand_material.dmi index 70127575ee6..dc642311e5d 100644 Binary files a/icons/mob/items/lefthand_material.dmi and b/icons/mob/items/lefthand_material.dmi differ diff --git a/icons/mob/items/righthand.dmi b/icons/mob/items/righthand.dmi index 9eb88606cac..b93636d66d7 100644 Binary files a/icons/mob/items/righthand.dmi and b/icons/mob/items/righthand.dmi differ diff --git a/icons/mob/items/righthand_material.dmi b/icons/mob/items/righthand_material.dmi index db11ee211f6..44904c68c75 100644 Binary files a/icons/mob/items/righthand_material.dmi and b/icons/mob/items/righthand_material.dmi differ diff --git a/icons/obj/items.dmi b/icons/obj/items.dmi index c0df5a707f7..dc3456ba672 100644 Binary files a/icons/obj/items.dmi and b/icons/obj/items.dmi differ diff --git a/icons/obj/weapons.dmi b/icons/obj/weapons.dmi index 884b8ac41ef..1e7a4ba8a7f 100644 Binary files a/icons/obj/weapons.dmi and b/icons/obj/weapons.dmi differ