Merge branch 'master' into upstream-merge-9307

This commit is contained in:
cadyn
2020-11-15 00:48:22 -08:00
committed by GitHub
149 changed files with 17211 additions and 466 deletions
+1 -1
View File
@@ -5,7 +5,7 @@
var/input_NIF
if(!check_rights(R_ADMIN|R_EVENT|R_DEBUG)) //CHOMPStation Edit TFF 24/4/19: Allow Devs to use Quick-NIF verb.
if(!check_rights(R_ADMIN|R_EVENT|R_DEBUG|R_MOD)) //CHOMPStation Edit TFF 24/4/19: Allow Devs to use Quick-NIF verb. 11/9/20: Also allow mods :3
return
var/mob/living/carbon/human/H = input("Pick a mob with a player","Quick NIF") as null|anything in player_list
@@ -0,0 +1,11 @@
/datum/gear/cigar_case
display_name = "cigar case"
path = /obj/item/weapon/storage/fancy/cigar
/datum/gear/cigar_case/New()
..()
var/list/cigars = list()
for(var/cigar in (typesof(/obj/item/weapon/storage/fancy/cigar)))
var/obj/item/weapon/storage/fancy/cigar/cigar_brand = cigar
cigars[initial(cigar_brand.name)] = cigar_brand
gear_tweaks += new/datum/gear_tweak/path(sortAssoc(cigars))
@@ -614,3 +614,34 @@
display_name = "disheveled suit"
path = /obj/item/clothing/under/disheveled
/datum/gear/uniform/orangedress
display_name = "orange dress"
path = /obj/item/clothing/under/dress/dress_orange
/datum/gear/uniform/sundress_pink
display_name = "pink sundress"
path = /obj/item/clothing/under/dress/sundress_pink
/datum/gear/uniform/sundress_white
display_name = "white sundress"
path = /obj/item/clothing/under/dress/sundress_white
/datum/gear/uniform/sundress_pinkbow
display_name = "bowed pink sundress"
path = /obj/item/clothing/under/dress/sundress_pinkbow
/datum/gear/uniform/sundress_blue
display_name = "long blue sundress"
path = /obj/item/clothing/under/dress/sundress_blue
/datum/gear/uniform/sundress_pinkshort
display_name = "short pink sundress"
path = /obj/item/clothing/under/dress/sundress_pinkshort
/datum/gear/uniform/twopiece
display_name = "two-piece dress"
path = /obj/item/clothing/under/dress/twopiece
/datum/gear/uniform/gothic2
display_name = "lacey gothic dress"
path = /obj/item/clothing/under/dress/gothic2
@@ -184,9 +184,12 @@
return TOPIC_REFRESH
else if(href_list["clicked_pos_trait"])
var/traitpath = text2path(href_list["clicked_pos_trait"]) //CHOMPEdit
var/datum/trait/trait = text2path(href_list["clicked_pos_trait"])
var/choice = alert("Remove [initial(trait.name)] and regain [initial(trait.cost)] points?","Remove Trait","Remove","Cancel")
if(choice == "Remove")
if(traitpath == /datum/trait/linguist) //CHOMPEdit
pref.num_languages = 0 //CHOMPEdit
pref.pos_traits -= trait
return TOPIC_REFRESH
@@ -287,7 +290,8 @@
alert("You cannot take this trait and [conflict] at the same time. \
Please remove that trait, or pick another trait to add.","Error")
return TOPIC_REFRESH
if(path==/datum/trait/linguist) //CHOMPEdit
pref.num_languages = 12 //CHOMPEdit
mylist += path
return TOPIC_REFRESH
@@ -159,6 +159,12 @@
icon_state = "scrubsnavyblue"
item_state_slots = list(slot_r_hand_str = "blue", slot_l_hand_str = "blue")
/obj/item/clothing/under/rank/medical/scrubs/white
name = "scrubs"
desc = "It's made of a special fiber that provides minor protection against biohazards"
icon_state = "scrubs"
item_state_slots = list(slot_r_hand_str = "white", slot_l_hand_str = "white")
/obj/item/clothing/under/rank/psych
desc = "A basic white jumpsuit. It has turqouise markings that denote the wearer as a psychiatrist."
name = "psychiatrist's jumpsuit"
+42 -1
View File
@@ -621,7 +621,7 @@ Uniforms and such
*/
/obj/item/clothing/under/sundress
name = "sundress"
name = "flowery white sundress"
desc = "Makes you want to frolic in a field of daisies."
icon_state = "sundress"
body_parts_covered = UPPER_TORSO|LOWER_TORSO
@@ -632,6 +632,47 @@ Uniforms and such
icon_state = "sundress_white"
body_parts_covered = UPPER_TORSO|LOWER_TORSO
/obj/item/clothing/under/dress/sundress_pink
name = "pink stripied sundress"
desc = "A cute pink sundress."
icon_state = "pinksun"
body_parts_covered = UPPER_TORSO|LOWER_TORSO
/obj/item/clothing/under/dress/sundress_white
name = "white sundress"
desc = "A white sundress, it's short."
icon_state = "whitesun"
body_parts_covered = UPPER_TORSO|LOWER_TORSO
/obj/item/clothing/under/dress/sundress_pinkbow
name = "bowed pink sundress"
desc = "A cute pink sundress with a bow."
icon_state = "bowsun"
body_parts_covered = UPPER_TORSO|LOWER_TORSO
/obj/item/clothing/under/dress/sundress_blue
name = "long blue sundress"
desc = "A long blue sun dress with white frills towards the bottom."
icon_state = "bluesun"
body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS
/obj/item/clothing/under/dress/sundress_pinkshort
name = "short pink sundress"
desc = "A very short pink sundress, it's more like a chemise."
icon_state = "shortpink"
body_parts_covered = UPPER_TORSO|LOWER_TORSO
/obj/item/clothing/under/dress/twopiece
name = "two-piece dress"
desc = "A fancy two-piece dress, the pieces are sewn together."
icon_state = "twopiece"
body_parts_covered = UPPER_TORSO|LOWER_TORSO
/obj/item/clothing/under/dress/gothic2
name = "lacey gothic dress"
desc = "An elegant gothic dress with lace decorations."
icon_state = "gothic2"
/obj/item/clothing/under/captainformal
name = "site manager's formal uniform"
desc = "A Site Manager's formal-wear, for special occasions."
+1 -1
View File
@@ -7,7 +7,7 @@
// List of all non-destroyed canisters on station levels
var/list/all_canisters = list()
for(var/obj/machinery/portable_atmospherics/canister/C in machines)
if(!C.destroyed && (C.z in using_map.station_levels) && C.air_contents.total_moles >= MOLES_CELLSTANDARD)
if(!C.destroyed && (C.z in using_map.station_levels) && C.air_contents.total_moles >= MOLES_CELLSTANDARD && !C.dont_burst) //CHOMPEdit
all_canisters += C
for(var/i in 1 to 10)
+4 -1
View File
@@ -73,7 +73,7 @@
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Carp School", /datum/event/carp_migration, -20, list(ASSIGNMENT_ENGINEER = 10, ASSIGNMENT_SECURITY = 30, ASSIGNMENT_HOS = 10, ASSIGNMENT_WARDEN = 5), 1),
// Just disables comms for a short while.
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Communication Blackout", /datum/event/communications_blackout, 500, list(ASSIGNMENT_AI = 150, ASSIGNMENT_SECURITY = 120), 1),
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Drone Pod Drop", /datum/event/drone_pod_drop, 10, list(ASSIGNMENT_SCIENTIST = 40), 1),
// Just blows out a few lights
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Electrical Storm", /datum/event/electrical_storm, 250, list(ASSIGNMENT_ENGINEER = 20, ASSIGNMENT_JANITOR = 150), 1),
//Escaped slime event itself needs to be rejiggered because of the mob refactor.
@@ -102,6 +102,8 @@
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Meteor Shower", /datum/event/meteor_wave, 30, list(ASSIGNMENT_ENGINEER = 20)),
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Random Antagonist", /datum/event/random_antag, 2.5, list(ASSIGNMENT_SECURITY = 1), 1, 0, 5),
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Carp School", /datum/event/carp_migration, 0, list(ASSIGNMENT_SECURITY = 30), 1),
//Commenting this event out, the pod is not mapped in.
//new /datum/event_meta(EVENT_LEVEL_MODERATE, "Drone Pod Drop", /datum/event/drone_pod_drop, 10, list(ASSIGNMENT_SCIENTIST = 40), 1),
//Spacedust doesn't work, commenting this out.
//new /datum/event_meta(EVENT_LEVEL_MODERATE, "Space Dust", /datum/event/dust, 0, list(ASSIGNMENT_ENGINEER = 20), 1, 0, 50),
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Maintenance Predator", /datum/event/maintenance_predator, 75, list(ASSIGNMENT_SECURITY = 25, ASSIGNMENT_SCIENTIST = 10), 1),
@@ -120,6 +122,7 @@
new /datum/event_meta(EVENT_LEVEL_MAJOR, "Blob", /datum/event/blob, -100, list(ASSIGNMENT_SECURITY = 40, ASSIGNMENT_HOS = 10, ASSIGNMENT_WARDEN = 10, ASSIGNMENT_ENGINEER = 5), 1),
new /datum/event_meta(EVENT_LEVEL_MAJOR, "Carp Migration", /datum/event/carp_migration, -110, list(ASSIGNMENT_SECURITY = 50, ASSIGNMENT_HOS = 10, ASSIGNMENT_WARDEN = 10), 1),
new /datum/event_meta(EVENT_LEVEL_MAJOR, "Containment Breach", /datum/event/prison_break/station,0, list(ASSIGNMENT_ANY = 5), 0),
new /datum/event_meta(EVENT_LEVEL_MODERATE, "Drone Pod Drop", /datum/event/drone_pod_drop, 10, list(ASSIGNMENT_SCIENTIST = 40), 1),
new /datum/event_meta(EVENT_LEVEL_MAJOR, "Meteor Wave", /datum/event/meteor_wave, -110, list(ASSIGNMENT_ENGINEER = 50), 1),
new /datum/event_meta(EVENT_LEVEL_MAJOR, "Space Vines", /datum/event/spacevine, 20, list(ASSIGNMENT_ENGINEER = 15), 1),
new /datum/event_meta(EVENT_LEVEL_MAJOR, "Viral Infection", /datum/event/viral_infection, -50, list(ASSIGNMENT_MEDICAL = 25), 1),
+34
View File
@@ -4039,6 +4039,40 @@
/obj/item/weapon/reagent_containers/food/snacks/rawsunflower/Initialize()
. = ..()
/obj/item/weapon/reagent_containers/food/snacks/frostbelle
name = "frostbelle bud"
desc = "A frostbelle flower from Sif. Its petals shimmer with an inner light."
icon = 'icons/obj/food_ingredients.dmi'
icon_state = "frostbelle"
bitesize = 1
nutriment_amt = 1
nutriment_desc = list("another world" = 2)
catalogue_data = list(/datum/category_item/catalogue/flora/frostbelle)
filling_color = "#5dadcf"
/obj/item/weapon/reagent_containers/food/snacks/frostbelle/Initialize()
. = ..()
set_light(1, 1, "#5dadcf")
reagents.add_reagent("oxycodone", 1)
reagents.add_reagent("sifsap", 5)
reagents.add_reagent("space_drugs", 5)
/obj/item/weapon/reagent_containers/food/snacks/bellefritter
name = "frostbelle fritters"
desc = "Frostbelles, prepared traditionally."
icon = 'icons/obj/food_syn.dmi'
icon_state = "bellefritter"
filling_color = "#5dadcf"
center_of_mass = list("x"=16, "y"=12)
do_coating_prefix = 0
/obj/item/weapon/reagent_containers/food/snacks/bellefritter/Initialize()
. = ..()
reagents.add_reagent("batter", 10)
reagents.add_reagent("sugar", 5)
bitesize = 2
/obj/item/weapon/reagent_containers/food/snacks/roastedsunflower
name = "sunflower seeds"
desc = "Sunflower seeds!"
+58 -1
View File
@@ -191,4 +191,61 @@
/obj/item/weapon/reagent_containers/food/snacks/greentealeaf/Initialize()
..()
reagents.add_reagent("tealeavesgreen", 6)
bitesize = 1
bitesize = 1
/obj/item/weapon/reagent_containers/food/snacks/butterscotch
name = "Butterscotch"
desc = "A sweet, golden-brown liquid, usually used as part of confectionary. Just a spoonful wouldn't hurt, right?"
icon = 'icons/obj/food_ch.dmi'
icon_state = "butterscotch" //Sprite by Dinnel
nutriment_amt = 1
nutriment_desc = list("sickly sweet deliciousness" = 1)
/obj/item/weapon/reagent_containers/food/snacks/butterscotch/Initialize()
..()
bitesize = 1
/obj/item/weapon/reagent_containers/food/snacks/slicable/buttspie
name = "Butterscotch-Cinnamon Pie"
desc = "A delightfully caramel-coloured filling in a crispy pie base, dotted with sprays of cream."
icon = 'icons/obj/food_ch.dmi'
icon_state = "butts_pie" //Sprite by Dinnel
slice_path = /obj/item/weapon/reagent_containers/food/snacks/slice/buttspie
slices_num = 6
nutriment_amt = 12
nutriment_desc = list("a warm, buttery sweetness that reminds you of home" = 5)
center_of_mass = list("x"=16, "y"=9)
/obj/item/weapon/reagent_containers/food/snacks/slicable/buttspie/Initialize()
..()
bitesize = 4
/obj/item/weapon/reagent_containers/food/snacks/slice/buttspie //TODO: Fix the numbers.
name = "Slice of Butterscotch-Cinnamon Pie"
desc = "A slice of pie, filled with delightfully caramel-coloured filling. There a spray of cream on top."
icon = 'icons/obj/food_ch.dmi'
icon_state = "butts_pie_slice" //Sprite by Dinnel
trash = /obj/item/trash/plate
whole_path = /obj/item/weapon/reagent_containers/food/snacks/slicable/buttspie
/obj/item/weapon/reagent_containers/food/snacks/slice/buttspie/Initialize()
..()
bitesize = 2
/obj/item/weapon/reagent_containers/food/snacks/spicy_boys //These are off-brand red hots/atomic fireballs
name = "Spicy Boys"
desc = "Spicy little candy rounds for very naughty individuals."
icon = 'icons/obj/food_ch.dmi'
icon_state = "spicy_boys" //Sprite by Dinnel
nutriment_amt = 1 //todo - change numbers
nutriment_desc = list("a sweet, candy-like spiciness." = 2) //WIP flavour??
/obj/item/weapon/reagent_containers/food/snacks/cinnamonroll
name = "cinnamon roll"
desc = "A precious little cinnamon roll, just begging to be eaten."
icon = 'icons/obj/food_ch.dmi'
icon_state = "cinnamon_roll" //Sprite by Dinnel
nutriment_amt = 1 //Todo - Change numbers.
nutriment_desc = list("a precious sweetness that needs protecting" = 2) //This is a WIP flavour, Could keep it if you don't mind the "gotta protect the precious cinnamon roll" joke
//TODO: Maybe butterscotch candies?
+21 -16
View File
@@ -188,18 +188,13 @@
update_icon()
var/slab_name = occupant.name
var/slab_count = 3
var/slab_type = /obj/item/weapon/reagent_containers/food/snacks/meat
var/slab_count = 2 + occupant.meat_amount
var/slab_type = occupant.meat_type ? occupant.meat_type : /obj/item/weapon/reagent_containers/food/snacks/meat
var/slab_nutrition = src.occupant.nutrition / 15
// Some mobs have specific meat item types.
if(istype(src.occupant,/mob/living/simple_mob))
var/mob/living/simple_mob/critter = src.occupant
if(critter.meat_amount)
slab_count = critter.meat_amount
if(critter.meat_type)
slab_type = critter.meat_type
else if(istype(src.occupant,/mob/living/carbon/human))
var/list/byproducts = occupant?.butchery_loot?.Copy()
if(istype(src.occupant,/mob/living/carbon/human))
var/mob/living/carbon/human/H = occupant
slab_name = src.occupant.real_name
slab_type = H.isSynthetic() ? /obj/item/stack/material/steel : H.species.meat_type
@@ -209,7 +204,8 @@
slab_nutrition *= 0.5
slab_nutrition /= slab_count
for(var/i=1 to slab_count)
while(slab_count)
slab_count--
var/obj/item/weapon/reagent_containers/food/snacks/meat/new_meat = new slab_type(src, rand(3,8))
if(istype(new_meat))
new_meat.name = "[slab_name] [new_meat.name]"
@@ -222,17 +218,26 @@
src.occupant.ghostize()
spawn(gib_time)
operating = 0
occupant.gib()
occupant = null
playsound(src, 'sound/effects/splat.ogg', 50, 1)
operating = 0
if(LAZYLEN(byproducts))
for(var/path in byproducts)
while(byproducts[path])
if(prob(min(90,30 * byproducts[path])))
new path(src)
byproducts[path] -= 1
for (var/obj/thing in contents)
// There's a chance that the gibber will fail to destroy some evidence.
// There's a chance that the gibber will fail to destroy or butcher some evidence.
if(istype(thing,/obj/item/organ) && prob(80))
qdel(thing)
var/obj/item/organ/OR = thing
if(OR.can_butcher(src))
OR.butcher(src, null, src) // Butcher it, and add it to our list of things to launch.
else
qdel(thing)
continue
thing.forceMove(get_turf(thing)) // Drop it onto the turf for throwing.
thing.throw_at(get_edge_target_turf(src,gib_throw_dir),rand(0,3),emagged ? 100 : 50) // Being pelted with bits of meat and bone would hurt.
+15
View File
@@ -137,6 +137,10 @@
var/obj/item/weapon/reagent_containers/food/snacks/S = O
if (S.dried_type)
return 1
if(istype(O, /obj/item/stack/wetleather))
return 1
return 0
/obj/machinery/smartfridge/drying_rack/process()
@@ -180,6 +184,17 @@
new D(get_turf(src))
qdel(S)
return
for(var/obj/item/stack/wetleather/WL in I.instances)
if(!WL.wetness)
if(WL.amount == 1)
WL.forceMove(get_turf(src))
I.instances -= WL
WL.dry()
break
WL.wetness = max(0, WL.wetness - rand(1, 3))
return
/obj/machinery/smartfridge/process()
+6 -1
View File
@@ -27,6 +27,11 @@
reagent_mix = RECIPE_REAGENT_REPLACE //Simplify end product
result = /obj/item/weapon/reagent_containers/food/snacks/risottoballs
/datum/recipe/bellefritter
appliance = FRYER
reagents = list("sugar" = 5, "batter" = 10)
items = list(/obj/item/weapon/reagent_containers/food/snacks/frostbelle)
result = /obj/item/weapon/reagent_containers/food/snacks/bellefritter
//Meaty Recipes
//====================
@@ -93,7 +98,7 @@
)
result = /obj/item/weapon/reagent_containers/food/snacks/donut/jelly
result_quantity = 2
/datum/recipe/jellydonut/poisonberry
reagents = list("poisonberryjuice" = 5, "sugar" = 5)
items = list(
@@ -97,3 +97,12 @@
/obj/item/weapon/reagent_containers/food/snacks/steamrolltealeaf
)
result = /obj/item/weapon/reagent_containers/food/snacks/greentealeaf
/datum/recipe/butterscotch
reagents = list("sugar" = 10, "cream" = 5)
reagent_mix = RECIPE_REAGENT_REPLACE //No actual reagents since it's meant to be a cooking item
items = list(
/obj/item/weapon/reagent_containers/food/snacks/spreads/butter
)
result = /obj/item/weapon/reagent_containers/food/snacks/butterscotch
result_quantity = 2
+23
View File
@@ -0,0 +1,23 @@
/datum/recipe/buttspie
appliance = OVEN
reagents = list("cinnamonpowder" = 10)
items = list(
/obj/item/weapon/reagent_containers/food/snacks/butterscotch,
/obj/item/weapon/reagent_containers/food/snacks/sliceable/flatdough
)
result = /obj/item/weapon/reagent_containers/food/snacks/slicable/buttspie
/datum/recipe/cinnamon_roll
appliance = OVEN
reagents = list("cinnamonpowder" = 5, "sugar" = 10)
items = list(
/obj/item/weapon/reagent_containers/food/snacks/dough,
/obj/item/weapon/reagent_containers/food/snacks/spreads/butter
)
result = /obj/item/weapon/reagent_containers/food/snacks/cinnamonroll
/datum/recipe/spicy_boys
appliance = OVEN
reagents = list("cinnamonpowder" = 5, "sugar" = 10, "cornoil" = 10)
result = /obj/item/weapon/reagent_containers/food/snacks/spicy_boys
result_quantity = 6
+20 -1
View File
@@ -200,4 +200,23 @@
set_trait(TRAIT_PLANT_ICON,"alien4") //spooky pods
set_trait(TRAIT_IDEAL_HEAT, 283)
set_trait(TRAIT_NUTRIENT_CONSUMPTION, 0)
set_trait(TRAIT_WATER_CONSUMPTION, 0)
set_trait(TRAIT_WATER_CONSUMPTION, 0)
/datum/seed/cinnamon //WIP - I have no idea what I'm doing with growables in code right now.
name = "cinnamon"
seed_name = "cinnamon"
display_name = "cinnamon tree"
chems = list("cinnamonpowder" = list(5,25))
mutants = null
kitchen_tag = "cinnamon"
/datum/seed/cinnamon/New()
..()
set_trait(TRAIT_HARVEST_REPEAT,1)
set_trait(TRAIT_MATURATION,6)
set_trait(TRAIT_PRODUCTION,6)
set_trait(TRAIT_YIELD,5)
set_trait(TRAIT_POTENCY,10)
set_trait(TRAIT_PRODUCT_ICON, "stalk")
set_trait(TRAIT_PRODUCT_COLOUR, "#FF9A85")
set_trait(TRAIT_PLANT_ICON,"tree2")
+10 -6
View File
@@ -1,6 +1,10 @@
/obj/item/seeds/teaseed
seed_type = "tea"
/obj/item/seeds/pitcherseed
seed_type = "pitcher plant"
/obj/item/seeds/teaseed
seed_type = "tea"
/obj/item/seeds/cinnamon
seed_type = "cinnamon"
/obj/item/seeds/pitcherseed
seed_type = "pitcher plant"
@@ -77,12 +77,16 @@
update_lighting()
/obj/item/integrated_circuit/output/light/proc/update_lighting()
if(light_toggled)
if(assembly)
assembly.set_light(l_range = light_brightness, l_power = light_brightness, l_color = light_rgb)
else
if(assembly)
assembly.set_light(0)
//CHOMPEdit Begin
if(assembly)
var/atom/light_source = assembly
if(istype(assembly,/obj/item/device/electronic_assembly/clothing))
light_source = assembly.loc
if(light_toggled)
light_source.set_light(l_range = light_brightness, l_power = light_brightness, l_color = light_rgb)
else
light_source.set_light(0)
//CHOMPEdit End
power_draw_idle = light_toggled ? light_brightness * light_brightness : 0 // Should be the same draw as regular lights.
/obj/item/integrated_circuit/output/light/power_fail() // Turns off the flashlight if there's no power left.
@@ -140,6 +140,7 @@
recipes += new/datum/stack_recipe("plastic net", /obj/item/weapon/material/fishing_net, 25, time = 1 MINUTE, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("plastic fishtank", /obj/item/glass_jar/fish/plastic, 2, time = 30 SECONDS)
recipes += new/datum/stack_recipe("reagent tubing", /obj/item/stack/hose, 1, 4, 20, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("Feeder", /obj/machinery/feeder, 4, time = 20, one_per_turf = 1, on_floor = 1) //CHOMP Addition
/datum/material/wood/generate_recipes()
..()
@@ -248,3 +249,24 @@
recipes += new/datum/stack_recipe("[display_name] net", /obj/item/weapon/material/fishing_net, 10, time = 5 SECONDS, supplied_material = "[name]", pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("[display_name] membrane", /obj/effect/alien/resin/membrane, 1, time = 2 SECONDS, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("[display_name] node", /obj/effect/alien/weeds/node, 1, time = 4 SECONDS)
/datum/material/leather/generate_recipes()
recipes = list()
recipes += new/datum/stack_recipe("bedsheet", /obj/item/weapon/bedsheet, 10, time = 30 SECONDS, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("uniform", /obj/item/clothing/under/color/white, 8, time = 15 SECONDS, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("foot wraps", /obj/item/clothing/shoes/footwraps, 2, time = 5 SECONDS, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("gloves", /obj/item/clothing/gloves/white, 2, time = 5 SECONDS, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("wig", /obj/item/clothing/head/powdered_wig, 4, time = 10 SECONDS, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("philosopher's wig", /obj/item/clothing/head/philosopher_wig, 50, time = 2 MINUTES, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("taqiyah", /obj/item/clothing/head/taqiyah, 3, time = 6 SECONDS, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("turban", /obj/item/clothing/head/turban, 3, time = 6 SECONDS, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("hijab", /obj/item/clothing/head/hijab, 3, time = 6 SECONDS, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("kippa", /obj/item/clothing/head/kippa, 3, time = 6 SECONDS, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("scarf", /obj/item/clothing/accessory/scarf/white, 4, time = 5 SECONDS, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("baggy pants", /obj/item/clothing/under/pants/baggy/white, 8, time = 10 SECONDS, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("belt pouch", /obj/item/weapon/storage/belt/fannypack/white, 25, time = 1 MINUTE, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("crude [display_name] bandage", /obj/item/stack/medical/crude_pack, 1, time = 2 SECONDS, pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("[display_name] net", /obj/item/weapon/material/fishing_net, 10, time = 5 SECONDS, supplied_material = "[name]", pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("[display_name] ring", /obj/item/clothing/gloves/ring/material, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("[display_name] bracelet", /obj/item/clothing/accessory/bracelet/material, 1, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
recipes += new/datum/stack_recipe("[display_name] armor plate", /obj/item/weapon/material/armor_plating, 1, time = 20, on_floor = 1, supplied_material = "[name]", pass_stack_color = TRUE)
+12 -1
View File
@@ -444,7 +444,18 @@
name = "leather"
desc = "The by-product of mob grinding."
icon_state = "sheet-leather"
default_type = "leather"
default_type = MAT_LEATHER
no_variants = FALSE
pass_color = TRUE
strict_color_stacking = TRUE
drop_sound = 'sound/items/drop/leather.ogg'
pickup_sound = 'sound/items/pickup/leather.ogg'
/obj/item/stack/material/chitin
name = "chitin"
desc = "The by-product of mob grinding."
icon_state = "chitin"
default_type = MAT_CHITIN
no_variants = FALSE
pass_color = TRUE
strict_color_stacking = TRUE
+20 -3
View File
@@ -922,7 +922,7 @@ var/list/name_to_material
sheet_singular_name = null
sheet_plural_name = "pile"
pass_stack_colors = TRUE
supply_conversion_value = 3 //YW Adds: logs worth points
supply_conversion_value = 1
/datum/material/wood/log/sif
name = MAT_SIFLOG
@@ -1008,6 +1008,7 @@ var/list/name_to_material
flags = MATERIAL_PADDING
conductive = 0
pass_stack_colors = TRUE
supply_conversion_value = 2
/datum/material/cult
name = "cult"
@@ -1033,16 +1034,32 @@ var/list/name_to_material
/datum/material/cult/reinf/place_dismantled_product(var/turf/target)
new /obj/effect/decal/remains/human(target)
/datum/material/chitin
name = MAT_CHITIN
icon_colour = "#8d6653"
stack_type = /obj/item/stack/material/chitin
stack_origin_tech = list(TECH_MATERIAL = 3, TECH_BIO = 4)
icon_base = "solid"
icon_reinf = "reinf_mesh"
integrity = 60
ignition_point = T0C+400
melting_point = T0C+500
protectiveness = 25
conductive = 0
supply_conversion_value = 4
//TODO PLACEHOLDERS:
/datum/material/leather
name = "leather"
name = MAT_LEATHER
icon_colour = "#5C4831"
stack_origin_tech = list(TECH_MATERIAL = 2)
stack_type = /obj/item/stack/material/leather
stack_origin_tech = list(TECH_MATERIAL = 2, TECH_BIO = 2)
flags = MATERIAL_PADDING
ignition_point = T0C+300
melting_point = T0C+300
protectiveness = 3 // 13%
conductive = 0
supply_conversion_value = 3
//CHOMPstation Removal Start: Moved to materials_ch and changed to allow for material var
/*
+66
View File
@@ -0,0 +1,66 @@
/mob/living
var/meat_amount = 0 // How much meat to drop from this mob when butchered
var/obj/meat_type // The meat object to drop
var/gib_on_butchery = FALSE
var/list/butchery_loot // Associated list, path = number.
// Harvest an animal's delicious byproducts
/mob/living/proc/harvest(var/mob/user, var/obj/item/I)
if(meat_type && meat_amount>0 && (stat == DEAD))
while(meat_amount > 0 && do_after(user, 0.5 SECONDS * (mob_size / 10), src))
var/obj/item/meat = new meat_type(get_turf(src))
meat.name = "[src.name] [meat.name]"
new /obj/effect/decal/cleanable/blood/splatter(get_turf(src))
meat_amount--
if(!meat_amount)
handle_butcher(user, I)
/mob/living/proc/can_butcher(var/mob/user, var/obj/item/I) // Override for special butchering checks.
if(((meat_type && meat_amount) || LAZYLEN(butchery_loot)) && stat == DEAD)
return TRUE
return FALSE
/mob/living/proc/handle_butcher(var/mob/user, var/obj/item/I)
if(!user || do_after(user, 2 SECONDS * mob_size / 10, src))
if(LAZYLEN(butchery_loot))
if(LAZYLEN(butchery_loot))
for(var/path in butchery_loot)
while(butchery_loot[path])
butchery_loot[path] -= 1
var/obj/item/loot = new path(get_turf(src))
loot.pixel_x = rand(-12, 12)
loot.pixel_y = rand(-12, 12)
butchery_loot.Cut()
butchery_loot = null
if(LAZYLEN(organs))
organs_by_name.Cut()
for(var/obj/item/organ/OR in organs)
OR.removed()
organs -= OR
if(LAZYLEN(internal_organs))
internal_organs_by_name.Cut()
for(var/obj/item/organ/OR in internal_organs)
OR.removed()
internal_organs -= OR
if(!ckey)
if(issmall(src))
user?.visible_message("<span class='danger'>[user] chops up \the [src]!</span>")
new /obj/effect/decal/cleanable/blood/splatter(get_turf(src))
if(gib_on_butchery)
qdel(src)
else
user?.visible_message("<span class='danger'>[user] butchers \the [src] messily!</span>")
if(gib_on_butchery)
gib()
@@ -1,4 +1,4 @@
/mob/living/carbon/
/mob/living/carbon
gender = MALE
var/datum/species/species //Contains icon generation and language information, set during New().
var/list/stomach_contents = list()
@@ -177,7 +177,7 @@
message = "makes a weird noise!"
playsound(src.loc, 'sound/misc/ough.ogg', 50, 1, -1, preference = /datum/client_preference/emote_noises)
m_type = 2 //End of Yawn Addtion
*/
*/
if ("howl") // YW add begins
m_type = 2
message = "lets out a howl."
@@ -269,7 +269,7 @@
set desc = "Switch tail layer on top."
tail_alt = !tail_alt
update_tail_showing()
/mob/living/carbon/human/verb/hide_wings_vr()
set name = "Show/Hide wings"
set category = "IC"
@@ -282,4 +282,12 @@
else
message = "hides their wings."
visible_message("[src] [message]")
// Chomp Edit Start
/mob/living/carbon/human/verb/hide_nutrition_vr()
set name = "Show/Hide Nutrition Levels"
set category = "IC"
set desc = "Allow other player to see your current nutrition level or not."
nutrition_hidden = !nutrition_hidden
to_chat(src, "Players will [nutrition_hidden ? "no longer" : "now"] see your nutrition levels.")
// Chomp Edit End
@@ -68,6 +68,8 @@
/mob/living/carbon/human/proc/examine_nutrition()
if(!show_pudge()) //Some clothing or equipment can hide this.
return ""
if(nutrition_hidden) // Chomp Edit
return ""
var/message = ""
var/nutrition_examine = round(nutrition)
var/t_He = "It" //capitalised for use at the start of each line.
@@ -1,3 +1,6 @@
/mob/living/carbon/human
var/datum/unarmed_attack/default_attack
/mob/living/carbon/human/proc/get_unarmed_attack(var/mob/living/carbon/human/target, var/hit_zone)
// VOREStation Edit - Begin
if(nif && nif.flag_check(NIF_C_HARDCLAWS,NIF_FLAGS_COMBAT)){return unarmed_hardclaws}
@@ -16,6 +19,12 @@
if(soft_type)
return soft_type
return G.special_attack
if(src.default_attack && src.default_attack.is_usable(src, target, hit_zone))
if(pulling_punches)
var/datum/unarmed_attack/soft_type = src.default_attack.get_sparring_variant()
if(soft_type)
return soft_type
return src.default_attack
for(var/datum/unarmed_attack/u_attack in species.unarmed_attacks)
if(u_attack.is_usable(src, target, hit_zone))
if(pulling_punches)
@@ -434,3 +443,37 @@
user.visible_message("\The [user] stops applying pressure to [src]'s [organ.name]!", "You stop applying pressure to [src]'s [organ.name]!")
return TRUE
/mob/living/carbon/human/verb/check_attacks()
set name = "Check Attacks"
set category = "IC"
set src = usr
var/dat = "<b><font size = 5>Known Attacks</font></b><br/><br/>"
if(default_attack)
dat += "Current default attack: [default_attack.attack_name] - <a href='byond://?src=\ref[src];default_attk=reset_attk'>reset</a><br/><br/>"
for(var/datum/unarmed_attack/u_attack in species.unarmed_attacks)
if(u_attack == default_attack)
dat += "<b>Primarily [u_attack.attack_name]</b> - default - <a href='byond://?src=\ref[src];default_attk=reset_attk'>reset</a><br/><br/><br/>"
else
dat += "<b>Primarily [u_attack.attack_name]</b> - <a href='byond://?src=\ref[src];default_attk=\ref[u_attack]'>set default</a><br/><br/><br/>"
src << browse(dat, "window=checkattack")
/mob/living/carbon/human/Topic(href, href_list)
if(href_list["default_attk"])
if(href_list["default_attk"] == "reset_attk")
set_default_attack(null)
else
var/datum/unarmed_attack/u_attack = locate(href_list["default_attk"])
if(u_attack && (u_attack in species.unarmed_attacks))
set_default_attack(u_attack)
check_attacks()
return 1
else
return ..()
/mob/living/carbon/human/proc/set_default_attack(var/datum/unarmed_attack/u_attack)
default_attack = u_attack
@@ -288,7 +288,7 @@
oxyloss = 0
else
..()
/mob/living/carbon/human/adjustHalLoss(var/amount)
if(species.flags & NO_PAIN)
halloss = 0
@@ -439,13 +439,14 @@ This function restores all organs.
return 0
return
/*
/mob/living/carbon/human/proc/get_organ(var/zone)
if(!zone)
zone = BP_TORSO
else if (zone in list( O_EYES, O_MOUTH ))
zone = BP_HEAD
return organs_by_name[zone]
*/
/mob/living/carbon/human/apply_damage(var/damage = 0, var/damagetype = BRUTE, var/def_zone = null, var/blocked = 0, var/soaked = 0, var/sharp = 0, var/edge = 0, var/obj/used_weapon = null)
if(Debug2)
@@ -44,7 +44,7 @@
var/age = 30 //Player's age (pure fluff)
var/b_type = "A+" //Player's bloodtype
var/datum/robolimb/synthetic //If they are a synthetic (aka synthetic torso)
var/datum/robolimb/synthetic //If they are a synthetic (aka synthetic torso). Also holds the datum for the type of robolimb.
var/list/all_underwear = list()
var/list/all_underwear_metadata = list()
@@ -85,7 +85,6 @@
var/special_voice = "" // For changing our voice. Used by a symptom.
var/last_dam = -1 //Used for determining if we need to process all organs or just some or even none.
var/list/bad_external_organs = list()// organs we check until they are good.
var/xylophone = 0 //For the spoooooooky xylophone cooldown
@@ -118,3 +117,4 @@
var/obj/machinery/machine_visual //machine that is currently applying visual effects to this mob. Only used for camera monitors currently.
inventory_panel_type = /datum/inventory_panel/human
butchery_loot = list(/obj/item/stack/animalhide/human = 1)
@@ -10,6 +10,7 @@
var/ability_flags = 0 //Shadekin abilities/potentially other species-based?
var/sensorpref = 5 //Suit sensor loadout pref
var/wings_hidden = FALSE
var/nutrition_hidden = FALSE // Chomp Edit
/mob/living/carbon/human/proc/shadekin_get_energy()
var/datum/species/shadekin/SK = species
@@ -5,6 +5,7 @@
update_icons_body() //Body handles eyes
update_eyes() //For floating eyes only
/*
/mob/living/carbon/var/list/internal_organs = list()
/mob/living/carbon/human/var/list/organs = list()
/mob/living/carbon/human/var/list/organs_by_name = list() // map organ names to organs
@@ -13,6 +14,7 @@
/mob/living/carbon/human/proc/get_bodypart_name(var/zone)
var/obj/item/organ/external/E = get_organ(zone)
if(E) . = E.name
*/
/mob/living/carbon/human/proc/recheck_bad_external_organs()
var/damage_this_tick = getToxLoss()
@@ -1,4 +1,5 @@
/datum/unarmed_attack/bite/sharp //eye teeth
attack_name = "sharp bite"
attack_verb = list("bit", "chomped on")
attack_sound = 'sound/weapons/bite.ogg'
shredding = 0
@@ -6,12 +7,14 @@
edge = 1
/datum/unarmed_attack/diona
attack_name = "tendrils"
attack_verb = list("lashed", "bludgeoned")
attack_noun = list("tendril")
eye_attack_text = "a tendril"
eye_attack_text_victim = "a tendril"
/datum/unarmed_attack/claws
attack_name = "claws"
attack_verb = list("scratched", "clawed", "slashed")
attack_noun = list("claws")
eye_attack_text = "claws"
@@ -54,6 +57,7 @@
if(5) user.visible_message("<span class='danger'>[user] tears [T.his] [pick(attack_noun)] [pick("deep into", "into", "across")] [target]'s [affecting.name]!</span>")
/datum/unarmed_attack/claws/strong
attack_name = "strong claws"
attack_verb = list("slashed")
damage = 5
shredding = 1
@@ -67,6 +71,7 @@
damage = 15
/datum/unarmed_attack/bite/strong
attack_name = "strong bite"
attack_verb = list("mauled")
damage = 8
shredding = 1
@@ -75,6 +80,7 @@
damage = 10
/datum/unarmed_attack/slime_glomp
attack_name = "glomp"
attack_verb = list("glomped")
attack_noun = list("body")
damage = 2
@@ -84,6 +90,7 @@
user.apply_stored_shock_to(target)
/datum/unarmed_attack/stomp/weak
attack_name = "weak stomp"
attack_verb = list("jumped on")
/datum/unarmed_attack/stomp/weak/get_unarmed_damage()
@@ -142,8 +142,8 @@
)
unarmed_types = list(
/datum/unarmed_attack/bite/sharp,
/datum/unarmed_attack/claws,
/datum/unarmed_attack/bite/sharp,
/datum/unarmed_attack/stomp/weak
)
@@ -30,11 +30,10 @@
excludes = list(/datum/trait/lonely)
/datum/trait/lonely/proc/check_mob_company(var/mob/living/carbon/human/H,var/mob/living/M)
if(only_people && !istype(M, /mob/living/carbon) && !istype(M, /mob/living/silicon/robot))
return 0
if(M == H || M.stat == DEAD || M.invisibility > H.see_invisible)
return 0
if(only_people && !M.ckey)
var/social_check = only_people && !istype(M, /mob/living/carbon) && !istype(M, /mob/living/silicon/robot)
var/self_dead_invisible_check = M == H || M.stat == DEAD || M.invisibility > H.see_invisible
var/ckey_check = only_people && !M.ckey
if(social_check || self_dead_invisible_check || ckey_check)
return 0
if(M.faction == "neutral" || M.faction == H.faction)
if(H.loneliness_stage > 0)
@@ -71,9 +70,13 @@
H.loneliness_stage -= 4
return
// Check for company.
for(var/mob/living/M in viewers(H))
for(var/mob/living/M in H.contents)
if(istype(M) && check_mob_company(H,M))
return
for(var/mob/living/M in viewers(get_turf(H)))
if(check_mob_company(H,M))
return
//Check to see if there's anyone in our belly
if(H.vore_organs)
for(var/obj/belly/B in H.vore_organs)
for(var/mob/living/content in B.contents)
@@ -34,4 +34,4 @@
desc = "Your body is able to produce nutrition from being in light."
cost = 3
var_changes = list("photosynthesizing" = TRUE)
not_for_synths = 1 //Synths don't use nutrition.
not_for_synths = 0 //Synths actually use nutrition, just with a fancy covering.
@@ -2,6 +2,7 @@ var/global/list/sparring_attack_cache = list()
//Species unarmed attacks
/datum/unarmed_attack
var/attack_name = "fist"
var/attack_verb = list("attack") // Empty hand hurt intent verb.
var/attack_noun = list("fist")
var/damage = 0 // Extra empty hand attack damage.
@@ -109,6 +110,7 @@ var/global/list/sparring_attack_cache = list()
return FALSE //return true if the unarmed override prevents further attacks
/datum/unarmed_attack/bite
attack_name = "bite"
attack_verb = list("bit")
attack_sound = 'sound/weapons/bite.ogg'
shredding = 0
@@ -127,6 +129,7 @@ var/global/list/sparring_attack_cache = list()
return TRUE
/datum/unarmed_attack/punch
attack_name = "punch"
attack_verb = list("punched")
attack_noun = list("fist")
eye_attack_text = "fingers"
@@ -181,6 +184,7 @@ var/global/list/sparring_attack_cache = list()
user.visible_message("<span class='danger'>[user] [pick("punched", "threw a punch against", "struck", "slammed [TU.his] [pick(attack_noun)] into")] [target]'s [organ]!</span>") //why do we have a separate set of verbs for lying targets?
/datum/unarmed_attack/kick
attack_name = "kick"
attack_verb = list("kicked", "kicked", "kicked", "kneed")
attack_noun = list("kick", "kick", "kick", "knee strike")
attack_sound = "swing_hit"
@@ -224,6 +228,7 @@ var/global/list/sparring_attack_cache = list()
if(5) user.visible_message("<span class='danger'>[user] landed a strong [pick(attack_noun)] against [target]'s [organ]!</span>")
/datum/unarmed_attack/stomp
attack_name = "stomp"
attack_verb = null
attack_noun = list("stomp")
attack_sound = "swing_hit"
@@ -269,6 +274,7 @@ var/global/list/sparring_attack_cache = list()
if(5) user.visible_message("<span class='danger'>[pick("[user] landed a powerful stomp on", "[user] stomped down hard on", "[user] slammed [TU.his] [shoes ? copytext(shoes.name, 1, -1) : "foot"] down hard onto")] [target]'s [organ]!</span>") //Devastated lol. No. We want to say that the stomp was powerful or forceful, not that it /wrought devastation/
/datum/unarmed_attack/light_strike
attack_name = "light hit"
attack_noun = list("tap","light strike")
attack_verb = list("tapped", "lightly struck")
damage = 3
+23 -1
View File
@@ -31,9 +31,25 @@
nest = null
if(buckled)
buckled.unbuckle_mob(src, TRUE)
qdel(selected_image)
QDEL_NULL(vorePanel) //VOREStation Add
QDEL_LIST_NULL(vore_organs) //VOREStation Add
if(LAZYLEN(organs))
organs_by_name.Cut()
while(organs.len)
var/obj/item/OR = organs[1]
organs -= OR
qdel(OR)
if(LAZYLEN(internal_organs))
internal_organs_by_name.Cut()
while(internal_organs.len)
var/obj/item/OR = internal_organs[1]
internal_organs -= OR
qdel(OR)
return ..()
//mob verbs are faster than object verbs. See mob/verb/examine.
@@ -924,6 +940,12 @@ default behaviour is:
/mob/living/Moved(var/atom/oldloc, direct, forced, movetime)
. = ..()
handle_footstep(loc)
// Begin VOREstation edit
if(is_shifted)
is_shifted = FALSE
pixel_x = 0
pixel_y = 0
// End VOREstation edit
if(pulling) // we were pulling a thing and didn't lose it during our move.
var/pull_dir = get_dir(src, pulling)
@@ -1462,4 +1484,4 @@ default behaviour is:
// Tries to turn off things that let you see through walls, like mesons.
// Each mob does vision a bit differently so this is just for inheritence and also so overrided procs can make the vision apply instantly if they call `..()`.
/mob/living/proc/disable_spoiler_vision()
handle_vision()
handle_vision()
+1 -1
View File
@@ -74,4 +74,4 @@
var/image/selected_image = null // Used for buildmode AI control stuff.
var/inventory_panel_type = /datum/inventory_panel
var/datum/inventory_panel/inventory_panel
var/datum/inventory_panel/inventory_panel
+28
View File
@@ -0,0 +1,28 @@
/mob/living
var/list/internal_organs = list()
var/list/organs = list()
var/list/organs_by_name = list() // map organ names to organs
var/list/internal_organs_by_name = list() // so internal organs have less ickiness too
var/list/bad_external_organs = list()// organs we check until they are good.
/mob/living/proc/get_bodypart_name(var/zone)
var/obj/item/organ/external/E = get_organ(zone)
if(E) . = E.name
/mob/living/proc/get_organ(var/zone)
if(!zone)
zone = BP_TORSO
else if (zone in list( O_EYES, O_MOUTH ))
zone = BP_HEAD
return organs_by_name[zone]
/mob/living/gib()
for(var/obj/item/organ/I in internal_organs)
I.removed()
if(isturf(I?.loc)) // Some organs qdel themselves or other things when removed
I.throw_at(get_edge_target_turf(src,pick(alldirs)),rand(1,3),30)
for(var/obj/item/organ/external/E in src.organs)
E.droplimb(0,DROPLIMB_EDGE,1)
..()
@@ -145,6 +145,7 @@
name = "MediHound hypospray"
desc = "An advanced chemical synthesizer and injection system utilizing carrier's reserves, designed for heavy-duty medical equipment."
charge_cost = 10
reagent_ids = list("inaprovaline", "dexalin", "bicaridine", "kelotane", "anti_toxin", "spaceacillin", "paracetamol")
var/datum/matter_synth/water = null
/obj/item/weapon/reagent_containers/borghypo/hound/process() //Recharges in smaller steps and uses the water reserves as well.
@@ -39,6 +39,7 @@
var/datum/matter_synth/water = null
var/digest_brute = 2
var/digest_burn = 3
var/digest_multiplier = 1
var/recycles = FALSE
var/medsensor = TRUE //Does belly sprite come with patient ok/dead light?
@@ -541,8 +542,8 @@
else
var/old_brute = T.getBruteLoss()
var/old_burn = T.getFireLoss()
T.adjustBruteLoss(digest_brute)
T.adjustFireLoss(digest_burn)
T.adjustBruteLoss(digest_brute * digest_multiplier)
T.adjustFireLoss(digest_burn * digest_multiplier)
var/actual_brute = T.getBruteLoss() - old_brute
var/actual_burn = T.getFireLoss() - old_burn
var/damage_gain = actual_brute + actual_burn
@@ -717,6 +718,7 @@
icon_state = "sleeperc"
injection_chems = list("glucose","inaprovaline","tricordrazine")
max_item_count = 1
/obj/item/device/dogborg/sleeper/command //Command borg belly // CH addition
name = "Bluespace Filing Belly"
desc = "A mounted bluespace storage unit for carrying paperwork"
@@ -726,4 +728,4 @@
recycles = FALSE
max_item_count = 25
#undef SLEEPER_INJECT_COST
#undef SLEEPER_INJECT_COST
@@ -71,6 +71,5 @@
/mob/living/simple_mob/proc/remove_eyes()
cut_overlay(eye_layer)
/mob/living/simple_mob/gib()
..(icon_gib,1,icon) // we need to specify where the gib animation is stored
..(icon_gib,1,icon) // we need to specify where the gib animation is stored
@@ -0,0 +1,8 @@
/mob/living/simple_mob
gib_on_butchery = TRUE
/mob/living/simple_mob/can_butcher(var/mob/user, var/obj/item/I) // Override for special butchering checks.
. = ..()
if(. && (!is_sharp(I) || !has_edge(I)))
return FALSE
@@ -68,9 +68,9 @@
else
var/datum/gender/T = gender_datums[src.get_visible_gender()]
to_chat(user, "<span class='notice'>\The [src] is dead, medical items won't bring [T.him] back to life.</span>") // the gender lookup is somewhat overkill, but it functions identically to the obsolete gender macros and future-proofs this code
if(meat_type && (stat == DEAD)) //if the animal has a meat, and if it is dead.
if(istype(O, /obj/item/weapon/material/knife))
harvest(user)
if(can_butcher(user, O)) //if the animal can be butchered, do so and return. It's likely to be gibbed.
harvest(user, O)
return
if(user.a_intent == I_HELP && harvest_tool && istype(O, harvest_tool) && stat != DEAD)
if(world.time > (harvest_recent + harvest_cooldown))
@@ -17,7 +17,7 @@
/mob/living/simple_mob/examine(mob/user)
. = ..()
if(user && harvest_tool && (get_dist(user, src) <= 3))
if(stat != DEAD && user && harvest_tool && (get_dist(user, src) <= 3))
. += "<span class='notice'>\The [src] can be [harvest_verb] with a [initial(harvest_tool.name)] every [round(harvest_cooldown, 0.1)] minutes.</span>"
var/time_to_harvest = (harvest_recent + harvest_cooldown) - world.time
if(time_to_harvest > 0)
+9 -1
View File
@@ -14,6 +14,8 @@
handle_special()
handle_guts()
return TRUE
@@ -94,7 +96,7 @@
throw_alert("oxy", /obj/screen/alert/too_much_oxy)
else
clear_alert("oxy")
if(min_tox && Environment.gas["phoron"] < min_tox)
atmos_unsuitable = 2
throw_alert("tox_in_air", /obj/screen/alert/not_enough_tox)
@@ -137,6 +139,12 @@
else
adjustOxyLoss(-unsuitable_atoms_damage)
/mob/living/simple_mob/proc/handle_guts()
for(var/obj/item/organ/OR in internal_organs)
OR.process()
for(var/obj/item/organ/OR in organs)
OR.process()
/mob/living/simple_mob/proc/handle_supernatural()
if(purge)
@@ -57,8 +57,6 @@
var/response_harm = "tries to hurt" // If clicked on harm intent
var/list/friends = list() // Mobs on this list wont get attacked regardless of faction status.
var/harm_intent_damage = 3 // How much an unarmed harm click does to this mob.
var/meat_amount = 0 // How much meat to drop from this mob when butchered
var/obj/meat_type // The meat object to drop
var/list/loot_list = list() // The list of lootable objects to drop, with "/path = prob%" structure
var/obj/item/weapon/card/id/myid// An ID card if they have one to give them access to stuff.
@@ -158,6 +156,10 @@
// don't process me if there's nobody around to see it
low_priority = TRUE
// Used for if the mob can drop limbs. Overrides species dmi.
var/limb_icon
// Used for if the mob can drop limbs. Overrides the icon cache key, so it doesn't keep remaking the icon needlessly.
var/limb_icon_key
/mob/living/simple_mob/Initialize()
verbs -= /mob/verb/observe
@@ -170,8 +172,31 @@
if(has_eye_glow)
add_eyes()
return ..()
if(LAZYLEN(organs))
for(var/path in organs)
if(ispath(path))
var/obj/item/organ/external/neworg = new path(src)
neworg.name = "[name] [neworg.name]"
neworg.meat_type = meat_type
if(limb_icon)
neworg.force_icon = limb_icon
neworg.force_icon_key = limb_icon_key
organs |= neworg
organs -= path
if(LAZYLEN(internal_organs))
for(var/path in internal_organs)
if(ispath(path))
var/obj/item/organ/neworg = new path(src)
neworg.name = "[name] [neworg.name]"
neworg.meat_type = meat_type
internal_organs |= neworg
internal_organs -= path
return ..()
/mob/living/simple_mob/Destroy()
default_language = null
@@ -190,7 +215,6 @@
update_icon()
..()
//Client attached
/mob/living/simple_mob/Login()
. = ..()
@@ -269,27 +293,6 @@
/mob/living/simple_mob/get_speech_ending(verb, var/ending)
return verb
// Harvest an animal's delicious byproducts
/mob/living/simple_mob/proc/harvest(var/mob/user, var/invisible)
var/actual_meat_amount = max(1,(meat_amount/2))
var/attacker_name = user.name
if(invisible)
attacker_name = "someone"
if(meat_type && actual_meat_amount>0 && (stat == DEAD))
for(var/i=0;i<actual_meat_amount;i++)
var/obj/item/meat = new meat_type(get_turf(src))
meat.name = "[src.name] [meat.name]"
if(issmall(src))
user.visible_message("<span class='danger'>[attacker_name] chops up \the [src]!</span>")
new/obj/effect/decal/cleanable/blood/splatter(get_turf(src))
qdel(src)
else
user.visible_message("<span class='danger'>[attacker_name] butchers \the [src] messily!</span>")
gib()
/mob/living/simple_mob/is_sentient()
return mob_class & MOB_CLASS_HUMANOID|MOB_CLASS_ANIMAL|MOB_CLASS_SLIME // Update this if needed.
@@ -6,4 +6,17 @@
response_disarm = "shoos"
response_harm = "hits"
ai_holder_type = /datum/ai_holder/simple_mob/melee
ai_holder_type = /datum/ai_holder/simple_mob/melee
internal_organs = list(\
/obj/item/organ/internal/brain,\
/obj/item/organ/internal/heart,\
/obj/item/organ/internal/liver,\
/obj/item/organ/internal/stomach,\
/obj/item/organ/internal/intestine,\
/obj/item/organ/internal/lungs\
)
butchery_loot = list(\
/obj/item/stack/animalhide = 3\
)
@@ -110,6 +110,10 @@
var/poison_chance = 10 // Chance for injection to occur.
var/poison_per_bite = 5 // Amount added per injection.
butchery_loot = list(\
/obj/item/stack/material/chitin = 1\
)
/mob/living/simple_mob/animal/giant_spider/apply_melee_effects(var/atom/A)
if(isliving(A))
var/mob/living/L = A
+301
View File
@@ -0,0 +1,301 @@
#define BULLET_AP_DIVISOR 200
#define AP_DIVISOR 4152
#define ARMOR_Y_INTERCEPT 0.2
#define ARMOR_SLOPE 0.017
#define PENETRATION_PROBABILITY_EXP_BASE 2
#define PENETRATION_PROBABILITY_EXP_MULT 30
#define BULLET_DEFLECTED_PAIN_DIVISOR 5000
#define BULLET_DEFLECTED_BULLET_DIVISOR 70
#define BULLET_DEFLECTED_MELEE_DIVISOR 280
#define BULLET_DEFLECTED_PAIN_EXPONENT 1.5
#define BULLET_DEFLECTED_BRUISE_SUBTRACT 5
GLOBAL_VAR_INIT(SKIN_LOSS_COEFFICIENT,16)
GLOBAL_VAR_INIT(ARMOR_LOSS_COEFFICIENT,150)
GLOBAL_VAR_INIT(ARMOR_LOSS_MIN_MULT,0.5)
GLOBAL_VAR_INIT(ARMOR_LOSS_MIN_ARMOR,20)
GLOBAL_VAR_INIT(INTERNAL_LOSS_COEFFICIENT,195)
#define ORGAN_LOSS_COEFFICIENT 350
#define HIT_VITAL_ORGAN_CHANCE 35
#define BONE_HIT_CHANCE_UNENCASED 45
#define BONE_HIT_CHANCE_ENCASED 80
GLOBAL_VAR_INIT(BONE_JOULES_PERHP_AVG,2)
GLOBAL_VAR_INIT(BONE_JOULES_PERHP_DEV,1)
GLOBAL_VAR_INIT(BONE_JOULES_MIN,100)
#define BONE_HP_AVG 25
GLOBAL_VAR_INIT(HOLLOW_POINT_VELLOSS_BONUS,2.35)
GLOBAL_VAR_INIT(HOLLOW_POINT_CONVERSION_EFF,1.15)
#define PROB_LEAVE_EARLY_FIRST 20
#define PROB_LEAVE_EARLY_SECOND 40
GLOBAL_VAR_INIT(ENERGY_DAMAGE_FLESH_FACTOR,0.03)
GLOBAL_VAR_INIT(ENERGY_DAMAGE_ORGAN_FACTOR,0.035)
#ifndef GAUSSIAN_RANDOM
#define GAUSSIAN_RANDOM(vars...) ((-2*log(rand()))**0.5 * cos(6.28318530718*rand()))
#endif
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////// CADYN'S BALLISTICS ////////////////////////////////////////////////////////////////////////// ORIGINAL FROM CHOMPSTATION ////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/mob/living/proc/handle_ballistics(var/obj/item/projectile/bullet/P, var/def_zone)
var/list/updated_organ_weight = list()
var/ballistic_armor = getarmor(def_zone, "bullet")
var/melee_armor = getarmor(def_zone, "melee")
var/obj/item/organ/external/hit_organ
var/mob/living/carbon/human/H = src
if(istype(H))
hit_organ = H.get_organ(def_zone)
for(var/ext_organ in ballistic_variables["organ_hit_weight"])
var/list/input = list()
var/obj/item/organ/external/ref_ext_organ = H.get_organ(ext_organ)
for(var/int_organ in ballistic_variables["organ_hit_weight"][ext_organ])
var/ref_int_organ = H.internal_organs_by_name[int_organ]
if(ref_ext_organ && ref_int_organ && (ref_int_organ in ref_ext_organ.internal_organs))
input[ref_int_organ] = ballistic_variables["organ_hit_weight"][ext_organ][int_organ]
if(input.len)
updated_organ_weight[ref_ext_organ] = input
//log_and_message_admins("Beginning handle_ballistics")
var/penetration_chance = armor_penetration_probability(ballistic_armor,P)
if(!prob(penetration_chance)) //Boo-hoo we got deflected. Do boring agony/bruises stuff.
//log_and_message_admins("Bullet deflected")
var/pain_hit = hit_organ ? "into your [hit_organ]" : "into you"
var/hurt_value = P.velocity * P.grains / (BULLET_DEFLECTED_PAIN_DIVISOR * (1 + ballistic_armor/BULLET_DEFLECTED_BULLET_DIVISOR + melee_armor/BULLET_DEFLECTED_MELEE_DIVISOR)) //Better armor spreads out the energy better.
var/hurt_value_pain = hurt_value ** BULLET_DEFLECTED_PAIN_EXPONENT
var/hurt_value_bruise = max(0,hurt_value-BULLET_DEFLECTED_BRUISE_SUBTRACT)
var/absorber = ballistic_armor ? "armor" : "body" //There is a super tiny chance that small rounds can get deflected without armor, so this is just incase.
to_chat(src,"<span class='warning'>You feel the energy of the bullet painfully transfered [pain_hit] as your [absorber] deflects it!</span>")
apply_damage(hurt_value_pain,HALLOSS,def_zone)
if(hurt_value_bruise)
apply_damage(hurt_value_bruise,BRUTE,def_zone)
P.sub_velocity(P.velocity)
return 2
else //Now the FUN begins
//log_and_message_admins("Bullet penetrated")
var/area_over_mass = P.diam * P.diam / P.grains
//Most of these calculations don't involve energies because I'm treating flesh and organic tissue as a fluid since it's squishy and stuff.
//Since drag is proportional to velocity, we can do things on an m*v basis instead of an mv^2 basis.
//Obviously bones are more solid, so we do actual energy calculations for that.
var/conversion_efficiency = P.hollow_point ? GLOB.HOLLOW_POINT_CONVERSION_EFF : 1
var/vel_loss_multiplier = P.hollow_point ? GLOB.HOLLOW_POINT_VELLOSS_BONUS : 1
var/energy_dumped_organic = 0
var/vel_lost_armor = ballistic_armor >= GLOB.ARMOR_LOSS_MIN_ARMOR ? GLOB.ARMOR_LOSS_COEFFICIENT * area_over_mass * ((1 + GLOB.ARMOR_LOSS_MIN_MULT) - penetration_chance/100) : 0
P.sub_velocity(vel_lost_armor)
var/energy_past = P.energy
var/internal_loss = vel_loss_multiplier * GLOB.INTERNAL_LOSS_COEFFICIENT * area_over_mass
var/vel_lost_skin = vel_loss_multiplier * GLOB.SKIN_LOSS_COEFFICIENT * area_over_mass
P.sub_velocity(vel_lost_skin + internal_loss)
energy_dumped_organic += (energy_past - P.energy)
if(prob(PROB_LEAVE_EARLY_FIRST) || !P.velocity)
energy_to_damage(energy_dumped_organic * conversion_efficiency,def_zone)
return 1
if(hit_organ)
//log_and_message_admins("organ_handle_ballistics called. hit_organ = [hit_organ], energy_dumped_organic = [energy_dumped_organic], internal_loss = [internal_loss], ballistic_armor = [ballistic_armor], P.velocity = [P.velocity], P.energy = [P.energy]")
return organ_handle_ballistics(P,hit_organ,energy_dumped_organic,internal_loss,ballistic_armor,updated_organ_weight)
else
//log_and_message_admins("general_handle_ballistics called.")
return general_handle_ballistics(P,def_zone,energy_dumped_organic,internal_loss,ballistic_armor)
/mob/living/proc/organ_handle_ballistics(var/obj/item/projectile/bullet/P,var/obj/item/organ/external/hit_organ,var/energy_dumped_organic,var/internal_loss,var/ballistic_armor,var/list/updated_organ_weight)
var/conversion_efficiency = P.hollow_point ? GLOB.HOLLOW_POINT_CONVERSION_EFF : 1
var/energy_past
var/area_over_mass = P.diam * P.diam / P.grains
var/bone_chance = BONE_HIT_CHANCE_UNENCASED
if(hit_organ.encased)
bone_chance = BONE_HIT_CHANCE_ENCASED
else
bone_chance = ballistic_variables["bone_chance_unencased"][hit_organ.organ_tag]
//log_and_message_admins("Bone hit chance is [bone_chance], organ is [hit_organ]")
if(prob(bone_chance))
var/energy_to_fracture = max(GLOB.BONE_JOULES_MIN, hit_organ.min_broken_damage * (GAUSSIAN_RANDOM()*GLOB.BONE_JOULES_PERHP_DEV + GLOB.BONE_JOULES_PERHP_AVG))
//log_and_message_admins("Bone hit, bone_chance1. energy_to_fracture = [energy_to_fracture]")
if(energy_to_fracture>=P.energy) //We don't have enough energy to get through the bone. This is the end for us!
energy_dumped_organic += P.energy/2 //About half of our remaining energy will go into fucking up this boi, the rest is absorbed by the bone
P.sub_velocity(P.velocity)
//log_and_message_admins("Insufficient projectile energy. Stopping projectile.")
energy_to_damage(energy_dumped_organic * conversion_efficiency,hit_organ.organ_tag)
return 2
else
//log_and_message_admins("Sufficient projectile energy to pass through bone.")
P.sub_energy(energy_to_fracture)
energy_dumped_organic += P.energy / 3 //About a third of the energy that goes into fracturing the bone also goes into fucking up tissues.
if(!(hit_organ.status & ORGAN_BROKEN))
//log_and_message_admins("Fracturing [hit_organ]")
hit_organ.fracture()
//log_and_message_admins("Bone checking done. hit_organ = [hit_organ], energy_dumped_organic = [energy_dumped_organic], internal_loss = [internal_loss], ballistic_armor = [ballistic_armor], P.velocity = [P.velocity], P.energy = [P.energy]")
if(hit_organ.internal_organs.len && P.velocity > area_over_mass*ORGAN_LOSS_COEFFICIENT && prob(ballistic_variables["organ_hit_chance"][hit_organ.organ_tag]) && updated_organ_weight[hit_organ] && updated_organ_weight[hit_organ].len)
//log_and_message_admins("Organ was hit by bullet.")
energy_past = P.energy
P.sub_velocity(internal_loss)
damage_organ_energy((energy_past - P.energy) * conversion_efficiency, pickweight(updated_organ_weight[hit_organ]))
if(!P.velocity)
//log_and_message_admins("Organ stopped bullet.")
energy_to_damage(energy_dumped_organic * conversion_efficiency,hit_organ.organ_tag)
return 2
//log_and_message_admins("Organ check done, hit_organ = [hit_organ], energy_dumped_organic = [energy_dumped_organic], internal_loss = [internal_loss], ballistic_armor = [ballistic_armor], P.velocity = [P.velocity], P.energy = [P.energy]")
energy_past = P.energy
P.sub_velocity(internal_loss)
energy_dumped_organic += energy_past - P.energy
if(!P.velocity || (hit_organ.organ_tag in ballistic_variables["organ_leave_early"]) || prob(PROB_LEAVE_EARLY_SECOND))
energy_to_damage(energy_dumped_organic * conversion_efficiency,hit_organ.organ_tag)
return P.velocity ? -1 : 2
//log_and_message_admins("Internal_loss 2 stopped bullet")
//log_and_message_admins("Internal_loss 2 completed, hit_organ = [hit_organ], energy_dumped_organic = [energy_dumped_organic], internal_loss = [internal_loss], ballistic_armor = [ballistic_armor], P.velocity = [P.velocity], P.energy = [P.energy]")
if(prob(bone_chance))
var/energy_to_fracture = max(GLOB.BONE_JOULES_MIN, hit_organ.min_broken_damage * (GAUSSIAN_RANDOM()*GLOB.BONE_JOULES_PERHP_DEV + GLOB.BONE_JOULES_PERHP_AVG))
//log_and_message_admins("Bone hit, bone_chance1. energy_to_fracture = [energy_to_fracture]")
if(energy_to_fracture>=P.energy) //We don't have enough energy to get through the bone. This is the end for us!
energy_dumped_organic += P.energy/2 //About half of our remaining energy will go into fucking up this boi, the rest is absorbed by the bone
P.sub_velocity(P.velocity)
//log_and_message_admins("Insufficient projectile energy. Stopping projectile.")
energy_to_damage(energy_dumped_organic * conversion_efficiency,hit_organ.organ_tag)
return 2
else
//log_and_message_admins("Sufficient projectile energy to pass through bone.")
P.sub_energy(energy_to_fracture)
energy_dumped_organic += P.energy / 3 //About a third of the energy that goes into fracturing the bone also goes into fucking up tissues.
if(!(hit_organ.status & ORGAN_BROKEN))
//log_and_message_admins("Fracturing [hit_organ]")
hit_organ.fracture()
energy_past = P.energy
P.sub_velocity(internal_loss)
energy_dumped_organic += energy_past - P.energy
if(!P.velocity)
//log_and_message_admins("Internal_loss 3 stopped bullet")
energy_to_damage(energy_dumped_organic * conversion_efficiency,hit_organ.organ_tag)
return 2
//log_and_message_admins("Internal_loss 3 completed. hit_organ = [hit_organ], energy_dumped_organic = [energy_dumped_organic], internal_loss = [internal_loss], ballistic_armor = [ballistic_armor], P.velocity = [P.velocity], P.energy = [P.energy]")
var/penetration_chance = armor_penetration_probability(ballistic_armor,P)
if(prob(penetration_chance))
//log_and_message_admins("Projectile exiting.")
energy_to_damage(energy_dumped_organic * conversion_efficiency,hit_organ.organ_tag)
return -1
else
//log_and_message_admins("Projectile continuing inside body")
energy_dumped_organic += P.energy / 3
P.sub_velocity(P.velocity)
energy_to_damage(energy_dumped_organic * conversion_efficiency,hit_organ.organ_tag)
return 2
/mob/living/proc/general_handle_ballistics(var/obj/item/projectile/bullet/P,var/def_zone,var/energy_dumped_organic,var/internal_loss,var/ballistic_armor)
var/conversion_efficiency = P.hollow_point ? GLOB.HOLLOW_POINT_CONVERSION_EFF : 1
var/energy_past
var/area_over_mass = P.diam * P.diam / P.grains
var/bone_chance = BONE_HIT_CHANCE_UNENCASED
//if(def_zone in ballistic_variables["bone_chance_unencased"])
//bone_chance = ballistic_variables["bone_chance_unencased"][def_zone]
if(prob(bone_chance))
var/energy_to_fracture = max(GLOB.BONE_JOULES_MIN, BONE_HP_AVG * (GAUSSIAN_RANDOM()*GLOB.BONE_JOULES_PERHP_DEV + GLOB.BONE_JOULES_PERHP_AVG))
if(energy_to_fracture>=P.energy) //We don't have enough energy to get through the bone. This is the end for us!
energy_dumped_organic += P.energy/2 //About half of our remaining energy will go into fucking up this boi, the rest is absorbed by the bone
P.sub_velocity(P.velocity)
energy_to_damage(energy_dumped_organic * conversion_efficiency,def_zone)
return 2
else
P.sub_energy(energy_to_fracture)
energy_dumped_organic += P.energy / 3 //About a third of the energy that goes into fracturing the bone also goes into fucking up tissues.
if(P.velocity > area_over_mass * ORGAN_LOSS_COEFFICIENT && prob(HIT_VITAL_ORGAN_CHANCE))
energy_past = P.energy
P.sub_velocity(internal_loss)
energy_dumped_organic += (energy_past - P.energy) * 1.5
if(!P.velocity)
energy_to_damage(energy_dumped_organic * conversion_efficiency,def_zone)
return 2
energy_past = P.energy
P.sub_velocity(internal_loss)
energy_dumped_organic += energy_past - P.energy
if(!P.velocity || (def_zone in ballistic_variables["organ_leave_early"]) || prob(PROB_LEAVE_EARLY_SECOND))
energy_to_damage(energy_dumped_organic * conversion_efficiency,def_zone)
return P.velocity ? -1 : 2
if(prob(bone_chance))
var/energy_to_fracture = max(GLOB.BONE_JOULES_MIN, BONE_HP_AVG * (GAUSSIAN_RANDOM()*GLOB.BONE_JOULES_PERHP_DEV + GLOB.BONE_JOULES_PERHP_AVG))
if(energy_to_fracture>=P.energy) //We don't have enough energy to get through the bone. This is the end for us!
energy_dumped_organic += P.energy/2 //About half of our remaining energy will go into fucking up this boi, the rest is absorbed by the bone
P.sub_velocity(P.velocity)
energy_to_damage(energy_dumped_organic * conversion_efficiency,def_zone)
return 2
else
P.sub_energy(energy_to_fracture)
energy_dumped_organic += P.energy / 3 //About a third of the energy that goes into fracturing the bone also goes into fucking up tissues.
energy_past = P.energy
P.sub_velocity(internal_loss)
energy_dumped_organic += energy_past - P.energy
if(!P.velocity)
energy_to_damage(energy_dumped_organic * conversion_efficiency,def_zone)
return 2
var/penetration_chance = armor_penetration_probability(ballistic_armor,P)
if(prob(penetration_chance))
energy_to_damage(energy_dumped_organic * conversion_efficiency,def_zone)
return -1
else
energy_dumped_organic += P.energy / 3
P.sub_velocity(P.velocity)
energy_to_damage(energy_dumped_organic * conversion_efficiency,def_zone)
return 2
/mob/living/proc/damage_organ_energy(var/energy,var/obj/item/organ/internal/target)
var/damage = round(energy*GLOB.ENERGY_DAMAGE_ORGAN_FACTOR)
//log_and_message_admins("damage_organ_energy([energy]) : [target].take_damage([damage])")
target.take_damage(damage)
return
/mob/living/proc/energy_to_damage(var/energy,var/def_zone)
var/damage = round(energy*GLOB.ENERGY_DAMAGE_FLESH_FACTOR)
//log_and_message_admins("energy_to_damage([energy]) : apply_damage([damage], BRUTE, [def_zone])")
apply_damage(damage, BRUTE, def_zone)
return
/mob/living/proc/armor_penetration_probability(var/armor, var/obj/item/projectile/bullet/P)
var/bullet_ap_value = (1+((P.armor_penetration)/BULLET_AP_DIVISOR))
var/ap_value = P.velocity * bullet_ap_value * (P.grains / P.diam)**(2/3) / AP_DIVISOR
var/armor_value = ARMOR_Y_INTERCEPT + ARMOR_SLOPE * armor
var/penetration_chance = 100 / (1 + PENETRATION_PROBABILITY_EXP_BASE**(-PENETRATION_PROBABILITY_EXP_MULT*(ap_value - armor_value)))
return penetration_chance
/mob/living/bullet_act(var/obj/item/projectile/P, var/def_zone)
//log_and_message_admins("bullet_act_ch")
var/obj/item/projectile/bullet/B = P
if(P.check_armour == "bullet" && istype(B) && !B.old_bullet_act)
//log_and_message_admins("is bullet")
return handle_ballistics(P,def_zone)
else
//log_and_message_admins("is not bullet")
return ..()
/mob/living
var/list/ballistic_variables = list(\
"bone_chance_unencased" = list(BP_HEAD = 5, BP_TORSO = 20, BP_GROIN = 20, BP_L_FOOT = 80, BP_R_FOOT = 80, BP_L_LEG = 35, BP_R_LEG = 35, BP_L_ARM = 65, BP_R_ARM = 65, BP_L_HAND = 80, BP_R_HAND = 80), \
"organ_leave_early" = list("l_arm", "r_arm", "l_hand", "r_hand", "l_foot", "r_foot"), \
"organ_hit_weight" = list(\
BP_HEAD = list(\
/*Standard organs*/O_BRAIN = 90, O_EYES = 5, \
/*Diona organs*/O_RESPONSE = 10, O_RESPONSE = 15, O_GBLADDER = 15, \
/*Replicant organs*/O_VRLINK = 20, \
/*Xeno organs*/O_ACID = 10, O_RESIN = 10), \
BP_TORSO = list(\
/*Standard organs*/O_HEART = 5, O_LUNGS = 50, O_SPLEEN = 15, O_VOICE = 10, \
/*Synth organs*/O_CELL = 5, O_PUMP = 15, O_HEATSINK = 35, O_CYCLER = 15, O_DIAGNOSTIC = 10, \
/*Promethean organs*/O_REGBRUTE = 20, O_REGBURN = 20, O_REGOXY = 20, O_REGTOX = 20, \
/*Diona organs*/O_STRATA = 35, O_BRAIN = 20, O_NUTRIENT = 10, \
/*Replicant organs*/O_AREJECT = 35, \
/*Xeno organs*/O_PLASMA = 10, O_HIVE = 10), \
BP_GROIN = list(\
/*Standard organs*/O_INTESTINES = 50, O_STOMACH = 20, O_LIVER = 20, O_KIDNEYS = 15, O_APPENDIX = 5, \
/*Diona organs*/O_POLYP = 10, O_ANCHOR = 15, \
/*Replicant organs*/O_VENTC = 20, \
/*Xeno organs*/ O_EGG = 25) ), \
"organ_hit_chance" = list(BP_HEAD = 95, BP_TORSO = 90, BP_GROIN = 90) )
@@ -0,0 +1,236 @@
#define BULLET_PENETRATED 1<<0
#define BULLET_BONECHECK1_TRUE 1<<1
#define BULLET_ORGANCHECK_TRUE 1<<2
#define BULLET_BONECHECK2_TRUE 1<<3
#define BULLET_PASSED_LEAVE_EARLY 1<<4
#define BULLET_PASSED_BONECHECK1 1<<5
#define BULLET_PASSED_ORGANCHECK 1<<6
#define BULLET_PASSED_INTERNALCHECK2 1<<7
#define BULLET_PASSED_BONECHECK2 1<<8
#define BULLET_PASSED_INTERNALCHECK3 1<<9
#define BULLET_TESTS 150
/mob/living/carbon/human/monkey/testerboyo
name = "testerboyo"
var/the_big_armor = 0
/mob/living/carbon/human/monkey/testerboyo/getarmor(var/def_zone,var/type)
return the_big_armor
/proc/test_all_ballistics()
var/mob/living/carbon/human/monkey/testerboyo/tester = new()
var/obj/item/projectile/bullet/pistol/test1 = new()
var/obj/item/projectile/bullet/pistol/ap/test2 = new()
var/obj/item/projectile/bullet/pistol/hp/test3 = new()
var/obj/item/projectile/bullet/pistol/medium/test4 = new()
var/obj/item/projectile/bullet/pistol/medium/ap/test5 = new()
var/obj/item/projectile/bullet/pistol/medium/hp/test6 = new()
var/obj/item/projectile/bullet/pistol/strong/test7 = new()
var/obj/item/projectile/bullet/shotgun/test8 = new()
var/obj/item/projectile/bullet/shotgun/buckshot/test9 = new()
var/obj/item/projectile/bullet/rifle/a762/test10 = new()
var/obj/item/projectile/bullet/rifle/a762/ap/test11 = new()
var/obj/item/projectile/bullet/rifle/a762/hp/test12 = new()
var/obj/item/projectile/bullet/rifle/a545/test13 = new()
var/obj/item/projectile/bullet/rifle/a545/ap/test14 = new()
var/obj/item/projectile/bullet/rifle/a545/hp/test15 = new()
var/obj/item/projectile/bullet/rifle/a145/test16 = new()
var/obj/item/projectile/bullet/rifle/a145/highvel/test17 = new()
var/obj/item/projectile/bullet/rifle/a44rifle/test18 = new()
var/obj/item/projectile/bullet/rifle/a95/test19 = new()
var/obj/item/projectile/bullet/rifle/a762/lmg/test20 = new()
test_ballistics(test1,tester)
test_ballistics(test2,tester)
test_ballistics(test3,tester)
test_ballistics(test4,tester)
test_ballistics(test5,tester)
test_ballistics(test6,tester)
test_ballistics(test7,tester)
test_ballistics(test8,tester)
test_ballistics(test9,tester)
test_ballistics(test10,tester)
test_ballistics(test11,tester)
test_ballistics(test12,tester)
test_ballistics(test13,tester)
test_ballistics(test14,tester)
test_ballistics(test15,tester)
test_ballistics(test16,tester)
test_ballistics(test17,tester)
test_ballistics(test18,tester)
test_ballistics(test19,tester)
test_ballistics(test20,tester)
qdel(tester)
qdel(test1)
qdel(test2)
qdel(test3)
qdel(test4)
qdel(test5)
qdel(test6)
qdel(test7)
qdel(test8)
qdel(test9)
qdel(test10)
qdel(test11)
qdel(test12)
qdel(test13)
qdel(test14)
qdel(test15)
qdel(test16)
qdel(test17)
qdel(test18)
qdel(test19)
qdel(test20)
/proc/test_ballistics(var/obj/item/projectile/bullet/P,var/mob/living/carbon/human/monkey/testerboyo/tester)
var/list/data = list()
for(var/armor_level in list(0,5,10,20,50,80))
data["[armor_level]"] = list()
data["[armor_level]"]["average"] = list()
tester.the_big_armor = armor_level
var/bp_num = 0
for(var/body_part in list(BP_TORSO,BP_HEAD,BP_R_LEG,BP_R_ARM,BP_R_HAND))
bp_num++
data["[armor_level]"][body_part] = list()
for(var/i = 0,i<BULLET_TESTS,i++)
P.velocity = initial(P.velocity)
P.sub_velocity(0)
var/out = tester.handle_ballistics(P,body_part)
for(var/x = 0,x<10,x++)
var/input = (out["chex"] & (1<<x)) ? 1 : 0
data["[armor_level]"][body_part]["[x]"] += input
data["[armor_level]"]["average"]["[x]"] += input
data["[armor_level]"][body_part]["10"] += out["energy"]
data["[armor_level]"][body_part]["10"] /= BULLET_TESTS
data["[armor_level]"]["average"]["10"] += data["[armor_level]"][body_part]["10"]
for(var/x = 0,x<11,x++)
data["[armor_level]"]["average"]["[x]"] /= bp_num
for(var/entry in data["[armor_level]"])
var/string_to_send = "[P.type]: Armor level [armor_level]: [entry]:"
for(var/x = 0,x<11,x++)
string_to_send += " [x]:[data["[armor_level]"][entry]["[x]"]]"
log_and_message_admins(string_to_send)
/proc/lazy_return_testing(var/chex,var/energy)
return list("chex" = chex, "energy" = energy)
/mob/living/carbon/human/monkey/testerboyo/handle_ballistics(var/obj/item/projectile/bullet/P, var/def_zone)
var/chex = 0
var/list/updated_organ_weight = list()
var/ballistic_armor = getarmor(def_zone, "bullet")
var/melee_armor = getarmor(def_zone, "melee")
var/obj/item/organ/external/hit_organ
var/mob/living/carbon/human/H = src
if(istype(H))
hit_organ = H.get_organ(def_zone)
for(var/ext_organ in ballistic_variables["organ_hit_weight"])
var/list/input = list()
var/obj/item/organ/external/ref_ext_organ = H.get_organ(ext_organ)
for(var/int_organ in ballistic_variables["organ_hit_weight"][ext_organ])
var/ref_int_organ = H.internal_organs_by_name[int_organ]
if(ref_ext_organ && ref_int_organ && (ref_int_organ in ref_ext_organ.internal_organs))
input[ref_int_organ] = ballistic_variables["organ_hit_weight"][ext_organ][int_organ]
if(input.len)
updated_organ_weight[ref_ext_organ] = input
var/penetration_chance = armor_penetration_probability(ballistic_armor,P)
if(!prob(penetration_chance)) //Boo-hoo we got deflected. Do boring agony/bruises stuff.
var/pain_hit = hit_organ ? "into your [hit_organ]" : "into you"
var/hurt_value = P.velocity * P.grains / (BULLET_DEFLECTED_PAIN_DIVISOR * (1 + ballistic_armor/BULLET_DEFLECTED_BULLET_DIVISOR + melee_armor/BULLET_DEFLECTED_MELEE_DIVISOR)) //Better armor spreads out the energy better.
var/hurt_value_pain = hurt_value ** BULLET_DEFLECTED_PAIN_EXPONENT
var/hurt_value_bruise = max(0,hurt_value-BULLET_DEFLECTED_BRUISE_SUBTRACT)
var/absorber = ballistic_armor ? "armor" : "body" //There is a super tiny chance that small rounds can get deflected without armor, so this is just incase.
to_chat(src,"<span class='warning'>You feel the energy of the bullet painfully transfered [pain_hit] as your [absorber] deflects it!</span>")
apply_damage(hurt_value_pain,HALLOSS,def_zone)
if(hurt_value_bruise)
apply_damage(hurt_value_bruise,BRUTE,def_zone)
P.sub_velocity(P.velocity)
return lazy_return_testing(chex,0)
else //Now the FUN begins
chex |= BULLET_PENETRATED
var/area_over_mass = P.diam * P.diam / P.grains
//Most of these calculations don't involve energies because I'm treating flesh and organic tissue as a fluid since it's squishy and stuff.
//Since drag is proportional to velocity, we can do things on an m*v basis instead of an mv^2 basis.
//Obviously bones are more solid, so we do actual energy calculations for that.
//var/conversion_efficiency = P.hollow_point ? 0.925 : 1
var/vel_loss_multiplier = P.hollow_point ? GLOB.HOLLOW_POINT_VELLOSS_BONUS : 1
var/energy_dumped_organic = 0
var/vel_lost_armor = ballistic_armor >= GLOB.ARMOR_LOSS_MIN_ARMOR ? GLOB.ARMOR_LOSS_COEFFICIENT * area_over_mass * ((1 + GLOB.ARMOR_LOSS_MIN_MULT) - penetration_chance/100) : 0
P.sub_velocity(vel_lost_armor)
var/energy_past = P.energy
var/internal_loss = vel_loss_multiplier * GLOB.INTERNAL_LOSS_COEFFICIENT * area_over_mass
var/vel_lost_skin = vel_loss_multiplier * GLOB.SKIN_LOSS_COEFFICIENT * area_over_mass
P.sub_velocity(vel_lost_skin + internal_loss)
energy_dumped_organic += (energy_past - P.energy)
if(prob(PROB_LEAVE_EARLY_FIRST) || !P.velocity)
return lazy_return_testing(chex,energy_dumped_organic)
if(hit_organ)
chex |= BULLET_PASSED_LEAVE_EARLY
return organ_handle_ballistics(P,hit_organ,energy_dumped_organic,internal_loss,ballistic_armor,updated_organ_weight,chex)
else
return general_handle_ballistics(P,def_zone,energy_dumped_organic,internal_loss,ballistic_armor)
/mob/living/carbon/human/monkey/testerboyo/organ_handle_ballistics(var/obj/item/projectile/bullet/P,var/obj/item/organ/external/hit_organ,var/energy_dumped_organic,var/internal_loss,var/ballistic_armor,var/list/updated_organ_weight,var/chex)
//var/conversion_efficiency = P.hollow_point ? 0.8 : 1
var/energy_past
var/area_over_mass = P.diam * P.diam / P.grains
var/bone_chance = BONE_HIT_CHANCE_UNENCASED
if(hit_organ.encased)
bone_chance = BONE_HIT_CHANCE_ENCASED
else
bone_chance = ballistic_variables["bone_chance_unencased"][hit_organ.organ_tag]
if(prob(bone_chance))
chex |= BULLET_BONECHECK1_TRUE
var/energy_to_fracture = max(GLOB.BONE_JOULES_MIN, hit_organ.min_broken_damage * (GAUSSIAN_RANDOM()*GLOB.BONE_JOULES_PERHP_DEV + GLOB.BONE_JOULES_PERHP_AVG))
if(energy_to_fracture>=P.energy) //We don't have enough energy to get through the bone. This is the end for us!
energy_dumped_organic += P.energy/2 //About half of our remaining energy will go into fucking up this boi, the rest is absorbed by the bone
P.sub_velocity(P.velocity)
return lazy_return_testing(chex,energy_dumped_organic)
else
P.sub_energy(energy_to_fracture)
energy_dumped_organic += energy_to_fracture / 3 //About a third of the energy that goes into fracturing the bone also goes into fucking up tissues.
chex |= BULLET_PASSED_BONECHECK1
if(hit_organ.internal_organs.len && P.velocity > area_over_mass*ORGAN_LOSS_COEFFICIENT && prob(ballistic_variables["organ_hit_chance"][hit_organ.organ_tag]) && updated_organ_weight[hit_organ] && updated_organ_weight[hit_organ].len)
chex |= BULLET_ORGANCHECK_TRUE
energy_past = P.energy
P.sub_velocity(internal_loss)
if(!P.velocity)
return lazy_return_testing(chex,energy_dumped_organic)
chex |= BULLET_PASSED_ORGANCHECK
energy_past = P.energy
P.sub_velocity(internal_loss)
energy_dumped_organic += energy_past - P.energy
if(!P.velocity || (hit_organ.organ_tag in ballistic_variables["organ_leave_early"]) || prob(PROB_LEAVE_EARLY_SECOND))
return lazy_return_testing(chex,energy_dumped_organic)
chex |= BULLET_PASSED_INTERNALCHECK2
if(prob(bone_chance))
chex |= BULLET_BONECHECK2_TRUE
var/energy_to_fracture = max(GLOB.BONE_JOULES_MIN, hit_organ.min_broken_damage * (GAUSSIAN_RANDOM()*GLOB.BONE_JOULES_PERHP_DEV + GLOB.BONE_JOULES_PERHP_AVG))
if(energy_to_fracture>=P.energy) //We don't have enough energy to get through the bone. This is the end for us!
energy_dumped_organic += P.energy/2 //About half of our remaining energy will go into fucking up this boi, the rest is absorbed by the bone
P.sub_velocity(P.velocity)
return lazy_return_testing(chex,energy_dumped_organic)
else
P.sub_energy(energy_to_fracture)
energy_dumped_organic += energy_to_fracture / 3 //About a third of the energy that goes into fracturing the bone also goes into fucking up tissues.
chex |= BULLET_PASSED_BONECHECK2
energy_past = P.energy
P.sub_velocity(internal_loss)
energy_dumped_organic += energy_past - P.energy
if(!P.velocity)
return lazy_return_testing(chex,energy_dumped_organic)
chex |= BULLET_PASSED_INTERNALCHECK3
var/penetration_chance = armor_penetration_probability(ballistic_armor,P)
if(prob(penetration_chance))
return lazy_return_testing(chex,energy_dumped_organic)
else
energy_dumped_organic += P.energy / 3
P.sub_velocity(P.velocity)
return lazy_return_testing(chex,energy_dumped_organic)
+34
View File
@@ -1022,6 +1022,40 @@ mob/proc/yank_out_object()
set hidden = 1
set_face_dir(client.client_dir(WEST))
// Begin VOREstation edit
/mob/verb/shiftnorth()
set hidden = TRUE
if(!canface())
return FALSE
if(pixel_y <= 16)
pixel_y++
is_shifted = TRUE
/mob/verb/shiftsouth()
set hidden = TRUE
if(!canface())
return FALSE
if(pixel_y >= -16)
pixel_y--
is_shifted = TRUE
/mob/verb/shiftwest()
set hidden = TRUE
if(!canface())
return FALSE
if(pixel_x >= -16)
pixel_x--
is_shifted = TRUE
mob/verb/shifteast()
set hidden = TRUE
if(!canface())
return FALSE
if(pixel_x <= 16)
pixel_x++
is_shifted = TRUE
// End VOREstation edit
/mob/proc/adjustEarDamage()
return
+1
View File
@@ -83,6 +83,7 @@
var/resting = 0 //Carbon
var/lying = 0
var/lying_prev = 0
var/is_shifted = FALSE // VoreStation Edit; pixel shifting
var/canmove = 1
//Allows mobs to move through dense areas without restriction. For instance, in space or out of holder objects.
var/incorporeal_move = 0 //0 is off, 1 is normal, 2 is for ninjas.
@@ -1184,17 +1184,6 @@
bee_stripes
name = "bee stripes"
icon_state = "beestripes"
<<<<<<< HEAD
body_parts = list(BP_TORSO,BP_GROIN)
||||||| parent of bbd7600f00... Merge pull request #9307 from KasparoVy/port-some-citrp-stuff
body_parts = list(BP_TORSO,BP_GROIN)
vas_toes
name = "Bug Paws (Vasilissan)"
icon_state = "vas_toes"
color_blend_mode = ICON_MULTIPLY
body_parts = list(BP_L_FOOT,BP_R_FOOT)
=======
body_parts = list(BP_TORSO,BP_GROIN)
vas_toes
@@ -1269,4 +1258,4 @@
color_blend_mode = ICON_MULTIPLY
body_parts = list(BP_L_LEG,BP_R_LEG,BP_L_HAND,BP_R_HAND,BP_TORSO,BP_GROIN,BP_HEAD)
species_allowed = list(SPECIES_TESHARI)
>>>>>>> bbd7600f00... Merge pull request #9307 from KasparoVy/port-some-citrp-stuff
body_parts = list(BP_L_FOOT,BP_R_FOOT)
+14 -1
View File
@@ -100,6 +100,8 @@
/datum/nifsoft/medichines_syn/life()
if((. = ..()))
var/mob/living/carbon/human/H = nif.human // Chomp Edit
var/HP_percent = H.health/H.getMaxHealth() // Chomp Edit
//We're good!
if(!nif.human.bad_external_organs.len)
if(mode || active)
@@ -117,7 +119,7 @@
var/obj/item/organ/external/EO = eo
for(var/w in EO.wounds)
var/datum/wound/W = w
if(W.damage <= 5)
if(W.damage <= 30) // Chomp Edit // The current limb break threshold.
W.heal_damage(0.1)
EO.update_damages()
if(EO.update_icon())
@@ -127,6 +129,17 @@
else if(mode == 1)
mode = 2
nif.notify("Medichines unable to repair all damage. Perform manual repairs.",TRUE)
// Chomp Edit Start //
else if(mode == 2 && HP_percent < -0.4)
nif.notify("User Status: CRITICAL. Notifying medical!",TRUE)
H << 'sound/voice/nifmed_critical.ogg' //CHOMP Add
mode = 0
if(!isbelly(H.loc)) //Not notified in case of vore, for gameplay purposes.
var/turf/T = get_turf(H)
var/obj/item/device/radio/headset/a = new /obj/item/device/radio/headset/heads/captain(null)
a.autosay("[H.real_name] is in critical condition, located at ([T.x],[T.y],[T.z])!", "[H.real_name]'s NIF", "Medical")
qdel(a)
// Chomp Edit End //
return TRUE
+2
View File
@@ -14,6 +14,8 @@
target_parent_classes = list() // Is the parent supposed to be organic, robotic, assisted?
forgiving_class = TRUE // Will the organ give its verbs when it isn't a perfect match? I.E., assisted in organic, synthetic in organic.
butcherable = FALSE
var/obj/item/integrated_object // Objects held by the organ, used for re-usable, deployable things.
var/integrated_object_type // Object type the organ will spawn.
var/target_slot = null
+12 -7
View File
@@ -83,8 +83,11 @@ GLOBAL_LIST_BOILERPLATE(all_brain_organs, /obj/item/organ/internal/brain)
health = config.default_brain_health
defib_timer = (config.defib_timer MINUTES) / 2
spawn(5)
if(brainmob && brainmob.client)
brainmob.client.screen.len = null //clear the hud
if(brainmob)
butcherable = FALSE
if(brainmob.client)
brainmob.client.screen.len = null //clear the hud
/obj/item/organ/internal/brain/Destroy()
QDEL_NULL(brainmob)
@@ -96,9 +99,11 @@ GLOBAL_LIST_BOILERPLATE(all_brain_organs, /obj/item/organ/internal/brain)
brainmob = new(src)
brainmob.name = H.real_name
brainmob.real_name = H.real_name
brainmob.dna = H.dna.Clone()
brainmob.timeofhostdeath = H.timeofdeath
brainmob.ooc_notes = H.ooc_notes //VOREStation Edit
if(istype(H))
brainmob.dna = H.dna.Clone()
brainmob.timeofhostdeath = H.timeofdeath
brainmob.ooc_notes = H.ooc_notes //VOREStation Edit
// Copy modifiers.
for(var/datum/modifier/M in H.modifiers)
@@ -125,13 +130,13 @@ GLOBAL_LIST_BOILERPLATE(all_brain_organs, /obj/item/organ/internal/brain)
if(name == initial(name))
name = "\the [owner.real_name]'s [initial(name)]"
var/mob/living/simple_mob/animal/borer/borer = owner.has_brain_worms()
var/mob/living/simple_mob/animal/borer/borer = owner?.has_brain_worms()
if(borer)
borer.detatch() //Should remove borer if the brain is removed - RR
var/obj/item/organ/internal/brain/B = src
if(istype(B) && istype(owner))
if(istype(B) && owner)
B.transfer_identity(owner)
..()
+1 -1
View File
@@ -8,7 +8,7 @@
/obj/item/organ/internal/liver/process()
..()
if(!owner) return
if(!iscarbon(owner)) return
if(owner.life_tick % PROCESS_ACCURACY == 0)
@@ -9,3 +9,4 @@
decays = FALSE // Ditto. Rust takes a while.
robotic = ORGAN_ROBOT
butcherable = FALSE
+137 -56
View File
@@ -44,6 +44,9 @@ var/list/organ_cache = list()
var/list/target_parent_classes = list() // Is the parent supposed to be organic, robotic, assisted?
var/forgiving_class = TRUE // Will the organ give its verbs when it isn't a perfect match? I.E., assisted in organic, synthetic in organic.
var/butcherable = TRUE
var/meat_type // What does butchering, if possible, make?
/obj/item/organ/Destroy()
handle_organ_mod_special(TRUE)
@@ -59,21 +62,42 @@ var/list/organ_cache = list()
/obj/item/organ/proc/update_health()
return
/obj/item/organ/New(var/mob/living/carbon/holder, var/internal)
/obj/item/organ/New(var/mob/living/holder, var/internal)
..(holder)
create_reagents(5)
if(!max_damage)
max_damage = min_broken_damage * 2
if(istype(holder))
if(isliving(holder))
src.owner = holder
src.w_class = max(src.w_class + mob_size_difference(holder.mob_size, MOB_MEDIUM), 1) //smaller mobs have smaller organs.
if(internal)
if(!LAZYLEN(holder.internal_organs))
holder.internal_organs = list()
if(!LAZYLEN(holder.internal_organs_by_name))
holder.internal_organs_by_name = list()
holder.internal_organs |= src
holder.internal_organs_by_name[organ_tag] = src
else
if(!LAZYLEN(holder.organs))
holder.organs = list()
if(!LAZYLEN(holder.organs_by_name))
holder.organs_by_name = list()
holder.internal_organs |= src
holder.internal_organs_by_name[organ_tag] = src
if(!max_damage)
max_damage = min_broken_damage * 2
if(iscarbon(holder))
var/mob/living/carbon/C = holder
species = GLOB.all_species[SPECIES_HUMAN]
if(holder.dna)
dna = holder.dna.Clone()
species = holder.species //VOREStation Edit - For custom species
dna = C.dna.Clone()
species = C.species //VOREStation Edit - For custom species
else
log_debug("[src] at [loc] spawned without a proper DNA.")
var/mob/living/carbon/human/H = holder
var/mob/living/carbon/human/H = C
if(istype(H))
if(internal)
var/obj/item/organ/external/E = H.get_organ(parent_organ)
@@ -81,18 +105,32 @@ var/list/organ_cache = list()
if(E.internal_organs == null)
E.internal_organs = list()
E.internal_organs |= src
H.internal_organs_by_name[organ_tag] = src
if(dna)
if(!blood_DNA)
blood_DNA = list()
blood_DNA[dna.unique_enzymes] = dna.b_type
if(internal)
holder.internal_organs |= src
else
species = GLOB.all_species["Human"]
handle_organ_mod_special()
/obj/item/organ/Initialize()
..()
if(owner)
if(!meat_type)
if(owner.isSynthetic())
meat_type = /obj/item/stack/material/steel
else if(ishuman(owner))
var/mob/living/carbon/human/H = owner
meat_type = H?.species?.meat_type
if(!meat_type)
if(owner.meat_type)
meat_type = owner.meat_type
else
meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat
/obj/item/organ/proc/set_dna(var/datum/dna/new_dna)
if(new_dna)
dna = new_dna.Clone()
@@ -134,7 +172,7 @@ var/list/organ_cache = list()
handle_organ_proc_special()
//Process infections
if(robotic >= ORGAN_ROBOT || (owner && owner.species && (owner.species.flags & IS_PLANT || (owner.species.flags & NO_INFECT))))
if(robotic >= ORGAN_ROBOT || (istype(owner) && (owner.species && (owner.species.flags & (IS_PLANT | NO_INFECT)))))
germ_level = 0
return
@@ -152,7 +190,7 @@ var/list/organ_cache = list()
if(germ_level >= INFECTION_LEVEL_THREE)
die()
else if(owner && owner.bodytemperature >= 170) //cryo stops germs from moving and doing their bad stuffs
else if(owner && owner?.bodytemperature >= 170) //cryo stops germs from moving and doing their bad stuffs
//** Handle antibiotics and curing infections
handle_antibiotics()
handle_rejection()
@@ -170,7 +208,7 @@ var/list/organ_cache = list()
germ_level = 0
return 0
var/antibiotics = owner.chem_effects[CE_ANTIBIOTIC] || 0
var/antibiotics = iscarbon(owner) ? owner.chem_effects[CE_ANTIBIOTIC] || 0 : 0
var/infection_damage = 0
@@ -203,10 +241,12 @@ var/list/organ_cache = list()
//Level 1 qualifies for specific organ processing effects
if(germ_level >= INFECTION_LEVEL_ONE)
. = 1
var/fever_temperature = owner.species.heat_discomfort_level * 1.10 //Heat discomfort level plus 10%
if(owner.bodytemperature < fever_temperature)
owner.bodytemperature += min(0.2,(fever_temperature - owner.bodytemperature) / 10) //Will usually climb by 0.2, else 10% of the difference if less
. = 1 //Organ qualifies for effect-specific processing
//var/fever_temperature = (owner.species.heat_level_1 - owner.species.body_temperature - 5)* min(germ_level/INFECTION_LEVEL_TWO, 1) + owner.species.body_temperature
//owner.bodytemperature += between(0, (fever_temperature - T20C)/BODYTEMP_COLD_DIVISOR + 1, fever_temperature - owner.bodytemperature)
var/fever_temperature = owner?.species.heat_discomfort_level * 1.10 //Heat discomfort level plus 10%
if(owner?.bodytemperature < fever_temperature)
owner?.bodytemperature += min(0.2,(fever_temperature - owner?.bodytemperature) / 10) //Will usually climb by 0.2, else 10% of the difference if less
//Level two qualifies for further processing effects
if (germ_level >= INFECTION_LEVEL_TWO)
@@ -269,19 +309,20 @@ var/list/organ_cache = list()
//Germs
/obj/item/organ/proc/handle_antibiotics()
var/antibiotics = owner.chem_effects[CE_ANTIBIOTIC] || 0
if(istype(owner))
var/antibiotics = owner.chem_effects[CE_ANTIBIOTIC] || 0
if (!germ_level || antibiotics < ANTIBIO_NORM)
return
if (!germ_level || antibiotics < ANTIBIO_NORM)
return
if (germ_level < INFECTION_LEVEL_ONE)
germ_level = 0 //cure instantly
else if (germ_level < INFECTION_LEVEL_TWO)
adjust_germ_level(-antibiotics*4) //at germ_level < 500, this should cure the infection in a minute
else if (germ_level < INFECTION_LEVEL_THREE)
adjust_germ_level(-antibiotics*2) //at germ_level < 1000, this will cure the infection in 5 minutes
else
adjust_germ_level(-antibiotics) // You waited this long to get treated, you don't really deserve this organ
if (germ_level < INFECTION_LEVEL_ONE)
germ_level = 0 //cure instantly
else if (germ_level < INFECTION_LEVEL_TWO)
adjust_germ_level(-antibiotics*4) //at germ_level < 500, this should cure the infection in a minute
else if (germ_level < INFECTION_LEVEL_THREE)
adjust_germ_level(-antibiotics*2) //at germ_level < 1000, this will cure the infection in 5 minutes
else
adjust_germ_level(-antibiotics) // You waited this long to get treated, you don't really deserve this organ
//Adds autopsy data for used_weapon.
/obj/item/organ/proc/add_autopsy_data(var/used_weapon, var/damage)
@@ -304,7 +345,7 @@ var/list/organ_cache = list()
//only show this if the organ is not robotic
if(owner && parent_organ && amount > 0)
var/obj/item/organ/external/parent = owner.get_organ(parent_organ)
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.", amount)
@@ -322,6 +363,7 @@ var/list/organ_cache = list()
robotic = ORGAN_ASSISTED
min_bruised_damage = 15
min_broken_damage = 35
butcherable = FALSE
/obj/item/organ/proc/digitize() //Used to make the circuit-brain. On this level in the event more circuit-organs are added/tweaks are wanted.
robotize()
@@ -341,31 +383,30 @@ var/list/organ_cache = list()
take_damage(rand(1,3))
/obj/item/organ/proc/removed(var/mob/living/user)
if(owner)
owner.internal_organs_by_name[organ_tag] = null
owner.internal_organs_by_name -= organ_tag
owner.internal_organs_by_name -= null
owner.internal_organs -= src
if(!istype(owner))
return
var/obj/item/organ/external/affected = owner.get_organ(parent_organ)
if(affected) affected.internal_organs -= src
owner.internal_organs_by_name[organ_tag] = null
owner.internal_organs_by_name -= organ_tag
owner.internal_organs_by_name -= null
owner.internal_organs -= src
forceMove(owner.drop_location())
START_PROCESSING(SSobj, src)
rejecting = null
var/obj/item/organ/external/affected = owner.get_organ(parent_organ)
if(affected) affected.internal_organs -= src
if(istype(owner))
var/datum/reagent/blood/organ_blood = locate(/datum/reagent/blood) in reagents.reagent_list
if(!organ_blood || !organ_blood.data["blood_DNA"])
owner.vessel.trans_to(src, 5, 1, 1)
forceMove(owner.drop_location())
START_PROCESSING(SSobj, src)
rejecting = null
var/datum/reagent/blood/organ_blood = locate(/datum/reagent/blood) in reagents.reagent_list
if(!organ_blood || !organ_blood.data["blood_DNA"])
owner.vessel.trans_to(src, 5, 1, 1)
if(owner && vital)
if(user)
add_attack_logs(user, owner, "Removed vital organ [src.name]")
if(owner.stat != DEAD)
owner.can_defib = 0
owner.death()
if(owner && vital)
if(user)
add_attack_logs(user, owner, "Removed vital organ [src.name]")
if(owner.stat != DEAD)
owner.can_defib = 0
owner.death()
handle_organ_mod_special(TRUE)
@@ -379,13 +420,13 @@ var/list/organ_cache = list()
var/datum/reagent/blood/transplant_blood = locate(/datum/reagent/blood) in reagents.reagent_list
transplant_data = list()
if(!transplant_blood)
transplant_data["species"] = target.species.name
transplant_data["blood_type"] = target.dna.b_type
transplant_data["blood_DNA"] = target.dna.unique_enzymes
transplant_data["species"] = target?.species.name
transplant_data["blood_type"] = target?.dna.b_type
transplant_data["blood_DNA"] = target?.dna.unique_enzymes
else
transplant_data["species"] = transplant_blood.data["species"]
transplant_data["blood_type"] = transplant_blood.data["blood_type"]
transplant_data["blood_DNA"] = transplant_blood.data["blood_DNA"]
transplant_data["species"] = transplant_blood?.data["species"]
transplant_data["blood_type"] = transplant_blood?.data["blood_type"]
transplant_data["blood_DNA"] = transplant_blood?.data["blood_DNA"]
owner = target
loc = owner
@@ -428,6 +469,46 @@ var/list/organ_cache = list()
bitten(user)
return
/obj/item/organ/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(can_butcher(W, user))
butcher(W, user)
return
return ..()
/obj/item/organ/proc/can_butcher(var/obj/item/O, var/mob/living/user)
if(butcherable && meat_type)
if(istype(O, /obj/machinery/gibber)) // The great equalizer.
return TRUE
if(robotic >= ORGAN_ROBOT)
if(O.is_screwdriver())
return TRUE
else
if(is_sharp(O) && has_edge(O))
return TRUE
return FALSE
/obj/item/organ/proc/butcher(var/obj/item/O, var/mob/living/user, var/atom/newtarget)
if(robotic >= ORGAN_ROBOT)
user?.visible_message("<span class='notice'>[user] disassembles \the [src].</span>")
else
user?.visible_message("<span class='notice'>[user] butchers \the [src].</span>")
if(!newtarget)
newtarget = get_turf(src)
var/obj/item/newmeat = new meat_type(newtarget)
if(istype(newmeat, /obj/item/weapon/reagent_containers/food/snacks/meat))
newmeat.name = "[src.name] [newmeat.name]" // "liver meat" "heart meat", etc.
qdel(src)
/obj/item/organ/proc/organ_can_feel_pain()
if(species.flags & NO_PAIN)
return 0
+16 -12
View File
@@ -34,7 +34,8 @@
var/body_part = null // Part flag
var/icon_position = 0 // Used in mob overlay layering calculations.
var/model // Used when caching robolimb icons.
var/force_icon // Used to force override of species-specific limb icons (for prosthetics).
var/force_icon // Used to force override of species-specific limb icons (for prosthetics). Also used for any limbs chopped from a simple mob, and then attached to humans.
var/force_icon_key // Used to force the override of the icon-key generated using the species. Must be used in tandem with the above.
var/icon/mob_icon // Cached icon for use in mob overlays.
var/gendered_icon = 0 // Whether or not the icon state appends a gender.
var/s_tone // Skin tone.
@@ -97,7 +98,7 @@
qdel(splinted)
splinted = null
if(owner)
if(istype(owner))
owner.organs -= src
owner.organs_by_name[organ_tag] = null
owner.organs_by_name -= organ_tag
@@ -199,7 +200,7 @@
return
dislocated = 1
if(owner)
if(istype(owner))
owner.verbs |= /mob/living/carbon/human/proc/relocate
/obj/item/organ/external/proc/relocate()
@@ -207,7 +208,7 @@
return
dislocated = 0
if(owner)
if(istype(owner))
owner.shock_stage += 20
//check to see if we still need the verb
@@ -221,7 +222,7 @@
/obj/item/organ/external/New(var/mob/living/carbon/holder)
..(holder, 0)
if(owner)
if(istype(owner))
replaced(owner)
sync_colour_to_human(owner)
spawn(1)
@@ -887,11 +888,11 @@ Note that amputating the affected organ does in fact remove the infection from t
var/mob/living/carbon/human/victim = owner //Keep a reference for post-removed().
var/obj/item/organ/external/parent_organ = parent
var/use_flesh_colour = species.get_flesh_colour(owner)
var/use_blood_colour = species.get_blood_colour(owner)
var/use_flesh_colour = species?.get_flesh_colour(owner) ? species.get_flesh_colour(owner) : "#C80000"
var/use_blood_colour = species?.get_blood_colour(owner) ? species.get_blood_colour(owner) : "#C80000"
removed(null, ignore_children)
victim.traumatic_shock += 60
victim?.traumatic_shock += 60
if(parent_organ)
var/datum/wound/lost_limb/W = new (src, disintegrate, clean)
@@ -907,9 +908,12 @@ Note that amputating the affected organ does in fact remove the infection from t
stump.update_damages()
spawn(1)
victim.updatehealth()
victim.UpdateDamageIcon()
victim.update_icons_body()
if(istype(victim))
victim.updatehealth()
victim.UpdateDamageIcon()
victim.update_icons_body()
else
victim.update_icons()
dir = 2
var/atom/droploc = victim.drop_location()
@@ -1236,7 +1240,7 @@ Note that amputating the affected organ does in fact remove the infection from t
organ.loc = src
// Remove parent references
parent.children -= src
parent?.children -= src
parent = null
release_restraints(victim)
+5 -2
View File
@@ -58,7 +58,7 @@ var/global/list/limb_icon_cache = list()
cut_overlays()
//Every 'addon' below requires information from species
if(!owner || !owner.species)
if(!iscarbon(owner) || !owner.species)
return
//Eye color/icon
@@ -135,7 +135,10 @@ var/global/list/limb_icon_cache = list()
if(owner && owner.gender == FEMALE)
gender = "f"
icon_cache_key = "[icon_name]_[species ? species.get_bodytype() : SPECIES_HUMAN]" //VOREStation Edit
if(!force_icon_key)
icon_cache_key = "[icon_name]_[species ? species.get_bodytype() : SPECIES_HUMAN]" //VOREStation Edit
else
icon_cache_key = "[icon_name]_[force_icon_key]"
if(force_icon)
mob_icon = new /icon(force_icon, "[icon_name][gendered_icon ? "_[gender]" : ""]")
+1
View File
@@ -38,6 +38,7 @@
var/brain_type = /obj/item/device/mmi
var/obj/item/device/mmi/stored_mmi
robotic = ORGAN_ASSISTED
butcherable = FALSE
/obj/item/organ/internal/mmi_holder/Destroy()
if(stored_mmi && (stored_mmi.loc == src))
+9 -8
View File
@@ -282,14 +282,15 @@
/obj/item/organ/external/head/removed()
if(owner)
name = "[owner.real_name]'s head"
owner.drop_from_inventory(owner.glasses)
owner.drop_from_inventory(owner.head)
owner.drop_from_inventory(owner.l_ear)
owner.drop_from_inventory(owner.r_ear)
owner.drop_from_inventory(owner.wear_mask)
spawn(1)
owner.update_hair()
if(iscarbon(owner))
name = "[owner.real_name]'s head"
owner.drop_from_inventory(owner.glasses)
owner.drop_from_inventory(owner.head)
owner.drop_from_inventory(owner.l_ear)
owner.drop_from_inventory(owner.r_ear)
owner.drop_from_inventory(owner.wear_mask)
spawn(1)
owner.update_hair()
get_icon()
..()
@@ -112,7 +112,7 @@
var/can_hold_val = 0
loading = TRUE
while(mat_storage + SHEET_MATERIAL_AMOUNT <= max_mat_storage && do_after(user,1.5 SECONDS))
while(can_hold_val < M.amount && mat_storage + SHEET_MATERIAL_AMOUNT <= max_mat_storage && do_after(user,1.5 SECONDS)) //CHOMPEdit
can_hold_val ++
mat_storage += SHEET_MATERIAL_AMOUNT
playsound(src, 'sound/effects/phasein.ogg', 15, 1)
@@ -0,0 +1,243 @@
//automatic.dm
/obj/item/weapon/gun/projectile/automatic
bolt_name="charging handle"
/obj/item/weapon/gun/projectile/automatic/advanced_smg
muzzle_velocity = 390 //Based off MPX
/obj/item/weapon/gun/projectile/automatic/c20r
muzzle_velocity = 285 //Based off UMP-45, since apparently this 10mm smg fires .45 ftw. May be fixed in future updates.
/obj/item/weapon/gun/projectile/automatic/sts35
muzzle_velocity = 900 //Based off AK-74
/obj/item/weapon/gun/projectile/automatic/wt550
muzzle_velocity = 375 //Guestimation
/obj/item/weapon/gun/projectile/automatic/z8
muzzle_velocity = 750 //Based off HK417 16 in barrel.
/obj/item/weapon/gun/projectile/automatic/l6_saw
bolt_name="charging handle"
auto_loading_type = OPEN_BOLT
muzzle_velocity = 960 //Prototype PU-21(https://en.wikipedia.org/wiki/IP-2)
/obj/item/weapon/gun/projectile/automatic/as24
muzzle_velocity = 470 //Temporary, might be changed.
/obj/item/weapon/gun/projectile/automatic/mini_uzi
auto_loading_type = OPEN_BOLT
muzzle_velocity = 280 //Mac-10 .45
/obj/item/weapon/gun/projectile/automatic/p90 //Finally a gun that exists irl. oh wait fuck they decided to chamber the p90 in 9mm kms
muzzle_velocity = 397 //Guestimation. Will hopefully be able to replace with actual 5.7mm at some point.
/obj/item/weapon/gun/projectile/automatic/tommygun //Phew, an actual gun that fires the correct cartridge.
auto_loading_type = OPEN_BOLT
muzzle_velocity = 285
/obj/item/weapon/gun/projectile/automatic/bullpup
muzzle_velocity = 880 //7.62 NATO Bullpup was unsurprisingly difficult to find https://en.wikipedia.org/wiki/Kel-Tec_RFB
/obj/item/weapon/gun/projectile/automatic/combatsmg
muzzle_velocity = 370 //Guestimation
//automatic_vr.dm
/obj/item/weapon/gun/projectile/automatic/battlerifle
muzzle_velocity = 370 //Not a real rifle or cartridge. Guestimating.
/obj/item/weapon/gun/projectile/automatic/pdw
muzzle_velocity = 390 //MPX
/obj/item/weapon/gun/projectile/automatic/stg
muzzle_velocity = 685 //STG-44
/obj/item/weapon/gun/projectile/automatic/sol
muzzle_velocity = 380 //Guestimation
//automatic_yw.dm
/obj/item/weapon/gun/projectile/automatic/mg42
bolt_name="charging handle"
auto_loading_type = OPEN_BOLT
bolt_release = null
muzzle_velocity = 740 //Real gun.
//boltaction.dm
/obj/item/weapon/gun/projectile/shotgun/pump/rifle
muzzle_velocity = 860 //Guestimation
//caseless.dm
/obj/item/weapon/gun/projectile/caseless
bolt_name="charging handle"
muzzle_velocity = 380 //Based of 9mm, because this fires 9mm projectiles. Will be fixed in future updates, likely.
//contender.dm
/obj/item/weapon/gun/projectile/contender //To be updated to use .357
manual_chamber = FALSE
muzzle_velocity = 370
//dartgun.dm
/obj/item/weapon/gun/projectile/dartgun
manual_chamber = FALSE
//pistol.dm
/obj/item/weapon/gun/projectile/colt
bolt_name="slide"
bolt_release = "slide release"
auto_loading_type = CLOSED_BOLT | LOCK_OPEN_EMPTY
muzzle_velocity = 253 //M1911
/obj/item/weapon/gun/projectile/sec
bolt_name="slide"
bolt_release = "slide release"
auto_loading_type = CLOSED_BOLT | LOCK_OPEN_EMPTY
muzzle_velocity = 253 //M1911
/obj/item/weapon/gun/projectile/silenced
bolt_name="slide"
bolt_release = "slide release"
auto_loading_type = CLOSED_BOLT | LOCK_OPEN_EMPTY
muzzle_velocity = 240 //Guestimation, minus velocity for suppressor
/obj/item/weapon/gun/projectile/deagle
bolt_name="slide"
bolt_release = "slide release"
auto_loading_type = CLOSED_BOLT | LOCK_OPEN_EMPTY
muzzle_velocity = 430 //Guestimation, everyone uses .50AE lol
/obj/item/weapon/gun/projectile/gyropistol
bolt_name="slide"
bolt_release = "slide release"
auto_loading_type = CLOSED_BOLT | LOCK_OPEN_EMPTY
/obj/item/weapon/gun/projectile/pistol
bolt_name="slide"
bolt_release = "slide release"
auto_loading_type = CLOSED_BOLT | LOCK_OPEN_EMPTY
muzzle_velocity = 300 //P365
/obj/item/weapon/gun/projectile/pirate
manual_chamber = FALSE
/obj/item/weapon/gun/projectile/derringer
manual_chamber = FALSE
muzzle_velocity = 350 //Guestimation
/obj/item/weapon/gun/projectile/luger
bolt_name="slide"
bolt_release = "slide release"
auto_loading_type = CLOSED_BOLT | LOCK_OPEN_EMPTY
muzzle_velocity = 350 //Luger
/obj/item/weapon/gun/projectile/p92x
bolt_name="slide"
bolt_release = "slide release"
auto_loading_type = CLOSED_BOLT | LOCK_OPEN_EMPTY
muzzle_velocity = 370
//pistol_vr.dm
/obj/item/weapon/gun/projectile/lamia
bolt_name="slide"
bolt_release = "slide release"
auto_loading_type = CLOSED_BOLT | LOCK_OPEN_EMPTY
muzzle_velocity = 400 //Guestimation
/obj/item/weapon/gun/projectile/giskard //To be updated to .380
bolt_name="slide"
bolt_release = "slide release"
auto_loading_type = CLOSED_BOLT | LOCK_OPEN_EMPTY
muzzle_velocity = 300 //Guestimation
//pistol_yw.dm
/obj/item/weapon/gun/projectile/automatic/glock
bolt_name="slide"
bolt_release = "slide release"
auto_loading_type = CLOSED_BOLT | LOCK_OPEN_EMPTY
muzzle_velocity = 375 //Actual gun.
/obj/item/weapon/gun/projectile/ppk
bolt_name="slide"
bolt_release = "slide release"
auto_loading_type = CLOSED_BOLT | LOCK_OPEN_EMPTY
muzzle_velocity = 310 //Guestimation since PPK doesn't fire 9mm
/obj/item/weapon/gun/projectile/m2024
bolt_name="slide"
bolt_release = "slide release"
auto_loading_type = CLOSED_BOLT | LOCK_OPEN_EMPTY
muzzle_velocity = 260 //Guestimation
/obj/item/weapon/gun/projectile/fluff/m1911
bolt_name="slide"
bolt_release = "slide release"
auto_loading_type = CLOSED_BOLT | LOCK_OPEN_EMPTY
muzzle_velocity = 253 //M1911
//revolver.dm
/obj/item/weapon/gun/projectile/revolver //To be updated to use .375
manual_chamber = FALSE
muzzle_velocity = 330 //Guestimation
/obj/item/weapon/gun/projectile/revolver/detective //To be updated to use .38
muzzle_velocity = 350 //Guestimation
/obj/item/weapon/gun/projectile/revolver/detective45 //Awful.
muzzle_velocity = 230 //Guestimation
/obj/item/weapon/gun/projectile/revolver/deckard //To be updated to use .38
muzzle_velocity = 365
/obj/item/weapon/gun/projectile/revolver/judge
muzzle_velocity = 440 //Temporary
/obj/item/weapon/gun/projectile/revolver/lemat
muzzle_velocity = 365
/obj/item/weapon/gun/projectile/revolver/webley
muzzle_velocity = 340 //Guestimation
/obj/item/weapon/gun/projectile/revolver/consul
muzzle_velocity = 350 //Guestimation
/obj/item/weapon/gun/projectile/revolver/nova
muzzle_velocity = 330 //Guestimation
/obj/item/weapon/gun/projectile/revolver/cerberus
muzzle_velocity = 340 //Guestimation
//semiauto.dm
/obj/item/weapon/gun/projectile/garand //To be updated to use .30 springfield.
bolt_name="charging handle"
auto_loading_type = CLOSED_BOLT | LOCK_OPEN_EMPTY | CHAMBER_ON_RELOAD
bolt_release = null
muzzle_velocity = 853 //Actual gun.
/obj/item/weapon/gun/projectile/revolvingrifle
manual_chamber = FALSE
muzzle_velocity = 500 //Guestimation from leveraction .44 minus some for being a revolver.
//shotgun.dm
/obj/item/weapon/gun/projectile/shotgun
muzzle_velocity = 470 //Temporary
/obj/item/weapon/gun/projectile/shotgun/pump
manual_chamber = FALSE
/obj/item/weapon/gun/projectile/shotgun/doublebarrel
manual_chamber = FALSE
//shotgun_yw.dm
/obj/item/weapon/gun/projectile/revolvershotgun
manual_chamber = FALSE
muzzle_velocity = 470 //Temporary
//sniper.dm
/obj/item/weapon/gun/projectile/heavysniper
manual_chamber = FALSE
muzzle_velocity = 1132 //Istiglal IST-14.5 anti-materiel rifle
/obj/item/weapon/gun/projectile/SVD //To be updated to use actual 7.62x54 instead of 7.62 NATO
bolt_name = "charging handle"
muzzle_velocity = 830 //Actual gun.
@@ -22,7 +22,7 @@
scoped_accuracy = 75
ignore_visor_zoom_restriction = TRUE // Ignore the restriction on vision modifiers when using this gun's scope.
one_handed_penalty = 90
var/bolt_open = 0
bolt_open = 0 //CHOMPEdit
/obj/item/weapon/gun/projectile/heavysniper/update_icon()
if(bolt_open)
@@ -0,0 +1,447 @@
#define NO_AUTO_LOAD 0
#define OPEN_BOLT 1
#define CLOSED_BOLT 2
#define LOCK_OPEN_EMPTY 4
#define LOCK_MANUAL_LOCK 8
#define LOCK_SLAPPABLE 16
#define CHAMBER_ON_RELOAD 32
#define BOLT_NOEVENT 0
#define BOLT_CLOSED 1
#define BOLT_OPENED 2
#define BOLT_LOCKED 4
#define BOLT_UNLOCKED 8
#define BOLT_CASING_EJECTED 16
#define BOLT_CASING_CHAMBERED 32
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////// CADYN'S BALLISTICS ////////////////////////////////////////////////////////////////////////// ORIGINAL FROM CHOMPSTATION ////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/obj/item/weapon/gun/projectile
var/manual_chamber = TRUE
var/auto_loading_type = CLOSED_BOLT | LOCK_MANUAL_LOCK | LOCK_SLAPPABLE
var/bolt_name = "bolt"
var/bolt_open = FALSE
var/bolt_locked = FALSE
var/bolt_release = "bolt release"
var/muzzle_velocity = 500 // meters per second
/obj/item/weapon/gun/projectile/handle_post_fire(mob/user, atom/target, var/pointblank=0, var/reflex=0)
if(fire_anim)
flick(fire_anim, src)
if(muzzle_flash)
set_light(muzzle_flash)
if(one_handed_penalty)
if(!src.is_held_twohanded(user))
switch(one_handed_penalty)
if(1 to 15)
if(prob(50)) //don't need to tell them every single time
to_chat(user, "<span class='warning'>Your aim wavers slightly.</span>")
if(16 to 30)
to_chat(user, "<span class='warning'>Your aim wavers as you fire \the [src] with just one hand.</span>")
if(31 to 45)
to_chat(user, "<span class='warning'>You have trouble keeping \the [src] on target with just one hand.</span>")
if(46 to INFINITY)
to_chat(user, "<span class='warning'>You struggle to keep \the [src] on target with just one hand!</span>")
else if(!user.can_wield_item(src))
switch(one_handed_penalty)
if(1 to 15)
if(prob(50)) //don't need to tell them every single time
to_chat(user, "<span class='warning'>Your aim wavers slightly.</span>")
if(16 to 30)
to_chat(user, "<span class='warning'>Your aim wavers as you try to hold \the [src] steady.</span>")
if(31 to 45)
to_chat(user, "<span class='warning'>You have trouble holding \the [src] steady.</span>")
if(46 to INFINITY)
to_chat(user, "<span class='warning'>You struggle to hold \the [src] steady!</span>")
if(recoil)
spawn()
shake_camera(user, recoil+1, recoil)
update_icon()
if(chambered)
chambered.expend()
if(!manual_chamber) process_chambered()
if(manual_chamber)
bolt_toggle()
/obj/item/weapon/gun/projectile/attack_self(mob/user as mob)
if(manual_chamber)
if(do_after(user,4))
bolt_handle(user)
else if(firemodes.len > 1)
switch_firemodes(user)
else
unload_ammo(user)
/obj/item/weapon/gun/projectile/proc/bolt_handle(mob/user)
var/previous_chambered = chambered
var/result = bolt_toggle(TRUE)
if(!result)
to_chat(user,"<span class='notice'>Nothing happens.</span>")
else
var/closed = CHECK_BITFIELD(result,BOLT_CLOSED)
var/opened = CHECK_BITFIELD(result,BOLT_OPENED)
var/locked = CHECK_BITFIELD(result,BOLT_LOCKED)
var/unlocked = CHECK_BITFIELD(result,BOLT_UNLOCKED)
var/casing_ejected = CHECK_BITFIELD(result,BOLT_CASING_EJECTED)
var/close_open_ejected = casing_ejected ? ", which causes \the [previous_chambered] to be ejected, as well as" : ","
var/other_ejected = CHECK_BITFIELD(result,BOLT_CASING_CHAMBERED) ? " and causing \the [previous_chambered] to be ejected" : ", causing \the [previous_chambered] to be ejected"
other_ejected = casing_ejected ? other_ejected : ""
var/casing_chambered = CHECK_BITFIELD(result,BOLT_CASING_CHAMBERED) ? ", chambering a new round" : ""
if(closed && opened)
user.visible_message("<span class='notice'>[user] pulls back \the [bolt_name] before releasing it[close_open_ejected] causing it to slide forward again[casing_chambered].</span>", \
"<span class='notice'>You pull back \the [bolt_name] before releasing it[close_open_ejected] causing it to slide forward again[casing_chambered].</span>")
else if(opened)
if(locked)
if(CHECK_BITFIELD(auto_loading_type,LOCK_MANUAL_LOCK))
user.visible_message("<span class='notice'>[user] pulls back \the [bolt_name] and locks it in the open position[casing_chambered][other_ejected].</span>", \
"<span class='notice'>You pull back \the [bolt_name] and lock it in the open position[other_ejected][casing_chambered].</span>")
else
user.visible_message("<span class='notice'>[user] pulls back \the [bolt_name] before releasing it, causing it to lock in the open position[casing_chambered][other_ejected].</span>", \
"<span class='notice'>You pull back \the [bolt_name] before releasing it, causing it to lock in the open position[casing_chambered][other_ejected].</span>")
else
user.visible_message("<span class='notice'>[user] opens \the [bolt_name][casing_chambered][other_ejected].</span>", \
"<span class='notice'>You pull back \the [bolt_name][casing_chambered][other_ejected].</span>")
else if(closed)
if(unlocked)
if(bolt_release)
if(user.a_intent == I_HURT && CHECK_BITFIELD(auto_loading_type,LOCK_SLAPPABLE))
user.visible_message("<span class='notice'>[user] slaps the [bolt_release], causing \the [bolt_name] to slide forward[casing_chambered]!</span>", \
"<span class='notice'>You slap the [bolt_release], causing \the [bolt_name] to slide forward[casing_chambered]!</span>")
else
user.visible_message("<span class='notice'>[user] presses the [bolt_release], causing \the [bolt_name] to slide forward[casing_chambered].</span>", \
"<span class='notice'>You press the [bolt_release], causing \the [bolt_name] to slide forward[casing_chambered].</span>")
else
user.visible_message("<span class='notice'>[user] pulls \the [bolt_name] back the rest of the way, causing it to slide forward[casing_chambered].</span>", \
"<span class='notice'>You pull \the [bolt_name] back the rest of the way, causing it to slide forward[casing_chambered].</span>")
else
user.visible_message("<span class='notice'>[user] closes \the [bolt_name][casing_chambered].</span>", \
"<span class='notice'>You close \the [bolt_name][casing_chambered].</span>")
/obj/item/weapon/gun/projectile/proc/bolt_toggle(var/manual)
if(!bolt_open)
if(auto_loading_type)
var/able_to_lock = (CHECK_BITFIELD(auto_loading_type,LOCK_OPEN_EMPTY) || (CHECK_BITFIELD(auto_loading_type,LOCK_MANUAL_LOCK) && manual))
if(CHECK_BITFIELD(auto_loading_type,OPEN_BOLT))
bolt_open = TRUE
var/ejected = process_chambered()
var/output = BOLT_OPENED
if(ejected) output |= BOLT_CASING_EJECTED
return output
else if(loaded.len || (ammo_magazine && ammo_magazine.stored_ammo.len) || !able_to_lock)
var/ejected = process_chambered()
var/chambering = chamber_bullet()
var/output = BOLT_OPENED | BOLT_CLOSED
if(ejected) output |= BOLT_CASING_EJECTED
if(chambering) output |= BOLT_CASING_CHAMBERED
return output
else
if(!manual)
visible_message(src,"<span class='notice'>The [src] fires its last round, causing the [bolt_name] to lock.</span>")
bolt_open = TRUE
bolt_locked = TRUE
var/ejected = process_chambered()
var/output = BOLT_OPENED | BOLT_LOCKED
if(ejected) output |= BOLT_CASING_EJECTED
return output
else
bolt_open = TRUE
var/ejected = process_chambered()
var/chambering = chamber_bullet()
var/output = BOLT_OPENED
if(ejected) output |= BOLT_CASING_EJECTED
if(chambering) output |= BOLT_CASING_CHAMBERED
return output
else
if(auto_loading_type)
if(CHECK_BITFIELD(auto_loading_type,OPEN_BOLT))
if(loaded.len || (ammo_magazine && ammo_magazine.stored_ammo.len))
if(!manual)
var/ejected = process_chambered()
var/output = BOLT_CLOSED | BOLT_OPENED
if(ejected) output |= BOLT_CASING_EJECTED
return output
else
return BOLT_NOEVENT
else
bolt_open = FALSE
return BOLT_CLOSED
else if(bolt_locked)
var/chambering = FALSE
if(!chambered)
chambering = chamber_bullet()
bolt_locked = FALSE
bolt_open = FALSE
var/output = BOLT_CLOSED | BOLT_UNLOCKED
if(chambering) output |= BOLT_CASING_CHAMBERED
return output
else
bolt_open = FALSE
return BOLT_CLOSED
else
bolt_open = FALSE
return BOLT_CLOSED
/obj/item/weapon/gun/projectile/process_chambered()
if (!chambered) return 0
// Aurora forensics port, gunpowder residue.
if(chambered.leaves_residue)
var/mob/living/carbon/human/H = loc
if(istype(H))
if(!H.gloves)
H.gunshot_residue = chambered.caliber
else
var/obj/item/clothing/G = H.gloves
G.gunshot_residue = chambered.caliber
switch(handle_casings)
if(EJECT_CASINGS) //eject casing onto ground.
if(chambered.caseless)
qdel(chambered)
chambered = null
return 0
else
chambered.loc = get_turf(src)
playsound(src, "casing", 50, 1)
chambered = null
return 1
if(CYCLE_CASINGS) //cycle the casing back to the end.
if(ammo_magazine)
ammo_magazine.stored_ammo += chambered
else
loaded += chambered
chambered = null
return 0
if(handle_casings != HOLD_CASINGS)
chambered = null
return 0
/obj/item/weapon/gun/projectile/consume_next_projectile()
if(!manual_chamber)
//get the next casing
if(loaded.len)
chambered = loaded[1] //load next casing.
if(handle_casings != HOLD_CASINGS)
loaded -= chambered
else if(ammo_magazine && ammo_magazine.stored_ammo.len)
chambered = ammo_magazine.stored_ammo[ammo_magazine.stored_ammo.len]
if(handle_casings != HOLD_CASINGS)
ammo_magazine.stored_ammo -= chambered
if(manual_chamber && auto_loading_type && CHECK_BITFIELD(auto_loading_type,OPEN_BOLT) && bolt_open)
chamber_bullet()
if(chambered)
return chambered.BB
return null
/obj/item/weapon/gun/projectile/proc/chamber_bullet()
var/obj/item/ammo_casing/to_chamber
if(loaded.len)
to_chamber = loaded[1] //load next casing.
if(handle_casings != HOLD_CASINGS)
loaded -= to_chamber
else if(ammo_magazine && ammo_magazine.stored_ammo.len)
to_chamber = ammo_magazine.stored_ammo[ammo_magazine.stored_ammo.len]
if(handle_casings != HOLD_CASINGS)
ammo_magazine.stored_ammo -= to_chamber
chambered = to_chamber
if(to_chamber)
return 1
else
return 0
/obj/item/weapon/gun/projectile/load_ammo(var/obj/item/A, mob/user)
if(istype(A, /obj/item/ammo_magazine))
var/obj/item/ammo_magazine/AM = A
if(!(load_method & AM.mag_type) || caliber != AM.caliber || allowed_magazines && !is_type_in_list(A, allowed_magazines))
to_chat(user, "<span class='warning'>[AM] won't load into [src]!</span>")
return
switch(AM.mag_type)
if(MAGAZINE)
if(ammo_magazine)
to_chat(user, "<span class='warning'>[src] already has a magazine loaded.</span>") //already a magazine here
return
if(manual_chamber && CHECK_BITFIELD(auto_loading_type,OPEN_BOLT) && bolt_open)
to_chat(user, "<span class='warning'>This is an open bolt gun. Make sure you close the bolt before inserting a new magazine.</span>")
return
user.remove_from_mob(AM)
AM.loc = src
ammo_magazine = AM
user.visible_message("[user] inserts [AM] into [src].", "<span class='notice'>You insert [AM] into [src].</span>")
if(manual_chamber && CHECK_BITFIELD(auto_loading_type,CHAMBER_ON_RELOAD) && bolt_open && !chambered)
chamber_bullet()
bolt_toggle()
playsound(src, 'sound/weapons/flipblade.ogg', 50, 1)
if(SPEEDLOADER)
if(loaded.len >= max_shells)
to_chat(user, "<span class='warning'>[src] is full!</span>")
return
var/count = 0
for(var/obj/item/ammo_casing/C in AM.stored_ammo)
if(loaded.len >= max_shells)
break
if(C.caliber == caliber)
C.loc = src
loaded += C
AM.stored_ammo -= C //should probably go inside an ammo_magazine proc, but I guess less proc calls this way...
count++
if(count)
user.visible_message("[user] reloads [src].", "<span class='notice'>You load [count] round\s into [src].</span>")
playsound(src, 'sound/weapons/empty.ogg', 50, 1)
AM.update_icon()
else if(istype(A, /obj/item/ammo_casing))
var/obj/item/ammo_casing/C = A
if(caliber != C.caliber)
return
if(!(load_method & SINGLE_CASING))
if(manual_chamber)
if(!CHECK_BITFIELD(auto_loading_type,OPEN_BOLT))
if(!chambered)
if(bolt_open)
if(do_after(user,5))
user.visible_message("<span class='notice'>[user] slides \the [C] into the [src]'s chamber.</span>","<span class='notice'>You slide \the [C] into the [src]'s chamber.</span>")
chambered = C
else
return
else if(!(CHECK_BITFIELD(auto_loading_type,LOCK_OPEN_EMPTY) || (CHECK_BITFIELD(auto_loading_type,LOCK_MANUAL_LOCK))))
if(do_after(user,15))
user.visible_message("<span class='notice'>[user] holds open \the [src]'s [bolt_name] and slides [C] into the chamber before letting the bolt close again.</span>","<span class='notice'>You slide \the [C] into the [src]'s chamber.</span>")
chambered = C
else
return
else
to_chat(user,"<span class='warning'>Open the bolt first before chambering a round!</span>")
return
else
to_chat(user,"<span class='warning'>Eject the current chambered round before trying to chamber a new one!</span>")
return
else
to_chat(user,"<span class='warning'>You can't manually chamber rounds with an open bolt gun!</span>")
return
user.remove_from_mob(C)
C.loc = src
update_icon()
return
else
return
if(loaded.len >= max_shells)
to_chat(user, "<span class='warning'>[src] is full.</span>")
return
user.remove_from_mob(C)
C.loc = src
loaded.Insert(1, C) //add to the head of the list
user.visible_message("[user] inserts \a [C] into [src].", "<span class='notice'>You insert \a [C] into [src].</span>")
playsound(src, 'sound/weapons/empty.ogg', 50, 1)
else if(istype(A, /obj/item/weapon/storage))
var/obj/item/weapon/storage/storage = A
if(!(load_method & SINGLE_CASING))
return //incompatible
to_chat(user, "<span class='notice'>You start loading \the [src].</span>")
sleep(1 SECOND)
for(var/obj/item/ammo_casing/ammo in storage.contents)
if(caliber != ammo.caliber)
continue
load_ammo(ammo, user)
if(loaded.len >= max_shells)
to_chat(user, "<span class='warning'>[src] is full.</span>")
break
sleep(1 SECOND)
update_icon()
/obj/item/weapon/gun/projectile/afterattack(atom/A, mob/living/user, adjacent, params)
afteratt(A,user,adjacent,params)
if(auto_eject && ammo_magazine && ammo_magazine.stored_ammo && !ammo_magazine.stored_ammo.len && !(manual_chamber && chambered && chambered.BB != null))
ammo_magazine.loc = get_turf(src.loc)
user.visible_message(
"[ammo_magazine] falls out and clatters on the floor!",
"<span class='notice'>[ammo_magazine] falls out and clatters on the floor!</span>"
)
if(auto_eject_sound)
playsound(src, auto_eject_sound, 40, 1)
ammo_magazine.update_icon()
ammo_magazine = null
update_icon()
/obj/item/weapon/gun/projectile/proc/afteratt(atom/A, mob/living/user, adjacent, params)
if(adjacent) return //A is adjacent, is the user, or is on the user's person
if(!user.aiming)
user.aiming = new(user)
if(user && user.client && user.aiming && user.aiming.active && user.aiming.aiming_at != A)
PreFire(A,user,params) //They're using the new gun system, locate what they're aiming at.
return
if(user && user.a_intent == I_HELP && user.is_preference_enabled(/datum/client_preference/safefiring)) //regardless of what happens, refuse to shoot if help intent is on
to_chat(user, "<span class='warning'>You refrain from firing your [src] as your intent is set to help.</span>")
return
else
Fire(A, user, params) //Otherwise, fire normally.
return
/obj/item/weapon/gun/projectile/special_check(var/mob/user)
if(..())
if(manual_chamber)
if(CHECK_BITFIELD(auto_loading_type,OPEN_BOLT) && !bolt_open)
to_chat(user,"<span class='warning'>This is an open bolt gun! You need to open the bolt before firing it!</span>")
return 0
else if(CHECK_BITFIELD(auto_loading_type,CLOSED_BOLT) && bolt_open)
to_chat(user,"<span class='warning'>This is a closed bolt gun! You need to close the bolt before firing it!</span>")
return 0
else
return 1
else
return 1
/obj/item/weapon/gun/projectile/New(loc, var/starts_loaded = 1)
..()
if(manual_chamber)
verbs |= /obj/item/weapon/gun/projectile/verb/change_firemode
update_icon()
/obj/item/weapon/gun/projectile/verb/change_firemode()
set name = "Switch firemode"
set category = "Object"
set src in view(1)
switch_firemodes(usr)
/obj/item/weapon/gun/projectile/process_accuracy(obj/projectile, mob/living/user, atom/target, var/burst, var/held_twohanded)
. = ..()
var/obj/item/projectile/bullet/P = projectile
if(!istype(P))
return
P.velocity = muzzle_velocity
//Special ammo handling bullshit
/obj/item/weapon/gun/projectile/pirate/process_accuracy(obj/projectile, mob/living/user, atom/target, var/burst, var/held_twohanded)
. = ..()
var/obj/item/projectile/bullet/P = projectile
if(!istype(P))
return
P.sub_velocity(P.velocity * 0.3) //Yeah, a gun that supposedly shoots any bullet is gonna be pretty shit.
/obj/item/weapon/gun/projectile/revolver/lemat/process_accuracy(obj/projectile, mob/living/user, atom/target, var/burst, var/held_twohanded)
. = ..()
var/obj/item/projectile/bullet/P = projectile
P.velocity = initial(P.velocity)
if(!istype(P))
return
P.sub_velocity(P.velocity - 35)
+7
View File
@@ -581,6 +581,13 @@
if(check_penetrate(A))
passthrough = TRUE
penetrating--
//CHOMPEdit Begin
var/obj/item/projectile/bullet/this = src
if(istype(this))
if(!this.velocity)
passthrough = FALSE
penetrating = 0
//CHOMPEdit End
if(passthrough)
trajectory_ignore_forcemove = TRUE
@@ -0,0 +1,191 @@
#define GRAINS_PER_KG 15432.4
/obj/item/projectile/bullet
var/diam = 9 //mm
var/energy_add = 0
var/velocity = 500 //Meters per second
var/hollow_point = FALSE
var/grains = 115 //I hope the unit is obvious
var/energy //Joules
var/old_bullet_act = FALSE
/obj/item/projectile/bullet/launch_projectile(atom/target, target_zone, mob/user, params, angle_override, forced_spread = 0)
energy = 0.5 * velocity * velocity * (grains / GRAINS_PER_KG) + energy_add
sub_energy(0)
return ..()
/obj/item/projectile/bullet/proc/sub_velocity(var/amount)
velocity = max(0,velocity - amount)
energy = 0.5 * velocity * velocity * (grains / GRAINS_PER_KG)
/obj/item/projectile/bullet/proc/sub_energy(var/amount)
energy = max(0,energy - amount)
velocity = sqrt(2*energy/(grains / GRAINS_PER_KG))
//Pistol projectiles
/obj/item/projectile/bullet/pistol //9x19mm
diam = 9
grains = 108
velocity = 381
/obj/item/projectile/bullet/pistol/ap
grains = 66
energy_add = 893
velocity = 595
armor_penetration = 25
/obj/item/projectile/bullet/pistol/hp
grains = 131
velocity = 350
energy_add = -96.18
hollow_point = TRUE
armor_penetration = -50
/obj/item/projectile/bullet/pistol/medium //.45
diam = 11.43
grains = 230
velocity = 295
/obj/item/projectile/bullet/pistol/medium/ap
grains = 173
energy_add = 374
velocity = 347
armor_penetration = 25
/obj/item/projectile/bullet/pistol/medium/hp
grains = 230
velocity = 286
armor_penetration = -50
/obj/item/projectile/bullet/pistol/strong //.357 and .44 are grouped because ftw
grains = 240
velocity = 360
//Shotgun projectiles
/obj/item/projectile/bullet/shotgun //Slug
grains = 657
velocity = 489
armor_penetration = -50 //Slugs needed a nerf. Will probably fix the stats for shotguns in general in future updates.
/obj/item/projectile/bullet/shotgun/buckshot //#00 Buckshot
damage = 5
name = "buckshot pellet"
diam = 8.38
grains = 53.8
velocity = 489
armor_penetration = -30
/obj/item/projectile/bullet/shotgun/buckshot/shell
use_submunitions = TRUE
submunition_spread_max = 67.5
submunitions = list(/obj/item/projectile/bullet/shotgun/buckshot = 8)
/obj/item/ammo_casing/a12g/pellet
name = "shotgun buckshot shell"
desc = "A 12 gauge buckshot shell."
icon_state = "gshell"
projectile_type = /obj/item/projectile/bullet/shotgun/buckshot/shell
//Rifle projectiles
/obj/item/projectile/bullet/rifle
armor_penetration = 0 //No. Rifle rounds don't get extra AP by default, their nature already makes them more armor penetrating.
/obj/item/projectile/bullet/rifle/a762 //7.62x51 NATO
diam = 7.62
grains = 147
velocity = 850
/obj/item/projectile/bullet/rifle/a762/ap
grains = 150.5
velocity = 854.6
armor_penetration = 50
/obj/item/projectile/bullet/rifle/a762/hp
grains = 175
energy_add = -539.978
velocity = 792
armor_penetration = -50
hollow_point = TRUE
/obj/item/projectile/bullet/rifle/a545
diam = 5.45
grains = 53
velocity = 880
/obj/item/projectile/bullet/rifle/a545/ap
grains = 57
velocity = 890
armor_penetration = 50
/obj/item/projectile/bullet/rifle/a545/hp
hollow_point = TRUE
armor_penetration = -50
/obj/item/projectile/bullet/rifle/a145 // 14.5×114mm
grains = 921
velocity = 1000
/obj/item/projectile/bullet/rifle/a145/highvel
grains = 700
energy_add = 9979
velocity = 1200
/obj/item/projectile/bullet/rifle/a44rifle
diam = 10.9
grains = 240
velocity = 536.448
/obj/item/projectile/bullet/rifle/a95 //I hate you. There is no real world analog for 9.5x40mm, I will guestimate from the 9x39mm russian round and give it some bonus for future points or whatever
diam = 9.5
grains = 310
velocity = 365
/obj/item/projectile/bullet/rifle/a762/lmg //This is actually 7.92x57 ffs
diam = 7.92
grains = 181
velocity = 820
//Various "We're not dealing with this shit because of how bad it is" (Some of these may be implemented into the new system with later updates)
/obj/item/projectile/bullet/magnetic
old_bullet_act = TRUE
/obj/item/projectile/bullet/pellet
old_bullet_act = TRUE
/obj/item/projectile/bullet/pellet/shotgun/flak
old_bullet_act = TRUE
/obj/item/projectile/bullet/rifle/a762/hunter
old_bullet_act = TRUE
/obj/item/projectile/bullet/rifle/a545/hunter
old_bullet_act = TRUE
/obj/item/projectile/bullet/suffocationbullet
old_bullet_act = TRUE
/obj/item/projectile/bullet/cyanideround
old_bullet_act = TRUE
/obj/item/projectile/bullet/burstbullet
old_bullet_act = TRUE
/obj/item/projectile/bullet/incendiary
old_bullet_act = TRUE
/obj/item/projectile/bullet/practice
old_bullet_act = TRUE
/obj/item/projectile/bullet/blank
old_bullet_act = TRUE
/obj/item/projectile/bullet/srmrocket
old_bullet_act = TRUE
/obj/item/projectile/bullet/chemdart
old_bullet_act = TRUE
/obj/item/projectile/bullet/gyro
old_bullet_act = TRUE
@@ -9,4 +9,16 @@
strength = 15
glass_name = "akvavit"
glass_desc = "Burns the nose and throat, and soothes it with a herby aftertaste...Barely."
glass_desc = "Burns the nose and throat, and soothes it with a herby aftertaste...Barely."
/datum/reagent/cinnamonpowder
name = "ground cinnamon"
id = "cinnamonpowder"
description = "Cinnamon, a spice made from tree bark, ground into a fine powder. Probably not a good idea to eat on its own!"
taste_description= "sweet spice with a hint of wood"
color = "#a96622"
glass_name = "ground cinnamon"
glass_desc = "A glass of ground cinnamon. Dare you take the challenge?"
//TODO: Make eating it on its own make you cough.
@@ -48,8 +48,10 @@
/obj/machinery/biogenerator,
/obj/structure/frame,
/obj/machinery/radiocarbon_spectrometer,
/obj/machinery/portable_atmospherics/powered/reagent_distillery
/obj/machinery/portable_atmospherics/powered/reagent_distillery,
/obj/machinery/feeder
)
//CHOMP Addition for feeder in the above list. I am paranoid about comments within lists so this is outside.
/obj/item/weapon/reagent_containers/glass/Initialize()
. = ..()
+2 -2
View File
@@ -123,7 +123,7 @@
..()
name = "Phase weapon prototype ([item_name])"
/* //VOREStation Removal Start
/**/ //VOREStation Removal Start // Chomp Edit : uncomment those weapons
/datum/design/item/weapon/phase/phase_pistol
id = "phasepistol"
req_tech = list(TECH_COMBAT = 3, TECH_MATERIAL = 2, TECH_POWER = 2)
@@ -151,7 +151,7 @@
materials = list(DEFAULT_WALL_MATERIAL = 10000, "glass" = 2000, "silver" = 1000, "diamond" = 750)
build_path = /obj/item/weapon/gun/energy/phasegun/cannon
sort_string = "MACAD"
*/ //VOREStation Removal End
/**/ //VOREStation Removal End // Chomp Edit : uncomment those weapons
// Other weapons
+5 -18
View File
@@ -14,12 +14,11 @@
return 0
if(coverage_check(user,target,affected,tool))
return 0
return target_zone == BP_TORSO
return target_zone == BP_TORSO && (HUSK in target.mutations)
/datum/surgery_step/dehusk/structinitial
allowed_tools = list(
/obj/item/weapon/surgical/bioregen = 100, \
/obj/item/weapon/surgical/hemostat = 30
/obj/item/weapon/surgical/bioregen = 100
)
min_duration = 90
max_duration = 120
@@ -28,32 +27,20 @@
return ..() && target.op_stage.dehusk == 0
/datum/surgery_step/dehusk/structinitial/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
if(istype(tool,/obj/item/weapon/surgical/bioregen))
user.visible_message("<span class='notice'>[user] begins to create a fleshy but rigid looking mesh over gaps in [target]'s flesh with \the [tool].</span>", \
user.visible_message("<span class='notice'>[user] begins to create a fleshy but rigid looking mesh over gaps in [target]'s flesh with \the [tool].</span>", \
"<span class='notice'>You begin to create a fleshy but rigid looking mesh over gaps in [target]'s flesh with \the [tool].</span>")
else if(istype(tool,/obj/item/weapon/surgical/FixOVein))
user.visible_message("<span class='notice'>[user] attempts to create a mesh structure over gaps in [target]'s flesh using strands of damaged flesh with \the [tool].</span>", \
"<span class='notice'>You attempt to create a mesh structure over gaps in [target]'s flesh using strands of damaged flesh with \the [tool].</span>")
..()
/datum/surgery_step/dehusk/structinitial/end_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
if(istype(tool,/obj/item/weapon/surgical/bioregen))
user.visible_message("<span class='notice'>[user] creates a fleshy but rigid looking mesh over gaps in [target]'s flesh with \the [tool].</span>", \
user.visible_message("<span class='notice'>[user] creates a fleshy but rigid looking mesh over gaps in [target]'s flesh with \the [tool].</span>", \
"<span class='notice'>You create a fleshy but rigid looking mesh over gaps in [target]'s flesh with \the [tool].</span>")
else if(istype(tool,/obj/item/weapon/surgical/FixOVein))
user.visible_message("<span class='notice'>[user] manages to create a mesh structure over gaps in [target]'s flesh using strands of damaged flesh with \the [tool].</span>", \
"<span class='notice'>You manage to create a mesh structure over gaps in [target]'s flesh using strands of damaged flesh with \the [tool].</span>")
target.op_stage.dehusk = 1
..()
/datum/surgery_step/dehusk/structinitial/fail_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
var/obj/item/organ/external/affected = target.get_organ(target_zone)
if(istype(tool,/obj/item/weapon/surgical/bioregen))
user.visible_message("<span class='danger'>[user]'s hand slips, and the mesh falls, with \the [tool] scraping [target]'s body.</span>", \
user.visible_message("<span class='danger'>[user]'s hand slips, and the mesh falls, with \the [tool] scraping [target]'s body.</span>", \
"<span class='danger'>Your hand slips, and the mesh falls, with \the [tool] scraping [target]'s body.</span>")
else if(istype(tool,/obj/item/weapon/surgical/FixOVein))
user.visible_message("<span class='danger'>[user] fails to create a mesh structure over gaps in [target]'s flesh, the damaged flesh just falling off and doing more damage than good.</span>", \
"<span class='danger'>You fail to create a mesh structure over gaps in [target]'s flesh, the damaged flesh just falling off and doing more damage than good.</span>")
affected.createwound(CUT, 15)
affected.createwound(BRUISE, 10)
..()
+10 -3
View File
@@ -421,7 +421,7 @@
//You're in a belly!
if(isbelly(loc))
var/obj/belly/B = loc
var/confirm = alert(src, "You're in a mob. Don't use this as a trick to get out of hostile animals. This is for escaping from preference-breaking and if you're otherwise unable to escape from endo (pred AFK for a long time).", "Confirmation", "Okay", "Cancel")
var/confirm = alert(src, "Please feel free to press use this button at any time you are uncomfortable and in a belly. Consent is important.", "Confirmation", "Okay", "Cancel")
if(!confirm == "Okay" || loc != B)
return
//Actual escaping
@@ -440,7 +440,7 @@
var/mob/living/silicon/pred = loc.loc //Thing holding the belly!
var/obj/item/device/dogborg/sleeper/belly = loc //The belly!
var/confirm = alert(src, "You're in a dogborg sleeper. This is for escaping from preference-breaking or if your predator disconnects/AFKs. If your preferences were being broken, please admin-help as well.", "Confirmation", "Okay", "Cancel")
var/confirm = alert(src, "Please feel free to press use this button at any time you are uncomfortable and in a belly. Consent is important.", "Confirmation", "Okay", "Cancel")
if(!confirm == "Okay" || loc != belly)
return
//Actual escaping
@@ -501,7 +501,14 @@
return FALSE
// Prepare messages
if(user == pred) //Feeding someone to yourself
//CHOMPEdit begin
if(prey.is_slipping)
attempt_msg = "<span class='warning'>It seems like [prey] is about to slide into [pred]'s [lowertext(belly.name)]!</span>"
success_msg = "<span class='warning'>[prey] suddenly slides into [pred]'s [lowertext(belly.name)]!</span>"
else if(pred.is_slipping)
attempt_msg = "<span class='warning'>It seems like [prey] is gonna end up inside [pred]'s [lowertext(belly.name)] as [pred] comes sliding over!</span>"
success_msg = "<span class='warning'>[prey] suddenly slips inside of [pred]'s [lowertext(belly.name)] as [pred] slides into them!</span>"
else if(user == pred) //CHOMPEdit End //Feeding someone to yourself
attempt_msg = "<span class='warning'>[pred] is attempting to [lowertext(belly.vore_verb)] [prey] into their [lowertext(belly.name)]!</span>"
success_msg = "<span class='warning'>[pred] manages to [lowertext(belly.vore_verb)] [prey] into their [lowertext(belly.name)]!</span>"
else //Feeding someone to another person
+62
View File
@@ -0,0 +1,62 @@
/mob/living
var/is_slipping = FALSE
var/slip_vore_in_progress = FALSE
/mob/living/proc/can_slip_vore(var/mob/living/target)
if(!target.is_slipping) //Obviously they have to be slipping to get slip vored
return FALSE
if(!(src.can_be_drop_pred && target.devourable && target.can_be_drop_prey)) //Make sure both of their prefs align with what we're gonna do.
return FALSE
if(!is_vore_predator(src)) //Check their bellies and stuff
return FALSE
if(!src.vore_selected) //Gotta have one selected as well.
return FALSE
return TRUE
/mob/living/proc/can_be_slip_vored_by(var/mob/living/target)
if(!target.is_slipping) //Obviously they have to be slipping to get slip vored
return FALSE
if(!(target.can_be_drop_pred && src.devourable && src.can_be_drop_prey)) //Make sure both of their prefs align with what we're gonna do.
return FALSE
if(!is_vore_predator(target)) //Check their bellies and stuff
return FALSE
if(!target.vore_selected) //Gotta have one selected as well.
return FALSE
return TRUE
/mob/living/Crossed(var/atom/movable/AM)
if(AM == src || AM.is_incorporeal()) // We're not going to run over ourselves or ghosts
return
if(istype(AM, /mob/living/bot/mulebot))
var/mob/living/bot/mulebot/MB = AM
MB.runOver(src)
if(istype(AM, /obj/vehicle))
var/obj/vehicle/V = AM
V.RunOver(src)
var/mob/living/target = AM
if(istype(target) && !target.incorporeal_move && !src.incorporeal_move) //The slip vore begins
if(can_slip_vore(target) && !src.slip_vore_in_progress && !target.slip_vore_in_progress) //If we can vore them go for it
target.slip_vore_in_progress = TRUE //Make them stop slipping
perform_the_nom(src,target,src,src.vore_selected,1)
target.slip_vore_in_progress = FALSE
target.is_slipping = FALSE
else if(can_be_slip_vored_by(target) && !src.slip_vore_in_progress && !target.slip_vore_in_progress) //Otherwise, if they can vore us, make it happen.
target.slip_vore_in_progress = TRUE //Make them stop slipping
perform_the_nom(target,src,target,target.vore_selected,1)
target.slip_vore_in_progress = FALSE
target.is_slipping = FALSE
/mob/living/carbon/slip(var/slipped_on,stun_duration=8)
. = ..()
if(.)
is_slipping = TRUE
return .
/mob/living/update_canmove()
. = ..()
if(is_slipping && !lying)
is_slipping = FALSE
return .