?
This commit is contained in:
@@ -5,61 +5,6 @@
|
||||
/datum/brain_trauma/magic
|
||||
resilience = TRAUMA_RESILIENCE_LOBOTOMY
|
||||
|
||||
/datum/brain_trauma/magic/lumiphobia
|
||||
name = "Lumiphobia"
|
||||
desc = "Patient has an inexplicable adverse reaction to light."
|
||||
scan_desc = "light hypersensitivity"
|
||||
gain_text = "<span class='warning'>You feel a craving for darkness.</span>"
|
||||
lose_text = "<span class='notice'>Light no longer bothers you.</span>"
|
||||
var/next_damage_warning = 0
|
||||
|
||||
/datum/brain_trauma/magic/lumiphobia/on_life()
|
||||
..()
|
||||
var/turf/T = owner.loc
|
||||
if(istype(T))
|
||||
var/light_amount = T.get_lumcount()
|
||||
if(light_amount > SHADOW_SPECIES_LIGHT_THRESHOLD) //if there's enough light, start dying
|
||||
if(world.time > next_damage_warning)
|
||||
to_chat(owner, "<span class='warning'><b>The light burns you!</b></span>")
|
||||
next_damage_warning = world.time + 100 //Avoid spamming
|
||||
owner.take_overall_damage(0,3)
|
||||
|
||||
/datum/brain_trauma/magic/poltergeist
|
||||
name = "Poltergeist"
|
||||
desc = "Patient appears to be targeted by a violent invisible entity."
|
||||
scan_desc = "paranormal activity"
|
||||
gain_text = "<span class='warning'>You feel a hateful presence close to you.</span>"
|
||||
lose_text = "<span class='notice'>You feel the hateful presence fade away.</span>"
|
||||
|
||||
/datum/brain_trauma/magic/poltergeist/on_life()
|
||||
..()
|
||||
if(prob(4))
|
||||
var/most_violent = -1 //So it can pick up items with 0 throwforce if there's nothing else
|
||||
var/obj/item/throwing
|
||||
for(var/obj/item/I in view(5, get_turf(owner)))
|
||||
if(I.anchored)
|
||||
continue
|
||||
if(I.throwforce > most_violent)
|
||||
most_violent = I.throwforce
|
||||
throwing = I
|
||||
if(throwing)
|
||||
throwing.throw_at(owner, 8, 2)
|
||||
|
||||
/datum/brain_trauma/magic/antimagic
|
||||
name = "Athaumasia"
|
||||
desc = "Patient is completely inert to magical forces."
|
||||
scan_desc = "thaumic blank"
|
||||
gain_text = "<span class='notice'>You realize that magic cannot be real.</span>"
|
||||
lose_text = "<span class='notice'>You realize that magic might be real.</span>"
|
||||
|
||||
/datum/brain_trauma/magic/antimagic/on_gain()
|
||||
ADD_TRAIT(owner, TRAIT_ANTIMAGIC, TRAUMA_TRAIT)
|
||||
..()
|
||||
|
||||
/datum/brain_trauma/magic/antimagic/on_lose()
|
||||
REMOVE_TRAIT(owner, TRAIT_ANTIMAGIC, TRAUMA_TRAIT)
|
||||
..()
|
||||
|
||||
/datum/brain_trauma/magic/stalker
|
||||
name = "Stalking Phantom"
|
||||
desc = "Patient is stalked by a phantom only they can see."
|
||||
|
||||
@@ -117,12 +117,6 @@
|
||||
paralysis_type = "legs"
|
||||
resilience = TRAUMA_RESILIENCE_ABSOLUTE
|
||||
|
||||
/datum/brain_trauma/severe/paralysis/spinesnapped
|
||||
random_gain = FALSE
|
||||
clonable = FALSE
|
||||
paralysis_type = "legs"
|
||||
resilience = TRAUMA_RESILIENCE_LOBOTOMY // It shouldn't fix severed spinal cords really, but there is no specific surgery for that yet.
|
||||
|
||||
/datum/brain_trauma/severe/narcolepsy
|
||||
name = "Narcolepsy"
|
||||
desc = "Patient may involuntarily fall asleep during normal activities."
|
||||
|
||||
@@ -123,9 +123,7 @@
|
||||
trauma = _trauma
|
||||
return ..()
|
||||
|
||||
/mob/living/split_personality/BiologicalLife(seconds, times_fired)
|
||||
if(!(. = ..()))
|
||||
return
|
||||
/mob/living/split_personality/Life()
|
||||
if(QDELETED(body))
|
||||
qdel(src) //in case trauma deletion doesn't already do it
|
||||
|
||||
@@ -134,6 +132,8 @@
|
||||
trauma.switch_personalities()
|
||||
qdel(trauma)
|
||||
|
||||
..()
|
||||
|
||||
/mob/living/split_personality/Login()
|
||||
..()
|
||||
to_chat(src, "<span class='notice'>As a split personality, you cannot do anything but observe. However, you will eventually gain control of your body, switching places with the current personality.</span>")
|
||||
|
||||
@@ -97,20 +97,20 @@
|
||||
[get_footer()]
|
||||
"}
|
||||
|
||||
/datum/browser/proc/open(use_onclose = TRUE)
|
||||
/datum/browser/proc/open(use_onclose = 1)
|
||||
if(isnull(window_id)) //null check because this can potentially nuke goonchat
|
||||
WARNING("Browser [title] tried to open with a null ID")
|
||||
to_chat(user, "<span class='userdanger'>The [title] browser you tried to open failed a sanity check! Please report this on github!</span>")
|
||||
return
|
||||
var/window_size = ""
|
||||
if(width && height)
|
||||
if (width && height)
|
||||
window_size = "size=[width]x[height];"
|
||||
if(stylesheets.len)
|
||||
send_asset_list(user, stylesheets)
|
||||
if(scripts.len)
|
||||
send_asset_list(user, scripts)
|
||||
if (stylesheets.len)
|
||||
send_asset_list(user, stylesheets, verify=FALSE)
|
||||
if (scripts.len)
|
||||
send_asset_list(user, scripts, verify=FALSE)
|
||||
user << browse(get_content(), "window=[window_id];[window_size][window_options]")
|
||||
if(use_onclose)
|
||||
if (use_onclose)
|
||||
setup_onclose()
|
||||
|
||||
/datum/browser/proc/setup_onclose()
|
||||
@@ -157,7 +157,7 @@
|
||||
close()
|
||||
|
||||
//designed as a drop in replacement for alert(); functions the same. (outside of needing User specified)
|
||||
/proc/tgalert(mob/User, Message, Title, Button1="Ok", Button2, Button3, StealFocus = 1, Timeout = 6000)
|
||||
/proc/tgalert(var/mob/User, Message, Title, Button1="Ok", Button2, Button3, StealFocus = 1, Timeout = 6000)
|
||||
if (!User)
|
||||
User = usr
|
||||
switch(askuser(User, Message, Title, Button1, Button2, Button3, StealFocus, Timeout))
|
||||
|
||||
@@ -114,7 +114,7 @@
|
||||
// BYOND Bug #2563917
|
||||
// Construct text
|
||||
var/static/regex/html_metachars = new(@"&[A-Za-z]{1,7};", "g")
|
||||
var/complete_text = "<span class='center maptext [extra_classes.Join(" ")]' style='color: [tgt_color]'>[owner.say_emphasis(text)]</span>"
|
||||
var/complete_text = "<span class='center maptext [extra_classes.Join(" ")]' style='color: [tgt_color]'>[text]</span>"
|
||||
var/mheight = WXH_TO_HEIGHT(owned_by.MeasureText(replacetext(complete_text, html_metachars, "m"), null, CHAT_MESSAGE_WIDTH))
|
||||
approx_lines = max(1, mheight / CHAT_MESSAGE_APPROX_LHEIGHT)
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ GLOBAL_LIST_EMPTY(cinematics)
|
||||
/datum/cinematic
|
||||
var/id = CINEMATIC_DEFAULT
|
||||
var/list/watching = list() //List of clients watching this
|
||||
var/list/locked = list() //Who had mob_transforming set during the cinematic
|
||||
var/list/locked = list() //Who had notransform set during the cinematic
|
||||
var/is_global = FALSE //Global cinematics will override mob-specific ones
|
||||
var/obj/screen/cinematic/screen
|
||||
var/datum/callback/special_callback //For special effects synced with animation (explosions after the countdown etc)
|
||||
@@ -45,7 +45,7 @@ GLOBAL_LIST_EMPTY(cinematics)
|
||||
GLOB.cinematics -= src
|
||||
QDEL_NULL(screen)
|
||||
for(var/mob/M in locked)
|
||||
M.mob_transforming = FALSE
|
||||
M.notransform = FALSE
|
||||
return ..()
|
||||
|
||||
/datum/cinematic/proc/play(watchers)
|
||||
@@ -70,7 +70,7 @@ GLOBAL_LIST_EMPTY(cinematics)
|
||||
|
||||
for(var/mob/M in GLOB.mob_list)
|
||||
if(M in watchers)
|
||||
M.mob_transforming = TRUE //Should this be done for non-global cinematics or even at all ?
|
||||
M.notransform = TRUE //Should this be done for non-global cinematics or even at all ?
|
||||
locked += M
|
||||
//Close watcher ui's
|
||||
SStgui.close_user_uis(M)
|
||||
@@ -79,7 +79,7 @@ GLOBAL_LIST_EMPTY(cinematics)
|
||||
M.client.screen += screen
|
||||
else
|
||||
if(is_global)
|
||||
M.mob_transforming = TRUE
|
||||
M.notransform = TRUE
|
||||
locked += M
|
||||
|
||||
//Actually play it
|
||||
@@ -254,4 +254,4 @@ Nuke.Explosion()
|
||||
|
||||
Narsie()
|
||||
-> Cinematic(CULT,world)
|
||||
*/
|
||||
*/
|
||||
@@ -38,9 +38,8 @@
|
||||
parent = raw_args[1]
|
||||
var/list/arguments = raw_args.Copy(2)
|
||||
if(Initialize(arglist(arguments)) == COMPONENT_INCOMPATIBLE)
|
||||
stack_trace("Incompatible [type] assigned to a [parent.type]! args: [json_encode(arguments)]")
|
||||
qdel(src, TRUE, TRUE)
|
||||
return
|
||||
CRASH("Incompatible [type] assigned to a [parent.type]! args: [json_encode(arguments)]")
|
||||
|
||||
_JoinParent(parent)
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
AM.visible_message("<span class='boldwarning'>[AM] falls into [parent]!</span>", "<span class='userdanger'>[oblivion_message]</span>")
|
||||
if (isliving(AM))
|
||||
var/mob/living/L = AM
|
||||
L.mob_transforming = TRUE
|
||||
L.notransform = TRUE
|
||||
L.Paralyze(200)
|
||||
|
||||
var/oldtransform = AM.transform
|
||||
|
||||
@@ -119,8 +119,6 @@
|
||||
if(hud_icon)
|
||||
hud_icon.combat_on = FALSE
|
||||
hud_icon.update_icon()
|
||||
source.stop_active_blocking()
|
||||
source.end_parry_sequence()
|
||||
|
||||
///Changes the user direction to (try) keep match the pointer.
|
||||
/datum/component/combat_mode/proc/on_move(atom/movable/source, dir, atom/oldloc, forced)
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
qdel(src)
|
||||
|
||||
/obj/item/glasswork/glasses
|
||||
name = "Handmade Glasses"
|
||||
desc = "Handmade glasses that have not been polished at all making them useless. Selling them could still be worth a few credits."
|
||||
name = "Hand Made Glasses"
|
||||
desc = "Hande made glasses that have not been polished at all making them useless. Selling them could still be worth a bit of credits."
|
||||
icon = 'icons/obj/glass_ware.dmi'
|
||||
icon_state = "frames_2"
|
||||
@@ -1,4 +1,4 @@
|
||||
// PARTS //
|
||||
k// PARTS //
|
||||
/obj/item/weaponcrafting
|
||||
icon = 'icons/obj/improvised.dmi'
|
||||
|
||||
@@ -8,33 +8,44 @@
|
||||
custom_materials = list(/datum/material/wood = MINERAL_MATERIAL_AMOUNT * 6)
|
||||
icon_state = "riflestock"
|
||||
|
||||
/obj/item/weaponcrafting/string
|
||||
name = "wound thread"
|
||||
desc = "A long piece of thread with some resemblance to cable coil."
|
||||
/obj/item/weaponcrafting/durathread_string
|
||||
name = "durathread string"
|
||||
desc = "A long piece of durathread with some resemblance to cable coil."
|
||||
icon_state = "durastring"
|
||||
|
||||
////////////////////////////////
|
||||
// IMPROVISED WEAPON PARTS//
|
||||
// KAT IMPROVISED WEAPON PARTS//
|
||||
////////////////////////////////
|
||||
|
||||
/obj/item/weaponcrafting/improvised_parts
|
||||
name = "Debug Improvised Gun Part"
|
||||
desc = "A badly coded gun part. You should report coders if you see this."
|
||||
name = "Eerie bunch of coloured dots."
|
||||
desc = "You feel the urge to report to Central that the parent type of guncrafting, which should never appear in this reality, has appeared. Whatever that means."
|
||||
icon = 'icons/obj/guns/gun_parts.dmi'
|
||||
icon_state = "palette"
|
||||
|
||||
// BARRELS
|
||||
|
||||
/obj/item/weaponcrafting/improvised_parts/barrel_rifle
|
||||
name = "rifle barrel"
|
||||
desc = "A pipe with a diameter just the right size to fire 7.62 rounds out of."
|
||||
icon_state = "barrel_rifle"
|
||||
|
||||
/obj/item/weaponcrafting/improvised_parts/barrel_shotgun
|
||||
name = "shotgun barrel"
|
||||
desc = "A twenty bore shotgun barrel."
|
||||
icon_state = "barrel_shotgun"
|
||||
|
||||
// RECEIVERS
|
||||
|
||||
/obj/item/weaponcrafting/improvised_parts/rifle_receiver
|
||||
name = "rifle receiver"
|
||||
desc = "A crudely constructed receiver to create an improvised bolt-action breechloaded rifle." // removed some text implying that the item had more uses than it does
|
||||
name = "bolt action receiver"
|
||||
desc = "A crudely constructed receiver to create an improvised bolt-action breechloaded rifle."
|
||||
icon_state = "receiver_rifle"
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
|
||||
|
||||
/obj/item/weaponcrafting/improvised_parts/shotgun_receiver
|
||||
name = "shotgun reciever"
|
||||
desc = "An improvised receiver to create a break-action breechloaded shotgun." // removed some text implying that the item had more uses than it does
|
||||
name = "break-action assembly"
|
||||
desc = "An improvised receiver to create a break-action breechloaded shotgun."
|
||||
icon_state = "receiver_shotgun"
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
|
||||
@@ -50,3 +61,4 @@
|
||||
name = "wooden firearm body"
|
||||
desc = "A crudely fashioned wooden body to help keep higher calibre improvised weapons from blowing themselves apart."
|
||||
icon_state = "wooden_body"
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
time = 150
|
||||
subcategory = CAT_MISCELLANEOUS
|
||||
category = CAT_MISC
|
||||
always_availible = FALSE // Disabled until learned
|
||||
always_availible = FALSE // Disabled til learned
|
||||
|
||||
|
||||
/datum/crafting_recipe/bloodsucker/candelabrum
|
||||
@@ -124,9 +124,9 @@
|
||||
category = CAT_MISC
|
||||
subcategory = CAT_TOOL
|
||||
|
||||
/datum/crafting_recipe/brute_pack
|
||||
name = "Suture Pack"
|
||||
result = /obj/item/stack/medical/suture/one
|
||||
/datum/crafting_recipe/bruise_pack
|
||||
name = "Bruise Pack"
|
||||
result = /obj/item/stack/medical/bruise_pack/one
|
||||
time = 1
|
||||
reqs = list(/obj/item/stack/medical/gauze = 1,
|
||||
/datum/reagent/medicine/styptic_powder = 10)
|
||||
@@ -134,8 +134,8 @@
|
||||
subcategory = CAT_TOOL
|
||||
|
||||
/datum/crafting_recipe/burn_pack
|
||||
name = "Regenerative Mesh"
|
||||
result = /obj/item/stack/medical/mesh/one
|
||||
name = "Burn Ointment"
|
||||
result = /obj/item/stack/medical/ointment/one
|
||||
time = 1
|
||||
reqs = list(/obj/item/stack/medical/gauze = 1,
|
||||
/datum/reagent/medicine/silver_sulfadiazine = 10)
|
||||
@@ -244,7 +244,7 @@
|
||||
|
||||
/datum/crafting_recipe/rcl
|
||||
name = "Makeshift Rapid Cable Layer"
|
||||
result = /obj/item/rcl/ghetto
|
||||
result = /obj/item/twohanded/rcl/ghetto
|
||||
time = 40
|
||||
tools = list(TOOL_WELDER, TOOL_SCREWDRIVER, TOOL_WRENCH)
|
||||
reqs = list(/obj/item/stack/sheet/metal = 15)
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
|
||||
/datum/crafting_recipe/bonespear
|
||||
name = "Bone Spear"
|
||||
result = /obj/item/spear/bonespear
|
||||
result = /obj/item/twohanded/bonespear
|
||||
time = 30
|
||||
reqs = list(/obj/item/stack/sheet/bone = 4,
|
||||
/obj/item/stack/sheet/sinew = 1)
|
||||
@@ -58,7 +58,7 @@
|
||||
|
||||
/datum/crafting_recipe/boneaxe
|
||||
name = "Bone Axe"
|
||||
result = /obj/item/fireaxe/boneaxe
|
||||
result = /obj/item/twohanded/fireaxe/boneaxe
|
||||
time = 50
|
||||
reqs = list(/obj/item/stack/sheet/bone = 6,
|
||||
/obj/item/stack/sheet/sinew = 3)
|
||||
@@ -74,20 +74,20 @@
|
||||
/datum/crafting_recipe/headpike
|
||||
name = "Spike Head (Glass Spear)"
|
||||
time = 65
|
||||
reqs = list(/obj/item/spear = 1,
|
||||
reqs = list(/obj/item/twohanded/spear = 1,
|
||||
/obj/item/bodypart/head = 1)
|
||||
parts = list(/obj/item/bodypart/head = 1,
|
||||
/obj/item/spear = 1)
|
||||
/obj/item/twohanded/spear = 1)
|
||||
result = /obj/structure/headpike
|
||||
category = CAT_PRIMAL
|
||||
|
||||
/datum/crafting_recipe/headpikebone
|
||||
name = "Spike Head (Bone Spear)"
|
||||
time = 65
|
||||
reqs = list(/obj/item/spear/bonespear = 1,
|
||||
reqs = list(/obj/item/twohanded/bonespear = 1,
|
||||
/obj/item/bodypart/head = 1)
|
||||
parts = list(/obj/item/bodypart/head = 1,
|
||||
/obj/item/spear/bonespear = 1)
|
||||
/obj/item/twohanded/bonespear = 1)
|
||||
result = /obj/structure/headpike/bone
|
||||
category = CAT_PRIMAL
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
/datum/crafting_recipe/bone_bow
|
||||
name = "Bone Bow"
|
||||
result = /obj/item/gun/ballistic/bow/ashen
|
||||
time = 120 // 80+120 = 200
|
||||
time = 200
|
||||
always_availible = FALSE
|
||||
reqs = list(/obj/item/stack/sheet/bone = 8,
|
||||
/obj/item/stack/sheet/sinew = 4)
|
||||
@@ -112,7 +112,7 @@
|
||||
/datum/crafting_recipe/bow_tablet
|
||||
name = "Sandstone Bow Making Manual"
|
||||
result = /obj/item/book/granter/crafting_recipe/bone_bow
|
||||
time = 200 //Scribing // don't care
|
||||
time = 600 //Scribing
|
||||
always_availible = FALSE
|
||||
reqs = list(/obj/item/stack/rods = 1,
|
||||
/obj/item/stack/sheet/mineral/sandstone = 4)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
tools = list(TOOL_WELDER, TOOL_SCREWDRIVER, TOOL_WIRECUTTER)
|
||||
time = 50
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_OTHER
|
||||
subcategory = CAT_WEAPON
|
||||
|
||||
/datum/crafting_recipe/pin_removal/check_requirements(mob/user, list/collected_requirements)
|
||||
var/obj/item/gun/G = collected_requirements[/obj/item/gun][1]
|
||||
@@ -22,7 +22,7 @@
|
||||
/obj/item/shield/riot = 1)
|
||||
time = 40
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_MELEE
|
||||
subcategory = CAT_WEAPON
|
||||
|
||||
/datum/crafting_recipe/strobeshield/New()
|
||||
..()
|
||||
@@ -38,18 +38,18 @@
|
||||
tools = list(TOOL_WELDER, TOOL_SCREWDRIVER, TOOL_WIRECUTTER)
|
||||
time = 100
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_MELEE
|
||||
subcategory = CAT_WEAPON
|
||||
|
||||
/datum/crafting_recipe/spear
|
||||
name = "Spear"
|
||||
result = /obj/item/spear
|
||||
result = /obj/item/twohanded/spear
|
||||
reqs = list(/obj/item/restraints/handcuffs/cable = 1,
|
||||
/obj/item/shard = 1,
|
||||
/obj/item/stack/rods = 1)
|
||||
parts = list(/obj/item/shard = 1)
|
||||
time = 40
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_MELEE
|
||||
subcategory = CAT_WEAPON
|
||||
|
||||
/datum/crafting_recipe/stunprod
|
||||
name = "Stunprod"
|
||||
@@ -59,7 +59,7 @@
|
||||
/obj/item/assembly/igniter = 1)
|
||||
time = 40
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_MELEE
|
||||
subcategory = CAT_WEAPON
|
||||
|
||||
/datum/crafting_recipe/teleprod
|
||||
name = "Teleprod"
|
||||
@@ -70,7 +70,7 @@
|
||||
/obj/item/stack/ore/bluespace_crystal = 1)
|
||||
time = 40
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_MELEE
|
||||
subcategory = CAT_WEAPON
|
||||
|
||||
/datum/crafting_recipe/bola
|
||||
name = "Bola"
|
||||
@@ -88,7 +88,7 @@
|
||||
/obj/item/stack/sheet/metal = 1)
|
||||
time = 40
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_MELEE
|
||||
subcategory = CAT_WEAPON
|
||||
|
||||
/datum/crafting_recipe/tailwhip
|
||||
name = "Liz O' Nine Tails"
|
||||
@@ -97,7 +97,7 @@
|
||||
/obj/item/stack/cable_coil = 1)
|
||||
time = 40
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_MELEE
|
||||
subcategory = CAT_WEAPON
|
||||
|
||||
/datum/crafting_recipe/catwhip
|
||||
name = "Cat O' Nine Tails"
|
||||
@@ -106,18 +106,18 @@
|
||||
/obj/item/stack/cable_coil = 1)
|
||||
time = 40
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_MELEE
|
||||
subcategory = CAT_WEAPON
|
||||
|
||||
/datum/crafting_recipe/chainsaw
|
||||
name = "Chainsaw"
|
||||
result = /obj/item/chainsaw
|
||||
result = /obj/item/twohanded/required/chainsaw
|
||||
reqs = list(/obj/item/circular_saw = 1,
|
||||
/obj/item/stack/cable_coil = 3,
|
||||
/obj/item/stack/sheet/plasteel = 5)
|
||||
tools = list(TOOL_WELDER)
|
||||
time = 50
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_MELEE
|
||||
subcategory = CAT_WEAPON
|
||||
|
||||
//////////////////
|
||||
///BOMB CRAFTING//
|
||||
@@ -134,20 +134,20 @@
|
||||
parts = list(/obj/item/stock_parts/matter_bin = 1, /obj/item/grenade/chem_grenade = 2)
|
||||
time = 30
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_OTHER
|
||||
subcategory = CAT_WEAPON
|
||||
|
||||
/datum/crafting_recipe/chemical_payload2
|
||||
name = "Chemical Payload (Gibtonite)"
|
||||
result = /obj/item/bombcore/chemical
|
||||
reqs = list(
|
||||
/obj/item/stock_parts/matter_bin = 1,
|
||||
/obj/item/gibtonite = 1,
|
||||
/obj/item/twohanded/required/gibtonite = 1,
|
||||
/obj/item/grenade/chem_grenade = 2
|
||||
)
|
||||
parts = list(/obj/item/stock_parts/matter_bin = 1, /obj/item/grenade/chem_grenade = 2)
|
||||
time = 50
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_OTHER
|
||||
subcategory = CAT_WEAPON
|
||||
|
||||
/datum/crafting_recipe/molotov
|
||||
name = "Molotov"
|
||||
@@ -169,18 +169,18 @@
|
||||
parts = list(/obj/item/reagent_containers/food/drinks/soda_cans = 1)
|
||||
time = 15
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_OTHER
|
||||
subcategory = CAT_WEAPON
|
||||
|
||||
/datum/crafting_recipe/lance
|
||||
name = "Explosive Lance (Grenade)"
|
||||
result = /obj/item/spear
|
||||
reqs = list(/obj/item/spear = 1,
|
||||
result = /obj/item/twohanded/spear
|
||||
reqs = list(/obj/item/twohanded/spear = 1,
|
||||
/obj/item/grenade = 1)
|
||||
parts = list(/obj/item/spear = 1,
|
||||
parts = list(/obj/item/twohanded/spear = 1,
|
||||
/obj/item/grenade = 1)
|
||||
time = 15
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_MELEE
|
||||
subcategory = CAT_WEAPON
|
||||
|
||||
//////////////////
|
||||
///GUNS CRAFTING//
|
||||
@@ -192,8 +192,8 @@
|
||||
result = /obj/item/gun/ballistic/bow/pipe
|
||||
reqs = list(/obj/item/pipe = 5,
|
||||
/obj/item/stack/sheet/plastic = 15,
|
||||
/obj/item/weaponcrafting/string = 5)
|
||||
time = 150
|
||||
/obj/item/weaponcrafting/durathread_string = 5)
|
||||
time = 450
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_WEAPON
|
||||
|
||||
@@ -248,10 +248,10 @@
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_WEAPON
|
||||
|
||||
/datum/crafting_recipe/ishotgun // smaller and more versatile gun requires some better materials
|
||||
/datum/crafting_recipe/ishotgun
|
||||
name = "Improvised Shotgun"
|
||||
result = /obj/item/gun/ballistic/revolver/doublebarrel/improvised
|
||||
reqs = list(/obj/item/pipe = 2, // putting a large amount of meaningless timegates by forcing people to turn base resources into upgraded resources kinda sucks
|
||||
reqs = list(/obj/item/weaponcrafting/improvised_parts/barrel_shotgun = 1,
|
||||
/obj/item/weaponcrafting/improvised_parts/shotgun_receiver = 1,
|
||||
/obj/item/weaponcrafting/improvised_parts/trigger_assembly = 1,
|
||||
/obj/item/weaponcrafting/improvised_parts/wooden_body = 1,
|
||||
@@ -262,10 +262,10 @@
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_WEAPON
|
||||
|
||||
/datum/crafting_recipe/irifle // larger and less versatile gun, but a bit easier to make
|
||||
/datum/crafting_recipe/irifle
|
||||
name = "Improvised Rifle (7.62mm)"
|
||||
result = /obj/item/gun/ballistic/shotgun/boltaction/improvised
|
||||
reqs = list(/obj/item/pipe = 2, // above
|
||||
reqs = list(/obj/item/weaponcrafting/improvised_parts/barrel_rifle = 1,
|
||||
/obj/item/weaponcrafting/improvised_parts/rifle_receiver = 1,
|
||||
/obj/item/weaponcrafting/improvised_parts/trigger_assembly = 1,
|
||||
/obj/item/weaponcrafting/improvised_parts/wooden_body = 1,
|
||||
@@ -283,9 +283,9 @@
|
||||
/datum/crafting_recipe/arrow
|
||||
name = "Arrow"
|
||||
result = /obj/item/ammo_casing/caseless/arrow/wood
|
||||
time = 5 // these only do 15 damage
|
||||
time = 30
|
||||
reqs = list(/obj/item/stack/sheet/mineral/wood = 1,
|
||||
/obj/item/stack/sheet/cloth = 1,
|
||||
/obj/item/stack/sheet/durathread = 1,
|
||||
/obj/item/stack/rods = 1) // 1 metal sheet = 2 rods = 2 arrows
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_AMMO
|
||||
@@ -293,7 +293,7 @@
|
||||
/datum/crafting_recipe/bone_arrow
|
||||
name = "Bone Arrow"
|
||||
result = /obj/item/ammo_casing/caseless/arrow/bone
|
||||
time = 5
|
||||
time = 30
|
||||
always_availible = FALSE
|
||||
reqs = list(/obj/item/stack/sheet/bone = 1,
|
||||
/obj/item/stack/sheet/sinew = 1,
|
||||
@@ -305,7 +305,7 @@
|
||||
name = "Ashen Arrow"
|
||||
result = /obj/item/ammo_casing/caseless/arrow/ash
|
||||
tools = list(TOOL_WELDER)
|
||||
time = 10 // 1.5 seconds minimum per actually worthwhile arrow excluding interface lag
|
||||
time = 30
|
||||
always_availible = FALSE
|
||||
reqs = list(/obj/item/ammo_casing/caseless/arrow/wood = 1)
|
||||
category = CAT_WEAPONRY
|
||||
@@ -403,24 +403,44 @@
|
||||
// PARTS CRAFTING //
|
||||
////////////////////
|
||||
|
||||
// BARRELS
|
||||
|
||||
/datum/crafting_recipe/rifle_barrel
|
||||
name = "Improvised Rifle Barrel"
|
||||
result = /obj/item/weaponcrafting/improvised_parts/barrel_rifle
|
||||
reqs = list(/obj/item/pipe = 2)
|
||||
tools = list(TOOL_WELDER,TOOL_SAW)
|
||||
time = 150
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
/datum/crafting_recipe/shotgun_barrel
|
||||
name = "Improvised Shotgun Barrel"
|
||||
result = /obj/item/weaponcrafting/improvised_parts/barrel_shotgun
|
||||
reqs = list(/obj/item/pipe = 2)
|
||||
tools = list(TOOL_WELDER,TOOL_SAW)
|
||||
time = 150
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
// RECEIVERS
|
||||
|
||||
/datum/crafting_recipe/rifle_receiver
|
||||
name = "Improvised Rifle Receiver"
|
||||
result = /obj/item/weaponcrafting/improvised_parts/rifle_receiver
|
||||
reqs = list(/obj/item/stack/sheet/metal = 15) // you can carry multiple shotguns
|
||||
tools = list(TOOL_SCREWDRIVER, TOOL_WELDER)
|
||||
time = 25
|
||||
reqs = list(/obj/item/stack/sheet/metal = 20)
|
||||
tools = list(TOOL_SCREWDRIVER, TOOL_WELDER) // Rifle is the easiest to craft and can be made at an autolathe, this is a very light kick in the shin for dual-wielding ishotguns.
|
||||
time = 50
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
/datum/crafting_recipe/shotgun_receiver
|
||||
name = "Improvised Shotgun Receiver"
|
||||
result = /obj/item/weaponcrafting/improvised_parts/shotgun_receiver
|
||||
reqs = list(/obj/item/stack/sheet/metal = 15,
|
||||
/obj/item/stack/sheet/plasteel = 1) // requires access or hacking since shotgun is better
|
||||
tools = list(TOOL_SCREWDRIVER, TOOL_WELDER)
|
||||
time = 25
|
||||
reqs = list(/obj/item/stack/sheet/metal = 10,
|
||||
/obj/item/stack/sheet/plasteel = 1)
|
||||
tools = list(TOOL_SCREWDRIVER, TOOL_WELDER) // Increased cost is to stop dual-wield alpha striking. ishotgun is a rvolver and can be duel-wielded
|
||||
time = 50
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
@@ -432,6 +452,6 @@
|
||||
reqs = list(/obj/item/stack/sheet/metal = 3,
|
||||
/obj/item/assembly/igniter = 1)
|
||||
tools = list(TOOL_SCREWDRIVER, TOOL_WELDER)
|
||||
time = 25
|
||||
time = 150
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
@@ -1,244 +0,0 @@
|
||||
/*!
|
||||
This component makes it possible to make things edible. What this means is that you can take a bite or force someone to take a bite (in the case of items).
|
||||
These items take a specific time to eat, and can do most of the things our original food items could.
|
||||
Behavior that's still missing from this component that original food items had that should either be put into seperate components or somewhere else:
|
||||
Components:
|
||||
Drying component (jerky etc)
|
||||
Customizable component (custom pizzas etc)
|
||||
Processable component (Slicing and cooking behavior essentialy, making it go from item A to B when conditions are met.)
|
||||
Dunkable component (Dunking things into reagent containers to absorb a specific amount of reagents)
|
||||
Misc:
|
||||
Something for cakes (You can store things inside)
|
||||
*/
|
||||
/datum/component/edible
|
||||
///Amount of reagents taken per bite
|
||||
var/bite_consumption = 2
|
||||
///Amount of bites taken so far
|
||||
var/bitecount = 0
|
||||
///Flags for food
|
||||
var/food_flags = NONE
|
||||
///Bitfield of the types of this food
|
||||
var/foodtypes = NONE
|
||||
///Amount of seconds it takes to eat this food
|
||||
var/eat_time = 30
|
||||
///Defines how much it lowers someones satiety (Need to eat, essentialy)
|
||||
var/junkiness = 0
|
||||
///Message to send when eating
|
||||
var/list/eatverbs
|
||||
///Callback to be ran for when you take a bite of something
|
||||
var/datum/callback/after_eat
|
||||
///Last time we checked for food likes
|
||||
var/last_check_time
|
||||
|
||||
/datum/component/edible/Initialize(list/initial_reagents, food_flags = NONE, foodtypes = NONE, volume = 50, eat_time = 30, list/tastes, list/eatverbs = list("bite","chew","nibble","gnaw","gobble","chomp"), bite_consumption = 2, datum/callback/after_eat)
|
||||
if(!isatom(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/examine)
|
||||
RegisterSignal(parent, COMSIG_ATOM_ATTACK_ANIMAL, .proc/UseByAnimal)
|
||||
if(isitem(parent))
|
||||
RegisterSignal(parent, COMSIG_ITEM_ATTACK, .proc/UseFromHand)
|
||||
else if(isturf(parent))
|
||||
RegisterSignal(parent, COMSIG_ATOM_ATTACK_HAND, .proc/TryToEatTurf)
|
||||
|
||||
src.bite_consumption = bite_consumption
|
||||
src.food_flags = food_flags
|
||||
src.foodtypes = foodtypes
|
||||
src.eat_time = eat_time
|
||||
src.eatverbs = eatverbs
|
||||
src.junkiness = junkiness
|
||||
src.after_eat = after_eat
|
||||
|
||||
var/atom/owner = parent
|
||||
|
||||
owner.create_reagents(volume, INJECTABLE)
|
||||
|
||||
if(initial_reagents)
|
||||
for(var/rid in initial_reagents)
|
||||
var/amount = initial_reagents[rid]
|
||||
if(tastes && tastes.len && (rid == /datum/reagent/consumable/nutriment || rid == /datum/reagent/consumable/nutriment/vitamin))
|
||||
owner.reagents.add_reagent(rid, amount, tastes.Copy())
|
||||
else
|
||||
owner.reagents.add_reagent(rid, amount)
|
||||
|
||||
/datum/component/edible/proc/examine(datum/source, mob/user, list/examine_list)
|
||||
if(!(food_flags & FOOD_IN_CONTAINER))
|
||||
switch (bitecount)
|
||||
if (0)
|
||||
return
|
||||
if(1)
|
||||
examine_list += "[parent] was bitten by someone!"
|
||||
if(2,3)
|
||||
examine_list += "[parent] was bitten [bitecount] times!"
|
||||
else
|
||||
examine_list += "[parent] was bitten multiple times!"
|
||||
|
||||
/datum/component/edible/proc/UseFromHand(obj/item/source, mob/living/M, mob/living/user)
|
||||
return TryToEat(M, user)
|
||||
|
||||
/datum/component/edible/proc/TryToEatTurf(datum/source, mob/user)
|
||||
return TryToEat(user, user)
|
||||
|
||||
///All the checks for the act of eating itself and
|
||||
/datum/component/edible/proc/TryToEat(mob/living/eater, mob/living/feeder)
|
||||
|
||||
set waitfor = FALSE
|
||||
|
||||
var/atom/owner = parent
|
||||
|
||||
if(feeder.a_intent == INTENT_HARM)
|
||||
return
|
||||
if(!owner.reagents.total_volume)//Shouldn't be needed but it checks to see if it has anything left in it.
|
||||
to_chat(feeder, "<span class='warning'>None of [owner] left, oh no!</span>")
|
||||
if(isturf(parent))
|
||||
var/turf/T = parent
|
||||
T.ScrapeAway(1, CHANGETURF_INHERIT_AIR)
|
||||
else
|
||||
qdel(parent)
|
||||
return
|
||||
if(!CanConsume(eater, feeder))
|
||||
return
|
||||
var/fullness = eater.nutrition + 10 //The theoretical fullness of the person eating if they were to eat this
|
||||
for(var/datum/reagent/consumable/C in eater.reagents.reagent_list) //we add the nutrition value of what we're currently digesting
|
||||
fullness += C.nutriment_factor * C.volume / C.metabolization_rate
|
||||
|
||||
. = COMPONENT_ITEM_NO_ATTACK //Point of no return I suppose
|
||||
|
||||
if(eater == feeder)//If you're eating it yourself.
|
||||
if(!do_mob(feeder, eater, eat_time)) //Gotta pass the minimal eat time
|
||||
return
|
||||
var/eatverb = pick(eatverbs)
|
||||
if(junkiness && eater.satiety < -150 && eater.nutrition > NUTRITION_LEVEL_STARVING + 50 && !HAS_TRAIT(eater, TRAIT_VORACIOUS))
|
||||
to_chat(eater, "<span class='warning'>You don't feel like eating any more junk food at the moment!</span>")
|
||||
return
|
||||
else if(fullness <= 50)
|
||||
eater.visible_message("<span class='notice'>[eater] hungrily [eatverb]s \the [parent], gobbling it down!</span>", "<span class='notice'>You hungrily [eatverb] \the [parent], gobbling it down!</span>")
|
||||
else if(fullness > 50 && fullness < 150)
|
||||
eater.visible_message("<span class='notice'>[eater] hungrily [eatverb]s \the [parent].</span>", "<span class='notice'>You hungrily [eatverb] \the [parent].</span>")
|
||||
else if(fullness > 150 && fullness < 500)
|
||||
eater.visible_message("<span class='notice'>[eater] [eatverb]s \the [parent].</span>", "<span class='notice'>You [eatverb] \the [parent].</span>")
|
||||
else if(fullness > 500 && fullness < 600)
|
||||
eater.visible_message("<span class='notice'>[eater] unwillingly [eatverb]s a bit of \the [parent].</span>", "<span class='notice'>You unwillingly [eatverb] a bit of \the [parent].</span>")
|
||||
else if(fullness > (600 * (1 + eater.overeatduration / 2000))) // The more you eat - the more you can eat
|
||||
eater.visible_message("<span class='warning'>[eater] cannot force any more of \the [parent] to go down [eater.p_their()] throat!</span>", "<span class='warning'>You cannot force any more of \the [parent] to go down your throat!</span>")
|
||||
return
|
||||
else //If you're feeding it to someone else.
|
||||
if(isbrain(eater))
|
||||
to_chat(feeder, "<span class='warning'>[eater] doesn't seem to have a mouth!</span>")
|
||||
return
|
||||
if(fullness <= (600 * (1 + eater.overeatduration / 1000)))
|
||||
eater.visible_message("<span class='danger'>[feeder] attempts to feed [eater] [parent].</span>", \
|
||||
"<span class='userdanger'>[feeder] attempts to feed you [parent].</span>")
|
||||
else
|
||||
eater.visible_message("<span class='warning'>[feeder] cannot force any more of [parent] down [eater]'s throat!</span>", \
|
||||
"<span class='warning'>[feeder] cannot force any more of [parent] down your throat!</span>")
|
||||
return
|
||||
if(!do_mob(feeder, eater)) //Wait 3 seconds before you can feed
|
||||
return
|
||||
|
||||
log_combat(feeder, eater, "fed", owner.reagents.log_list())
|
||||
eater.visible_message("<span class='danger'>[feeder] forces [eater] to eat [parent]!</span>", \
|
||||
"<span class='userdanger'>[feeder] forces you to eat [parent]!</span>")
|
||||
|
||||
TakeBite(eater, feeder)
|
||||
|
||||
///This function lets the eater take a bite and transfers the reagents to the eater.
|
||||
/datum/component/edible/proc/TakeBite(mob/living/eater, mob/living/feeder)
|
||||
|
||||
var/atom/owner = parent
|
||||
|
||||
if(!owner?.reagents)
|
||||
return FALSE
|
||||
if(eater.satiety > -200)
|
||||
eater.satiety -= junkiness
|
||||
playsound(eater.loc,'sound/items/eatfood.ogg', rand(10,50), TRUE)
|
||||
if(owner.reagents.total_volume)
|
||||
SEND_SIGNAL(parent, COMSIG_FOOD_EATEN, eater, feeder)
|
||||
var/fraction = min(bite_consumption / owner.reagents.total_volume, 1)
|
||||
owner.reagents.reaction(eater, INGEST, fraction)
|
||||
owner.reagents.trans_to(eater, bite_consumption)
|
||||
bitecount++
|
||||
On_Consume(eater)
|
||||
checkLiked(fraction, eater)
|
||||
|
||||
//Invoke our after eat callback if it is valid
|
||||
if(after_eat)
|
||||
after_eat.Invoke(eater, feeder)
|
||||
|
||||
return TRUE
|
||||
|
||||
///Checks whether or not the eater can actually consume the food
|
||||
/datum/component/edible/proc/CanConsume(mob/living/eater, mob/living/feeder)
|
||||
if(!iscarbon(eater))
|
||||
return FALSE
|
||||
var/mob/living/carbon/C = eater
|
||||
var/covered = ""
|
||||
if(C.is_mouth_covered(head_only = 1))
|
||||
covered = "headgear"
|
||||
else if(C.is_mouth_covered(mask_only = 1))
|
||||
covered = "mask"
|
||||
if(covered)
|
||||
var/who = (isnull(feeder) || eater == feeder) ? "your" : "[eater.p_their()]"
|
||||
to_chat(feeder, "<span class='warning'>You have to remove [who] [covered] first!</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
///Check foodtypes to see if we should send a moodlet
|
||||
/datum/component/edible/proc/checkLiked(var/fraction, mob/M)
|
||||
if(last_check_time + 50 > world.time)
|
||||
return FALSE
|
||||
if(!ishuman(M))
|
||||
return FALSE
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(HAS_TRAIT(H, TRAIT_AGEUSIA) && foodtypes & H.dna.species.toxic_food)
|
||||
to_chat(H, "<span class='warning'>You don't feel so good...</span>")
|
||||
H.adjust_disgust(25 + 30 * fraction)
|
||||
else
|
||||
if(foodtypes & H.dna.species.toxic_food)
|
||||
to_chat(H,"<span class='warning'>What the hell was that thing?!</span>")
|
||||
H.adjust_disgust(25 + 30 * fraction)
|
||||
SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "toxic_food", /datum/mood_event/disgusting_food)
|
||||
else if(foodtypes & H.dna.species.disliked_food)
|
||||
to_chat(H,"<span class='notice'>That didn't taste very good...</span>")
|
||||
H.adjust_disgust(11 + 15 * fraction)
|
||||
SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "gross_food", /datum/mood_event/gross_food)
|
||||
else if(foodtypes & H.dna.species.liked_food)
|
||||
to_chat(H,"<span class='notice'>I love this taste!</span>")
|
||||
H.adjust_disgust(-5 + -2.5 * fraction)
|
||||
SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "fav_food", /datum/mood_event/favorite_food)
|
||||
if((foodtypes & BREAKFAST) && world.time - SSticker.round_start_time < STOP_SERVING_BREAKFAST)
|
||||
SEND_SIGNAL(H, COMSIG_ADD_MOOD_EVENT, "breakfast", /datum/mood_event/breakfast)
|
||||
last_check_time = world.time
|
||||
|
||||
///Delete the item when it is fully eaten
|
||||
/datum/component/edible/proc/On_Consume(mob/living/eater)
|
||||
|
||||
var/atom/owner = parent
|
||||
|
||||
if(!eater)
|
||||
return
|
||||
if(!owner.reagents.total_volume)
|
||||
if(isturf(parent))
|
||||
var/turf/T = parent
|
||||
T.ScrapeAway(1, CHANGETURF_INHERIT_AIR)
|
||||
else
|
||||
qdel(parent)
|
||||
|
||||
///Ability to feed food to puppers
|
||||
/datum/component/edible/proc/UseByAnimal(datum/source, mob/user)
|
||||
|
||||
var/atom/owner = parent
|
||||
|
||||
if(!isdog(user))
|
||||
return
|
||||
var/mob/living/L = user
|
||||
if(bitecount == 0 || prob(50))
|
||||
L.emote("me", 1, "nibbles away at \the [parent]")
|
||||
bitecount++
|
||||
. = COMPONENT_ITEM_NO_ATTACK
|
||||
L.taste(owner.reagents) // why should carbons get all the fun?
|
||||
if(bitecount >= 5)
|
||||
var/sattisfaction_text = pick("burps from enjoyment", "yaps for more", "woofs twice", "looks at the area where \the [parent] was")
|
||||
if(sattisfaction_text)
|
||||
L.emote("me", 1, "[sattisfaction_text]")
|
||||
qdel(parent)
|
||||
@@ -1,363 +0,0 @@
|
||||
/*
|
||||
This component is responsible for handling individual instances of embedded objects. The embeddable element is what allows an item to be embeddable and stores its embedding stats,
|
||||
and when it impacts and meets the requirements to stick into something, it instantiates an embedded component. Once the item falls out, the component is destroyed, while the
|
||||
element survives to embed another day.
|
||||
|
||||
There are 2 different things that can be embedded presently: carbons, and closed turfs (see: walls)
|
||||
|
||||
- Carbon embedding has all the classical embedding behavior, and tracks more events and signals. The main behaviors and hooks to look for are:
|
||||
-- Every process tick, there is a chance to randomly proc pain, controlled by pain_chance. There may also be a chance for the object to fall out randomly, per fall_chance
|
||||
-- Every time the mob moves, there is a chance to proc jostling pain, controlled by jostle_chance (and only 50% as likely if the mob is walking or crawling)
|
||||
-- Various signals hooking into carbon topic() and the embed removal surgery in order to handle removals.
|
||||
|
||||
- Turf embedding is much simpler. All we do here is draw an overlay of the item's inhand on the turf, hide the item, and create an HTML link in the turf's inspect
|
||||
that allows you to rip the item out. There's nothing dynamic about this, so far less checks.
|
||||
|
||||
|
||||
In addition, there are 2 cases of embedding: embedding, and sticking
|
||||
|
||||
- Embedding involves harmful and dangerous embeds, whether they cause brute damage, stamina damage, or a mix. This is the default behavior for embeddings, for when something is "pointy"
|
||||
|
||||
- Sticking occurs when an item should not cause any harm while embedding (imagine throwing a sticky ball of tape at someone, rather than a shuriken). An item is considered "sticky"
|
||||
when it has 0 for both pain multiplier and jostle pain multiplier. It's a bit arbitrary, but fairly straightforward.
|
||||
|
||||
Stickables differ from embeds in the following ways:
|
||||
-- Text descriptors use phrasing like "X is stuck to Y" rather than "X is embedded in Y"
|
||||
-- There is no slicing sound on impact
|
||||
-- All damage checks and bloodloss are skipped for carbons
|
||||
-- Pointy objects create sparks when embedding into a turf
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/datum/component/embedded
|
||||
dupe_mode = COMPONENT_DUPE_ALLOWED
|
||||
var/obj/item/bodypart/limb
|
||||
var/obj/item/weapon
|
||||
|
||||
// all of this stuff is explained in _DEFINES/combat.dm
|
||||
var/embed_chance // not like we really need it once we're already stuck in but hey
|
||||
var/fall_chance
|
||||
var/pain_chance
|
||||
var/pain_mult
|
||||
var/impact_pain_mult
|
||||
var/remove_pain_mult
|
||||
var/rip_time
|
||||
var/ignore_throwspeed_threshold
|
||||
var/jostle_chance
|
||||
var/jostle_pain_mult
|
||||
var/pain_stam_pct
|
||||
var/embed_chance_turf_mod
|
||||
|
||||
///if both our pain multiplier and jostle pain multiplier are 0, we're harmless and can omit most of the damage related stuff
|
||||
var/harmful
|
||||
var/mutable_appearance/overlay
|
||||
|
||||
/datum/component/embedded/Initialize(obj/item/I,
|
||||
datum/thrownthing/throwingdatum,
|
||||
obj/item/bodypart/part,
|
||||
embed_chance = EMBED_CHANCE,
|
||||
fall_chance = EMBEDDED_ITEM_FALLOUT,
|
||||
pain_chance = EMBEDDED_PAIN_CHANCE,
|
||||
pain_mult = EMBEDDED_PAIN_MULTIPLIER,
|
||||
remove_pain_mult = EMBEDDED_UNSAFE_REMOVAL_PAIN_MULTIPLIER,
|
||||
impact_pain_mult = EMBEDDED_IMPACT_PAIN_MULTIPLIER,
|
||||
rip_time = EMBEDDED_UNSAFE_REMOVAL_TIME,
|
||||
ignore_throwspeed_threshold = FALSE,
|
||||
jostle_chance = EMBEDDED_JOSTLE_CHANCE,
|
||||
jostle_pain_mult = EMBEDDED_JOSTLE_PAIN_MULTIPLIER,
|
||||
pain_stam_pct = EMBEDDED_PAIN_STAM_PCT,
|
||||
embed_chance_turf_mod = EMBED_CHANCE_TURF_MOD)
|
||||
|
||||
if((!iscarbon(parent) && !isclosedturf(parent)) || !isitem(I))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
if(part)
|
||||
limb = part
|
||||
src.embed_chance = embed_chance
|
||||
src.fall_chance = fall_chance
|
||||
src.pain_chance = pain_chance
|
||||
src.pain_mult = pain_mult
|
||||
src.remove_pain_mult = remove_pain_mult
|
||||
src.rip_time = rip_time
|
||||
src.impact_pain_mult = impact_pain_mult
|
||||
src.ignore_throwspeed_threshold = ignore_throwspeed_threshold
|
||||
src.jostle_chance = jostle_chance
|
||||
src.jostle_pain_mult = jostle_pain_mult
|
||||
src.pain_stam_pct = pain_stam_pct
|
||||
src.embed_chance_turf_mod = embed_chance_turf_mod
|
||||
|
||||
src.weapon = I
|
||||
|
||||
if(!weapon.isEmbedHarmless())
|
||||
harmful = TRUE
|
||||
|
||||
weapon.embedded(parent)
|
||||
|
||||
if(iscarbon(parent))
|
||||
initCarbon()
|
||||
else if(isclosedturf(parent))
|
||||
initTurf(throwingdatum)
|
||||
|
||||
/datum/component/embedded/RegisterWithParent()
|
||||
if(iscarbon(parent))
|
||||
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/jostleCheck)
|
||||
RegisterSignal(parent, COMSIG_CARBON_EMBED_RIP, .proc/ripOutCarbon)
|
||||
RegisterSignal(parent, COMSIG_CARBON_EMBED_REMOVAL, .proc/safeRemoveCarbon)
|
||||
else if(isclosedturf(parent))
|
||||
RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/examineTurf)
|
||||
RegisterSignal(parent, COMSIG_PARENT_QDELETING, .proc/itemMoved)
|
||||
|
||||
/datum/component/embedded/UnregisterFromParent()
|
||||
UnregisterSignal(parent, list(COMSIG_MOVABLE_MOVED, COMSIG_CARBON_EMBED_RIP, COMSIG_CARBON_EMBED_REMOVAL, COMSIG_PARENT_EXAMINE))
|
||||
|
||||
/datum/component/embedded/process()
|
||||
if(iscarbon(parent))
|
||||
processCarbon()
|
||||
|
||||
/datum/component/embedded/Destroy()
|
||||
if(weapon)
|
||||
UnregisterSignal(weapon, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING))
|
||||
if(overlay)
|
||||
var/atom/A = parent
|
||||
A.cut_overlay(overlay, TRUE)
|
||||
qdel(overlay)
|
||||
|
||||
return ..()
|
||||
|
||||
////////////////////////////////////////
|
||||
/////////////HUMAN PROCS////////////////
|
||||
////////////////////////////////////////
|
||||
|
||||
/// Set up an instance of embedding for a carbon. This is basically an extension of Initialize() so not much to say
|
||||
/datum/component/embedded/proc/initCarbon()
|
||||
START_PROCESSING(SSdcs, src)
|
||||
var/mob/living/carbon/victim = parent
|
||||
if(!istype(limb))
|
||||
limb = pick(victim.bodyparts)
|
||||
|
||||
limb.embedded_objects |= weapon // on the inside... on the inside...
|
||||
weapon.forceMove(victim)
|
||||
RegisterSignal(weapon, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING), .proc/byeItemCarbon)
|
||||
|
||||
if(harmful)
|
||||
victim.visible_message("<span class='danger'>[weapon] embeds itself in [victim]'s [limb.name]!</span>",ignored_mobs=victim)
|
||||
to_chat(victim, "<span class='userdanger'>[weapon] embeds itself in your [limb.name]!</span>")
|
||||
victim.throw_alert("embeddedobject", /obj/screen/alert/embeddedobject)
|
||||
playsound(victim,'sound/weapons/bladeslice.ogg', 40)
|
||||
weapon.add_mob_blood(victim)//it embedded itself in you, of course it's bloody!
|
||||
var/damage = weapon.w_class * impact_pain_mult
|
||||
limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage)
|
||||
SEND_SIGNAL(victim, COMSIG_ADD_MOOD_EVENT, "embedded", /datum/mood_event/embedded)
|
||||
else
|
||||
victim.visible_message("<span class='danger'>[weapon] sticks itself to [victim]'s [limb.name]!</span>",ignored_mobs=victim)
|
||||
to_chat(victim, "<span class='userdanger'>[weapon] sticks itself to your [limb.name]!</span>")
|
||||
|
||||
/// Called every time a carbon with a harmful embed moves, rolling a chance for the item to cause pain. The chance is halved if the carbon is crawling or walking.
|
||||
/datum/component/embedded/proc/jostleCheck()
|
||||
var/mob/living/carbon/victim = parent
|
||||
|
||||
var/chance = jostle_chance
|
||||
if(victim.m_intent == MOVE_INTENT_WALK || !(victim.mobility_flags & MOBILITY_STAND))
|
||||
chance *= 0.5
|
||||
|
||||
if(harmful && prob(chance))
|
||||
var/damage = weapon.w_class * jostle_pain_mult
|
||||
limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage)
|
||||
to_chat(victim, "<span class='userdanger'>[weapon] embedded in your [limb.name] jostles and stings!</span>")
|
||||
|
||||
|
||||
/// Called when then item randomly falls out of a carbon. This handles the damage and descriptors, then calls safe_remove()
|
||||
/datum/component/embedded/proc/fallOutCarbon()
|
||||
var/mob/living/carbon/victim = parent
|
||||
|
||||
if(harmful)
|
||||
var/damage = weapon.w_class * remove_pain_mult
|
||||
limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage)
|
||||
victim.visible_message("<span class='danger'>[weapon] falls out of [victim.name]'s [limb.name]!</span>", ignored_mobs=victim)
|
||||
to_chat(victim, "<span class='userdanger'>[weapon] falls out of your [limb.name]!</span>")
|
||||
else
|
||||
victim.visible_message("<span class='danger'>[weapon] falls off of [victim.name]'s [limb.name]!</span>", ignored_mobs=victim)
|
||||
to_chat(victim, "<span class='userdanger'>[weapon] falls off of your [limb.name]!</span>")
|
||||
|
||||
safeRemoveCarbon()
|
||||
|
||||
|
||||
/// Called when a carbon with an object embedded/stuck to them inspects themselves and clicks the appropriate link to begin ripping the item out. This handles the ripping attempt, descriptors, and dealing damage, then calls safe_remove()
|
||||
/datum/component/embedded/proc/ripOutCarbon(datum/source, obj/item/I, obj/item/bodypart/limb)
|
||||
if(I != weapon || src.limb != limb)
|
||||
return
|
||||
|
||||
var/mob/living/carbon/victim = parent
|
||||
var/time_taken = rip_time * weapon.w_class
|
||||
|
||||
victim.visible_message("<span class='warning'>[victim] attempts to remove [weapon] from [victim.p_their()] [limb.name].</span>","<span class='notice'>You attempt to remove [weapon] from your [limb.name]... (It will take [DisplayTimeText(time_taken)].)</span>")
|
||||
if(do_after(victim, time_taken, target = victim))
|
||||
if(!weapon || !limb || weapon.loc != victim || !(weapon in limb.embedded_objects))
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
if(harmful)
|
||||
var/damage = weapon.w_class * remove_pain_mult
|
||||
limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage) //It hurts to rip it out, get surgery you dingus.
|
||||
victim.emote("scream")
|
||||
victim.visible_message("<span class='notice'>[victim] successfully rips [weapon] out of [victim.p_their()] [limb.name]!</span>", "<span class='notice'>You successfully remove [weapon] from your [limb.name].</span>")
|
||||
else
|
||||
victim.visible_message("<span class='notice'>[victim] successfully rips [weapon] off of [victim.p_their()] [limb.name]!</span>", "<span class='notice'>You successfully remove [weapon] from your [limb.name].</span>")
|
||||
|
||||
safeRemoveCarbon(TRUE)
|
||||
|
||||
|
||||
/// This proc handles the final step and actual removal of an embedded/stuck item from a carbon, whether or not it was actually removed safely.
|
||||
/// Pass TRUE for to_hands if we want it to go to the victim's hands when they pull it out
|
||||
/datum/component/embedded/proc/safeRemoveCarbon(to_hands)
|
||||
var/mob/living/carbon/victim = parent
|
||||
limb.embedded_objects -= weapon
|
||||
|
||||
UnregisterSignal(weapon, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING)) // have to unhook these here so they don't also register as having disappeared
|
||||
|
||||
if(!weapon)
|
||||
if(!victim.has_embedded_objects())
|
||||
victim.clear_alert("embeddedobject")
|
||||
SEND_SIGNAL(victim, COMSIG_CLEAR_MOOD_EVENT, "embedded")
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
if(weapon.unembedded()) // if it deleted itself
|
||||
weapon = null
|
||||
if(!victim.has_embedded_objects())
|
||||
victim.clear_alert("embeddedobject")
|
||||
SEND_SIGNAL(victim, COMSIG_CLEAR_MOOD_EVENT, "embedded")
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
if(to_hands)
|
||||
victim.put_in_hands(weapon)
|
||||
else
|
||||
weapon.forceMove(get_turf(victim))
|
||||
|
||||
if(!victim.has_embedded_objects())
|
||||
victim.clear_alert("embeddedobject")
|
||||
SEND_SIGNAL(victim, COMSIG_CLEAR_MOOD_EVENT, "embedded")
|
||||
qdel(src)
|
||||
|
||||
|
||||
/// Something deleted or moved our weapon while it was embedded, how rude!
|
||||
/datum/component/embedded/proc/byeItemCarbon()
|
||||
var/mob/living/carbon/victim = parent
|
||||
limb.embedded_objects -= weapon
|
||||
UnregisterSignal(weapon, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING))
|
||||
|
||||
if(victim)
|
||||
to_chat(victim, "<span class='userdanger'>\The [weapon] that was embedded in your [limb.name] disappears!</span>")
|
||||
if(!victim.has_embedded_objects())
|
||||
victim.clear_alert("embeddedobject")
|
||||
SEND_SIGNAL(victim, COMSIG_CLEAR_MOOD_EVENT, "embedded")
|
||||
weapon = null
|
||||
qdel(src)
|
||||
|
||||
|
||||
/// Items embedded/stuck to carbons both check whether they randomly fall out (if applicable), as well as if the target mob and limb still exists.
|
||||
/// Items harmfully embedded in carbons have an additional check for random pain (if applicable)
|
||||
/datum/component/embedded/proc/processCarbon()
|
||||
var/mob/living/carbon/victim = parent
|
||||
|
||||
if(!victim || !limb) // in case the victim and/or their limbs exploded (say, due to a sticky bomb)
|
||||
weapon.forceMove(get_turf(weapon))
|
||||
qdel(src)
|
||||
|
||||
if(victim.stat == DEAD)
|
||||
return
|
||||
|
||||
var/damage = weapon.w_class * pain_mult
|
||||
var/chance = pain_chance
|
||||
if(pain_stam_pct && IS_STAMCRIT(victim)) //if it's a less-lethal embed, give them a break if they're already stamcritted
|
||||
chance *= 0.3
|
||||
damage *= 0.7
|
||||
|
||||
if(harmful && prob(chance))
|
||||
limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage)
|
||||
to_chat(victim, "<span class='userdanger'>[weapon] embedded in your [limb.name] hurts!</span>")
|
||||
|
||||
if(prob(fall_chance))
|
||||
fallOutCarbon()
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////
|
||||
//////////////TURF PROCS////////////////
|
||||
////////////////////////////////////////
|
||||
|
||||
/// Turfs are much lower maintenance, since we don't care if they're in pain, but since they don't bleed or scream, we draw an overlay to show their status.
|
||||
/// The only difference pointy/sticky items make here is text descriptors and pointy objects making a spark shower on impact.
|
||||
/datum/component/embedded/proc/initTurf(datum/thrownthing/throwingdatum)
|
||||
var/turf/closed/hit = parent
|
||||
|
||||
// we can't store the item IN the turf (cause turfs are just kinda... there), so we fake it by making the item invisible and bailing if it moves due to a blast
|
||||
weapon.forceMove(hit)
|
||||
weapon.invisibility = INVISIBILITY_ABSTRACT
|
||||
RegisterSignal(weapon, COMSIG_MOVABLE_MOVED, .proc/itemMoved)
|
||||
|
||||
var/pixelX = rand(-2, 2)
|
||||
var/pixelY = rand(-1, 3) // bias this upwards since in-hands are usually on the lower end of the sprite
|
||||
|
||||
switch(throwingdatum.init_dir)
|
||||
if(NORTH)
|
||||
pixelY -= 2
|
||||
if(SOUTH)
|
||||
pixelY += 2
|
||||
if(WEST)
|
||||
pixelX += 2
|
||||
if(EAST)
|
||||
pixelX -= 2
|
||||
|
||||
if(throwingdatum.init_dir in list(NORTH, WEST, NORTHWEST, SOUTHWEST))
|
||||
overlay = mutable_appearance(icon=weapon.righthand_file,icon_state=weapon.item_state)
|
||||
else
|
||||
overlay = mutable_appearance(icon=weapon.lefthand_file,icon_state=weapon.item_state)
|
||||
|
||||
var/matrix/M = matrix()
|
||||
M.Translate(pixelX, pixelY)
|
||||
overlay.transform = M
|
||||
hit.add_overlay(overlay, TRUE)
|
||||
|
||||
if(harmful)
|
||||
hit.visible_message("<span class='danger'>[weapon] embeds itself in [hit]!</span>")
|
||||
playsound(hit,'sound/weapons/bladeslice.ogg', 70)
|
||||
|
||||
var/datum/effect_system/spark_spread/sparks = new
|
||||
sparks.set_up(1, 1, parent)
|
||||
sparks.attach(parent)
|
||||
sparks.start()
|
||||
else
|
||||
hit.visible_message("<span class='danger'>[weapon] sticks itself to [hit]!</span>")
|
||||
|
||||
|
||||
/datum/component/embedded/proc/examineTurf(datum/source, mob/user, list/examine_list)
|
||||
if(harmful)
|
||||
examine_list += "\t <a href='?src=[REF(src)];embedded_object=[REF(weapon)]' class='warning'>There is \a [weapon] embedded in [parent]!</a>"
|
||||
else
|
||||
examine_list += "\t <a href='?src=[REF(src)];embedded_object=[REF(weapon)]' class='warning'>There is \a [weapon] stuck to [parent]!</a>"
|
||||
|
||||
|
||||
/// Someone is ripping out the item from the turf by hand
|
||||
/datum/component/embedded/Topic(datum/source, href_list)
|
||||
var/mob/living/us = usr
|
||||
if(in_range(us, parent) && locate(href_list["embedded_object"]) == weapon)
|
||||
if(harmful)
|
||||
us.visible_message("<span class='notice'>[us] begins unwedging [weapon] from [parent].</span>", "<span class='notice'>You begin unwedging [weapon] from [parent]...</span>")
|
||||
else
|
||||
us.visible_message("<span class='notice'>[us] begins unsticking [weapon] from [parent].</span>", "<span class='notice'>You begin unsticking [weapon] from [parent]...</span>")
|
||||
|
||||
if(do_after(us, 30, target = parent))
|
||||
us.put_in_hands(weapon)
|
||||
weapon.unembedded()
|
||||
qdel(src)
|
||||
|
||||
|
||||
/// This proc handles if something knocked the invisible item loose from the turf somehow (probably an explosion). Just make it visible and say it fell loose, then get outta here.
|
||||
/datum/component/embedded/proc/itemMoved()
|
||||
weapon.invisibility = initial(weapon.invisibility)
|
||||
weapon.visible_message("<span class='notice'>[weapon] falls loose from [parent].</span>")
|
||||
weapon.unembedded()
|
||||
qdel(src)
|
||||
@@ -144,7 +144,7 @@
|
||||
var/obj/item/projectile/picked_projectiletype = pickweight(weighted_projectile_types)
|
||||
|
||||
var/obj/item/master = comp.parent
|
||||
comp.appliedComponents += master.AddComponent(/datum/component/mirv, picked_projectiletype)
|
||||
comp.appliedComponents += master.AddComponent(/datum/component/shrapnel, picked_projectiletype)
|
||||
return "[newName] of [initial(picked_projectiletype.name)] shrapnel"
|
||||
|
||||
/datum/fantasy_affix/strength
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
/**
|
||||
* omen.dm: For when you want someone to have a really bad day
|
||||
*
|
||||
* When you attach an omen component to someone, they start running the risk of all sorts of bad environmental injuries, like nearby vending machines randomly falling on you,
|
||||
* or hitting your head really hard when you slip and fall, or... well, for now those two are all I have. More will come.
|
||||
*
|
||||
* Omens are removed once the victim is either maimed by one of the possible injuries, or if they receive a blessing (read: bashing with a bible) from the chaplain.
|
||||
*/
|
||||
/datum/component/omen
|
||||
dupe_mode = COMPONENT_DUPE_UNIQUE
|
||||
|
||||
/// Whatever's causing the omen, if there is one. Destroying the vessel won't stop the omen, but we destroy the vessel (if one exists) upon the omen ending
|
||||
var/obj/vessel
|
||||
|
||||
/datum/component/omen/Initialize(silent=FALSE, vessel)
|
||||
if(!isliving(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
var/mob/person = parent
|
||||
if(!silent)
|
||||
to_chat(person, "<span class='warning'>You get a bad feeling...</span>")
|
||||
src.vessel = vessel
|
||||
|
||||
/datum/component/omen/Destroy(force, silent)
|
||||
if(vessel)
|
||||
vessel.visible_message("<span class='warning'>[vessel] burns up in a sinister flash, taking an evil energy with it...</span>")
|
||||
vessel = null
|
||||
return ..()
|
||||
|
||||
/datum/component/omen/RegisterWithParent()
|
||||
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/check_accident)
|
||||
RegisterSignal(parent, COMSIG_LIVING_STATUS_KNOCKDOWN, .proc/check_slip)
|
||||
RegisterSignal(parent, COMSIG_ADD_MOOD_EVENT, .proc/check_bless)
|
||||
|
||||
/datum/component/omen/UnregisterFromParent()
|
||||
UnregisterSignal(parent, list(COMSIG_LIVING_STATUS_KNOCKDOWN, COMSIG_MOVABLE_MOVED, COMSIG_ADD_MOOD_EVENT))
|
||||
|
||||
/**
|
||||
* check_accident() is called each step we take
|
||||
*
|
||||
* While we're walking around, roll to see if there's any environmental hazards (currently only vending machines) on one of the adjacent tiles we can trigger.
|
||||
* We do the prob() at the beginning to A. add some tension for /when/ it will strike, and B. (more importantly) ameliorate the fact that we're checking up to 5 turfs's contents each time
|
||||
*/
|
||||
/datum/component/omen/proc/check_accident(atom/movable/our_guy)
|
||||
if(!prob(15))
|
||||
return
|
||||
for(var/t in get_adjacent_open_turfs(our_guy))
|
||||
var/turf/the_turf = t
|
||||
for(var/obj/machinery/vending/darth_vendor in the_turf)
|
||||
if(darth_vendor.tiltable)
|
||||
darth_vendor.tilt(our_guy)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
/// If we get knocked down, see if we have a really bad slip and bash our head hard
|
||||
/datum/component/omen/proc/check_slip(mob/living/our_guy, amount)
|
||||
if(amount <= 0 || prob(50)) // 50% chance to bonk our head
|
||||
return
|
||||
|
||||
var/obj/item/bodypart/the_head = our_guy.get_bodypart(BODY_ZONE_HEAD)
|
||||
if(!the_head)
|
||||
return
|
||||
|
||||
playsound(get_turf(our_guy), "sound/effects/tableheadsmash.ogg", 90, TRUE)
|
||||
our_guy.visible_message("<span class='danger'>[our_guy] hits [our_guy.p_their()] head really badly falling down!</span>", "<span class='userdanger'>You hit your head really badly falling down!</span>")
|
||||
the_head.receive_damage(75)
|
||||
our_guy.adjustOrganLoss(ORGAN_SLOT_BRAIN, 100)
|
||||
qdel(src)
|
||||
|
||||
/// Hijack the mood system to see if we get the blessing mood event to cancel the omen
|
||||
/datum/component/omen/proc/check_bless(mob/living/our_guy, category)
|
||||
if(category != "blessing")
|
||||
return
|
||||
to_chat(our_guy, "<span class='nicegreen'>You feel a horrible omen lifted off your shoulders!</span>")
|
||||
qdel(src)
|
||||
@@ -1,283 +0,0 @@
|
||||
/*
|
||||
* This component is used when you want to create a bunch of shrapnel or projectiles (say, shrapnel from a fragmentation grenade, or buckshot from a shotgun) from a central point,
|
||||
* without necessarily printing a separate message for every single impact. This component should be instantiated right when you need it (like the moment of firing), then activated
|
||||
* by signal.
|
||||
*
|
||||
* Pellet cloud currently works on two classes of sources: directed (ammo casings), and circular (grenades, landmines).
|
||||
* -Directed: This means you're shooting multiple pellets, like buckshot. If an ammo casing is defined as having multiple pellets, it will automatically create a pellet cloud
|
||||
* and call COMSIG_PELLET_CLOUD_INIT (see [/obj/item/ammo_casing/proc/fire_casing]). Thus, the only projectiles fired will be the ones fired here.
|
||||
* The magnitude var controls how many pellets are created.
|
||||
* -Circular: This results in a big spray of shrapnel flying all around the detonation point when the grenade fires COMSIG_GRENADE_PRIME or landmine triggers COMSIG_MINE_TRIGGERED.
|
||||
* The magnitude var controls how big the detonation radius is (the bigger the magnitude, the more shrapnel is created). Grenades can be covered with bodies to reduce shrapnel output.
|
||||
*
|
||||
* Once all of the fired projectiles either hit a target or disappear due to ranging out/whatever else, we resolve the list of all the things we hit and print aggregate messages so we get
|
||||
* one "You're hit by 6 buckshot pellets" vs 6x "You're hit by the buckshot blah blah" messages.
|
||||
*
|
||||
* Note that this is how all guns handle shooting ammo casings with multiple pellets, in case such a thing comes up.
|
||||
*/
|
||||
|
||||
/datum/component/pellet_cloud
|
||||
/// What's the projectile path of the shrapnel we're shooting?
|
||||
var/projectile_type
|
||||
|
||||
/// How many shrapnel projectiles are we responsible for tracking? May be reduced for grenades if someone dives on top of it. Defined by ammo casing for casings, derived from magnitude otherwise
|
||||
var/num_pellets
|
||||
/// For grenades/landmines, how big is the radius of turfs we're targeting? Note this does not effect the projectiles range, only how many we generate
|
||||
var/radius = 4
|
||||
|
||||
/// The list of pellets we're responsible for tracking, once these are all accounted for, we finalize.
|
||||
var/list/pellets = list()
|
||||
/// An associated list with the atom hit as the key and how many pellets they've eaten for the value, for printing aggregate messages
|
||||
var/list/targets_hit = list()
|
||||
/// For grenades, any /mob/living's the grenade is moved onto, see [/datum/component/pellet_cloud/proc/handle_martyrs()]
|
||||
var/list/bodies
|
||||
/// For grenades, tracking people who die covering a grenade for achievement purposes, see [/datum/component/pellet_cloud/proc/handle_martyrs()]
|
||||
var/list/purple_hearts
|
||||
|
||||
/// For grenades, tracking how many pellets are removed due to martyrs and how many pellets are added due to the last person to touch it being on top of it
|
||||
var/pellet_delta = 0
|
||||
/// how many pellets ranged out without hitting anything
|
||||
var/terminated
|
||||
/// how many pellets impacted something
|
||||
var/hits
|
||||
/// If the parent tried deleting and we're not done yet, we send it to nullspace then delete it after
|
||||
var/queued_delete = FALSE
|
||||
|
||||
/// for if we're an ammo casing being fired
|
||||
var/mob/living/shooter
|
||||
|
||||
/datum/component/pellet_cloud/Initialize(projectile_type=/obj/item/shrapnel, magnitude=5)
|
||||
if(!isammocasing(parent) && !isgrenade(parent) && !islandmine(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
if(magnitude < 1)
|
||||
stack_trace("Invalid magnitude [magnitude] < 1 on pellet_cloud, parent: [parent]")
|
||||
magnitude = 1
|
||||
|
||||
src.projectile_type = projectile_type
|
||||
|
||||
if(isammocasing(parent))
|
||||
num_pellets = magnitude
|
||||
else if(isgrenade(parent) || islandmine(parent))
|
||||
radius = magnitude
|
||||
|
||||
/datum/component/pellet_cloud/Destroy(force, silent)
|
||||
purple_hearts = null
|
||||
pellets = null
|
||||
targets_hit = null
|
||||
bodies = null
|
||||
return ..()
|
||||
|
||||
/datum/component/pellet_cloud/RegisterWithParent()
|
||||
RegisterSignal(parent, COMSIG_PARENT_PREQDELETED, .proc/nullspace_parent)
|
||||
if(isammocasing(parent))
|
||||
RegisterSignal(parent, COMSIG_PELLET_CLOUD_INIT, .proc/create_casing_pellets)
|
||||
else if(isgrenade(parent))
|
||||
RegisterSignal(parent, COMSIG_GRENADE_ARMED, .proc/grenade_armed)
|
||||
RegisterSignal(parent, COMSIG_GRENADE_PRIME, .proc/create_blast_pellets)
|
||||
else if(islandmine(parent))
|
||||
RegisterSignal(parent, COMSIG_MINE_TRIGGERED, .proc/create_blast_pellets)
|
||||
|
||||
/datum/component/pellet_cloud/UnregisterFromParent()
|
||||
UnregisterSignal(parent, list(COMSIG_PARENT_PREQDELETED, COMSIG_PELLET_CLOUD_INIT, COMSIG_GRENADE_PRIME, COMSIG_GRENADE_ARMED, COMSIG_MOVABLE_MOVED, COMSIG_MOVABLE_UNCROSSED, COMSIG_MINE_TRIGGERED, COMSIG_ITEM_DROPPED))
|
||||
|
||||
/**
|
||||
* create_casing_pellets() is for directed pellet clouds for ammo casings that have multiple pellets (buckshot and scatter lasers for instance)
|
||||
*
|
||||
* Honestly this is mostly just a rehash of [/obj/item/ammo_casing/proc/fire_casing()] for pellet counts > 1, except this lets us tamper with the pellets and hook onto them for tracking purposes.
|
||||
* The arguments really don't matter, this proc is triggered by COMSIG_PELLET_CLOUD_INIT which is only for this really, it's just a big mess of the state vars we need for doing the stuff over here.
|
||||
*/
|
||||
/datum/component/pellet_cloud/proc/create_casing_pellets(obj/item/ammo_casing/shell, atom/target, mob/living/user, fired_from, randomspread, spread, zone_override, params, distro)
|
||||
shooter = user
|
||||
var/targloc = get_turf(target)
|
||||
if(!zone_override)
|
||||
zone_override = shooter.zone_selected
|
||||
|
||||
for(var/i in 1 to num_pellets)
|
||||
shell.ready_proj(target, user, SUPPRESSED_VERY, zone_override, fired_from)
|
||||
if(distro)
|
||||
if(randomspread)
|
||||
spread = round((rand() - 0.5) * distro)
|
||||
else //Smart spread
|
||||
spread = round((i / num_pellets - 0.5) * distro)
|
||||
|
||||
RegisterSignal(shell.BB, COMSIG_PROJECTILE_SELF_ON_HIT, .proc/pellet_hit)
|
||||
RegisterSignal(shell.BB, list(COMSIG_PROJECTILE_RANGE_OUT, COMSIG_PARENT_QDELETING), .proc/pellet_range)
|
||||
pellets += shell.BB
|
||||
if(!shell.throw_proj(target, targloc, shooter, params, spread))
|
||||
return
|
||||
if(i != num_pellets)
|
||||
shell.newshot()
|
||||
|
||||
/**
|
||||
* create_blast_pellets() is for when we have a central point we want to shred the surroundings of with a ring of shrapnel, namely frag grenades and landmines.
|
||||
*
|
||||
* Note that grenades have extra handling for someone throwing themselves/being thrown on top of it, while landmines do not (obviously, it's a landmine!). See [/datum/component/pellet_cloud/proc/handle_martyrs()]
|
||||
*/
|
||||
/datum/component/pellet_cloud/proc/create_blast_pellets(obj/O, mob/living/lanced_by)
|
||||
var/atom/A = parent
|
||||
|
||||
if(isgrenade(parent)) // handle_martyrs can reduce the radius and thus the number of pellets we produce if someone dives on top of a frag grenade
|
||||
handle_martyrs(lanced_by) // note that we can modify radius in this proc
|
||||
|
||||
if(radius < 1)
|
||||
return
|
||||
|
||||
var/list/all_the_turfs_were_gonna_lacerate = RANGE_TURFS(radius, A) - RANGE_TURFS(radius-1, A)
|
||||
num_pellets = all_the_turfs_were_gonna_lacerate.len + pellet_delta
|
||||
|
||||
for(var/T in all_the_turfs_were_gonna_lacerate)
|
||||
var/turf/shootat_turf = T
|
||||
pew(shootat_turf)
|
||||
|
||||
/**
|
||||
* handle_martyrs() is used for grenades that shoot shrapnel to check if anyone threw themselves/were thrown on top of the grenade, thus absorbing a good chunk of the shrapnel
|
||||
*
|
||||
* Between the time the grenade is armed and the actual detonation, we set var/list/bodies to the list of mobs currently on the new tile, as if the grenade landed on top of them, tracking if any of them move off the tile and removing them from the "under" list
|
||||
* Once the grenade detonates, handle_martyrs() is called and gets all the new mobs on the tile, and add the ones not in var/list/bodies to var/list/martyrs
|
||||
* We then iterate through the martyrs and reduce the shrapnel magnitude for each mob on top of it, shredding each of them with some of the shrapnel they helped absorb. This can snuff out all of the shrapnel if there's enough bodies
|
||||
*
|
||||
* Note we track anyone who's alive and client'd when they get shredded in var/list/purple_hearts, for achievement checking later
|
||||
*/
|
||||
/datum/component/pellet_cloud/proc/handle_martyrs(mob/living/lanced_by)
|
||||
var/magnitude_absorbed
|
||||
var/list/martyrs = list()
|
||||
|
||||
var/self_harm_radius_mult = 3
|
||||
|
||||
if(lanced_by && prob(60))
|
||||
to_chat(lanced_by, "<span class='userdanger'>Your plan to whack someone with a grenade on a stick backfires on you, literally!</span>")
|
||||
self_harm_radius_mult = 1 // we'll still give the guy who got hit some extra shredding, but not 3*radius
|
||||
pellet_delta += radius
|
||||
for(var/i in 1 to radius)
|
||||
pew(lanced_by) // thought you could be tricky and lance someone with no ill effects!!
|
||||
|
||||
for(var/mob/living/body in get_turf(parent))
|
||||
if(body == shooter)
|
||||
pellet_delta += radius * self_harm_radius_mult
|
||||
for(var/i in 1 to radius * self_harm_radius_mult)
|
||||
pew(body) // free shrapnel if it goes off in your hand, and it doesn't even count towards the absorbed. fun!
|
||||
else if(!(body in bodies))
|
||||
martyrs += body // promoted from a corpse to a hero
|
||||
|
||||
for(var/M in martyrs)
|
||||
var/mob/living/martyr = M
|
||||
if(radius > 4)
|
||||
martyr.visible_message("<b><span class='danger'>[martyr] heroically covers \the [parent] with [martyr.p_their()] body, absorbing a load of the shrapnel!</span></b>", "<span class='userdanger'>You heroically cover \the [parent] with your body, absorbing a load of the shrapnel!</span>")
|
||||
magnitude_absorbed += round(radius * 0.5)
|
||||
else if(radius >= 2)
|
||||
martyr.visible_message("<b><span class='danger'>[martyr] heroically covers \the [parent] with [martyr.p_their()] body, absorbing some of the shrapnel!</span></b>", "<span class='userdanger'>You heroically cover \the [parent] with your body, absorbing some of the shrapnel!</span>")
|
||||
magnitude_absorbed += 2
|
||||
else
|
||||
martyr.visible_message("<b><span class='danger'>[martyr] heroically covers \the [parent] with [martyr.p_their()] body, snuffing out the shrapnel!</span></b>", "<span class='userdanger'>You heroically cover \the [parent] with your body, snuffing out the shrapnel!</span>")
|
||||
magnitude_absorbed = radius
|
||||
|
||||
var/pellets_absorbed = (radius ** 2) - ((radius - magnitude_absorbed - 1) ** 2)
|
||||
radius -= magnitude_absorbed
|
||||
pellet_delta -= round(pellets_absorbed * 0.5)
|
||||
|
||||
if(martyr.stat != DEAD && martyr.client)
|
||||
LAZYADD(purple_hearts, martyr)
|
||||
RegisterSignal(martyr, COMSIG_PARENT_QDELETING, .proc/on_target_qdel, override=TRUE)
|
||||
|
||||
for(var/i in 1 to round(pellets_absorbed * 0.5))
|
||||
pew(martyr)
|
||||
|
||||
if(radius < 1)
|
||||
break
|
||||
|
||||
///One of our pellets hit something, record what it was and check if we're done (terminated == num_pellets)
|
||||
/datum/component/pellet_cloud/proc/pellet_hit(obj/item/projectile/P, atom/movable/firer, atom/target, Angle)
|
||||
pellets -= P
|
||||
terminated++
|
||||
hits++
|
||||
targets_hit[target]++
|
||||
if(targets_hit[target] == 1)
|
||||
RegisterSignal(target, COMSIG_PARENT_QDELETING, .proc/on_target_qdel, override=TRUE)
|
||||
UnregisterSignal(P, list(COMSIG_PARENT_QDELETING, COMSIG_PROJECTILE_RANGE_OUT, COMSIG_PROJECTILE_SELF_ON_HIT))
|
||||
if(terminated == num_pellets)
|
||||
finalize()
|
||||
|
||||
///One of our pellets disappeared due to hitting their max range (or just somehow got qdel'd), remove it from our list and check if we're done (terminated == num_pellets)
|
||||
/datum/component/pellet_cloud/proc/pellet_range(obj/item/projectile/P)
|
||||
pellets -= P
|
||||
terminated++
|
||||
UnregisterSignal(P, list(COMSIG_PARENT_QDELETING, COMSIG_PROJECTILE_RANGE_OUT, COMSIG_PROJECTILE_SELF_ON_HIT))
|
||||
if(terminated == num_pellets)
|
||||
finalize()
|
||||
|
||||
/// Minor convenience function for creating each shrapnel piece with circle explosions, mostly stolen from the MIRV component
|
||||
/datum/component/pellet_cloud/proc/pew(atom/target, spread=0)
|
||||
var/obj/item/projectile/P = new projectile_type(get_turf(parent))
|
||||
|
||||
//Shooting Code:
|
||||
P.spread = spread
|
||||
P.original = target
|
||||
P.fired_from = parent
|
||||
P.firer = parent // don't hit ourself that would be really annoying
|
||||
P.permutated += parent // don't hit the target we hit already with the flak
|
||||
P.suppressed = SUPPRESSED_VERY // set the projectiles to make no message so we can do our own aggregate message
|
||||
P.preparePixelProjectile(target, parent)
|
||||
RegisterSignal(P, COMSIG_PROJECTILE_SELF_ON_HIT, .proc/pellet_hit)
|
||||
RegisterSignal(P, list(COMSIG_PROJECTILE_RANGE_OUT, COMSIG_PARENT_QDELETING), .proc/pellet_range)
|
||||
pellets += P
|
||||
P.fire()
|
||||
|
||||
///All of our pellets are accounted for, time to go target by target and tell them how many things they got hit by.
|
||||
/datum/component/pellet_cloud/proc/finalize()
|
||||
var/obj/item/projectile/P = projectile_type
|
||||
var/proj_name = initial(P.name)
|
||||
|
||||
for(var/atom/target in targets_hit)
|
||||
var/num_hits = targets_hit[target]
|
||||
UnregisterSignal(target, COMSIG_PARENT_QDELETING)
|
||||
if(num_hits > 1)
|
||||
target.visible_message("<span class='danger'>[target] is hit by [num_hits] [proj_name]s!</span>", null, null, COMBAT_MESSAGE_RANGE, target)
|
||||
to_chat(target, "<span class='userdanger'>You're hit by [num_hits] [proj_name]s!</span>")
|
||||
else
|
||||
target.visible_message("<span class='danger'>[target] is hit by a [proj_name]!</span>", null, null, COMBAT_MESSAGE_RANGE, target)
|
||||
to_chat(target, "<span class='userdanger'>You're hit by a [proj_name]!</span>")
|
||||
|
||||
UnregisterSignal(parent, COMSIG_PARENT_PREQDELETED)
|
||||
if(queued_delete)
|
||||
qdel(parent)
|
||||
qdel(src)
|
||||
|
||||
/// Look alive, we're armed! Now we start watching to see if anyone's covering us
|
||||
/datum/component/pellet_cloud/proc/grenade_armed(obj/item/nade)
|
||||
if(ismob(nade.loc))
|
||||
shooter = nade.loc
|
||||
LAZYINITLIST(bodies)
|
||||
RegisterSignal(parent, COMSIG_ITEM_DROPPED, .proc/grenade_dropped)
|
||||
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/grenade_moved)
|
||||
RegisterSignal(parent, COMSIG_MOVABLE_UNCROSSED, .proc/grenade_uncrossed)
|
||||
|
||||
/// Someone dropped the grenade, so set them to the shooter in case they're on top of it when it goes off
|
||||
/datum/component/pellet_cloud/proc/grenade_dropped(obj/item/nade, mob/living/slick_willy)
|
||||
shooter = slick_willy
|
||||
grenade_moved()
|
||||
|
||||
/// Our grenade has moved, reset var/list/bodies so we're "on top" of any mobs currently on the tile
|
||||
/datum/component/pellet_cloud/proc/grenade_moved()
|
||||
LAZYCLEARLIST(bodies)
|
||||
for(var/mob/living/L in get_turf(parent))
|
||||
RegisterSignal(L, COMSIG_PARENT_QDELETING, .proc/on_target_qdel, override=TRUE)
|
||||
bodies += L
|
||||
|
||||
/// Someone who was originally "under" the grenade has moved off the tile and is now eligible for being a martyr and "covering" it
|
||||
/datum/component/pellet_cloud/proc/grenade_uncrossed(datum/source, atom/movable/AM)
|
||||
bodies -= AM
|
||||
|
||||
/// Our grenade or landmine or caseless shell or whatever tried deleting itself, so we intervene and nullspace it until we're done here
|
||||
/datum/component/pellet_cloud/proc/nullspace_parent()
|
||||
var/atom/movable/AM = parent
|
||||
AM.moveToNullspace()
|
||||
queued_delete = TRUE
|
||||
return TRUE
|
||||
|
||||
/// Someone who was originally "under" the grenade has moved off the tile and is now eligible for being a martyr and "covering" it
|
||||
/datum/component/pellet_cloud/proc/on_target_qdel(atom/target)
|
||||
UnregisterSignal(target, COMSIG_PARENT_QDELETING)
|
||||
targets_hit -= target
|
||||
bodies -= target
|
||||
purple_hearts -= target
|
||||
@@ -69,9 +69,8 @@
|
||||
out += "[out ? " and it " : "[master] "]seems to be glowing a bit."
|
||||
if(RAD_AMOUNT_HIGH to INFINITY) //At this level the object can contaminate other objects
|
||||
out += "[out ? " and it " : "[master] "]hurts to look at."
|
||||
if(!LAZYLEN(out))
|
||||
return
|
||||
out += "."
|
||||
else
|
||||
out += "."
|
||||
examine_list += out.Join()
|
||||
|
||||
/datum/component/radioactive/proc/rad_attack(datum/source, atom/movable/target, mob/living/user)
|
||||
|
||||
@@ -1,37 +1,36 @@
|
||||
/datum/component/mirv
|
||||
|
||||
/datum/component/shrapnel
|
||||
var/projectile_type
|
||||
var/radius // shoots a projectile for every turf on this radius from the hit target
|
||||
var/override_projectile_range
|
||||
|
||||
/datum/component/mirv/Initialize(projectile_type, radius=1, override_projectile_range)
|
||||
if(!isgun(parent) && !ismachinery(parent) && !isstructure(parent) && !isgrenade(parent))
|
||||
/datum/component/shrapnel/Initialize(projectile_type, radius=1, override_projectile_range)
|
||||
if(!isgun(parent) && !ismachinery(parent) && !isstructure(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
src.projectile_type = projectile_type
|
||||
src.radius = radius
|
||||
src.override_projectile_range = override_projectile_range
|
||||
if(isgrenade(parent))
|
||||
parent.AddComponent(/datum/component/pellet_cloud, projectile_type=projectile_type)
|
||||
|
||||
/datum/component/mirv/RegisterWithParent()
|
||||
/datum/component/shrapnel/RegisterWithParent()
|
||||
. = ..()
|
||||
if(ismachinery(parent) || isstructure(parent) || isgun(parent)) // turrets, etc
|
||||
RegisterSignal(parent, COMSIG_PROJECTILE_ON_HIT, .proc/projectile_hit)
|
||||
|
||||
/datum/component/mirv/UnregisterFromParent()
|
||||
/datum/component/shrapnel/UnregisterFromParent()
|
||||
. = ..()
|
||||
UnregisterSignal(parent, list(COMSIG_PROJECTILE_ON_HIT))
|
||||
|
||||
/datum/component/mirv/proc/projectile_hit(atom/fired_from, atom/movable/firer, atom/target, Angle)
|
||||
/datum/component/shrapnel/proc/projectile_hit(atom/fired_from, atom/movable/firer, atom/target, Angle)
|
||||
do_shrapnel(firer, target)
|
||||
|
||||
/datum/component/mirv/proc/do_shrapnel(mob/firer, atom/target)
|
||||
/datum/component/shrapnel/proc/do_shrapnel(mob/firer, atom/target)
|
||||
if(radius < 1)
|
||||
return
|
||||
var/turf/target_turf = get_turf(target)
|
||||
for(var/turf/shootat_turf in RANGE_TURFS(radius, target) - RANGE_TURFS(radius-1, target))
|
||||
|
||||
var/obj/item/projectile/P = new projectile_type(target_turf)
|
||||
|
||||
//Shooting Code:
|
||||
P.range = radius+1
|
||||
if(override_projectile_range)
|
||||
@@ -8,8 +8,6 @@
|
||||
var/list/faction = list("mining")
|
||||
|
||||
/datum/component/spawner/Initialize(_mob_types, _spawn_time, _faction, _spawn_text, _max_mobs)
|
||||
if(!isatom(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
if(_spawn_time)
|
||||
spawn_time=_spawn_time
|
||||
if(_mob_types)
|
||||
@@ -21,25 +19,20 @@
|
||||
if(_max_mobs)
|
||||
max_mobs=_max_mobs
|
||||
|
||||
RegisterSignal(parent, COMSIG_PARENT_QDELETING, .proc/stop_spawning)
|
||||
RegisterSignal(parent, COMSIG_OBJ_ATTACK_GENERIC, .proc/on_attack_generic)
|
||||
RegisterSignal(parent, list(COMSIG_PARENT_QDELETING), .proc/stop_spawning)
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
|
||||
/datum/component/spawner/process()
|
||||
try_spawn_mob()
|
||||
|
||||
/datum/component/spawner/proc/stop_spawning(datum/source, force, hint)
|
||||
|
||||
/datum/component/spawner/proc/stop_spawning(force, hint)
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
for(var/mob/living/simple_animal/L in spawned_mobs)
|
||||
if(L.nest == src)
|
||||
L.nest = null
|
||||
spawned_mobs = null
|
||||
|
||||
// Stopping clientless simple mobs' from indiscriminately bashing their own spawners due DestroySurroundings() et similars.
|
||||
/datum/component/spawner/proc/on_attack_generic(datum/source, mob/user, damage_amount, damage_type, damage_flag, sound_effect, armor_penetration)
|
||||
if(!user.client && ((user.faction & faction) || (user in spawned_mobs)))
|
||||
return COMPONENT_STOP_GENERIC_ATTACK
|
||||
|
||||
/datum/component/spawner/proc/try_spawn_mob()
|
||||
var/atom/P = parent
|
||||
if(spawned_mobs.len >= max_mobs)
|
||||
|
||||
@@ -34,8 +34,3 @@
|
||||
qdel(A)
|
||||
return
|
||||
. = ..()
|
||||
|
||||
/datum/component/storage/concrete/bluespace/bag_of_holding/can_be_inserted(obj/item/I, stop_messages = FALSE, mob/M)
|
||||
if(I.GetComponent(/datum/component/storage/concrete/bluespace/bag_of_holding))
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
@@ -11,17 +11,6 @@
|
||||
RegisterSignal(parent, COMSIG_MOVABLE_CROSSED, .proc/join_swarm)
|
||||
RegisterSignal(parent, COMSIG_MOVABLE_UNCROSSED, .proc/leave_swarm)
|
||||
|
||||
/datum/component/swarming/Destroy()
|
||||
if(is_swarming)
|
||||
for(var/A in swarm_members)
|
||||
var/datum/component/swarming/other_swarm = A
|
||||
other_swarm.swarm_members -= src
|
||||
swarm_members -= other_swarm
|
||||
if(!length(other_swarm.swarm_members))
|
||||
other_swarm.unswarm()
|
||||
unswarm()
|
||||
return ..()
|
||||
|
||||
/datum/component/swarming/proc/join_swarm(datum/source, atom/movable/AM)
|
||||
var/datum/component/swarming/other_swarm = AM.GetComponent(/datum/component/swarming)
|
||||
if(!other_swarm)
|
||||
|
||||
@@ -206,7 +206,7 @@
|
||||
user.set_resting(FALSE, TRUE, FALSE)
|
||||
user.forceMove(get_turf(target))
|
||||
target.adjustStaminaLoss(65)
|
||||
target.Paralyze(10)
|
||||
target.Paralyze(10)
|
||||
target.DefaultCombatKnockdown(20)
|
||||
if(ishuman(target) && iscarbon(user))
|
||||
target.grabbedby(user)
|
||||
@@ -354,7 +354,7 @@
|
||||
playsound(user, 'sound/effects/blobattack.ogg', 60, TRUE)
|
||||
playsound(user, 'sound/effects/splat.ogg', 70, TRUE)
|
||||
user.emote("scream")
|
||||
user.gain_trauma(/datum/brain_trauma/severe/paralysis/spinesnapped) // oopsie indeed!
|
||||
user.gain_trauma(/datum/brain_trauma/severe/paralysis/paraplegic) // oopsie indeed!
|
||||
shake_camera(user, 7, 7)
|
||||
user.overlay_fullscreen("flash", /obj/screen/fullscreen/flash)
|
||||
user.clear_fullscreen("flash", 4.5)
|
||||
@@ -415,10 +415,10 @@
|
||||
for(var/i = 0, i < speed, i++)
|
||||
var/obj/item/shard/shard = new /obj/item/shard(get_turf(user))
|
||||
//shard.embedding = list(embed_chance = 100, ignore_throwspeed_threshold = TRUE, impact_pain_mult=3, pain_chance=5)
|
||||
shard.updateEmbedding()
|
||||
//shard.AddElement(/datum/element/embed, shard.embedding)
|
||||
user.hitby(shard, skipcatch = TRUE, hitpush = FALSE)
|
||||
shard.embedding = list()
|
||||
shard.updateEmbedding()
|
||||
//shard.embedding = list()
|
||||
//shard.AddElement(/datum/element/embed, shard.embedding)
|
||||
W.obj_destruction()
|
||||
user.adjustStaminaLoss(10 * speed)
|
||||
user.DefaultCombatKnockdown(40)
|
||||
|
||||
@@ -1,311 +0,0 @@
|
||||
/**
|
||||
* Two Handed Component
|
||||
*
|
||||
* When applied to an item it will make it two handed
|
||||
*
|
||||
*/
|
||||
/datum/component/two_handed
|
||||
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS // Only one of the component can exist on an item
|
||||
var/wielded = FALSE /// Are we holding the two handed item properly
|
||||
var/force_multiplier = 0 /// The multiplier applied to force when wielded, does not work with force_wielded, and force_unwielded
|
||||
var/force_wielded = 0 /// The force of the item when weilded
|
||||
var/force_unwielded = 0 /// The force of the item when unweilded
|
||||
var/wieldsound = FALSE /// Play sound when wielded
|
||||
var/unwieldsound = FALSE /// Play sound when unwielded
|
||||
var/attacksound = FALSE /// Play sound on attack when wielded
|
||||
var/require_twohands = FALSE /// Does it have to be held in both hands
|
||||
var/icon_wielded = FALSE /// The icon that will be used when wielded
|
||||
var/obj/item/offhand/offhand_item = null /// Reference to the offhand created for the item
|
||||
var/sharpened_increase = 0 /// The amount of increase recived from sharpening the item
|
||||
|
||||
/**
|
||||
* Two Handed component
|
||||
*
|
||||
* vars:
|
||||
* * require_twohands (optional) Does the item need both hands to be carried
|
||||
* * wieldsound (optional) The sound to play when wielded
|
||||
* * unwieldsound (optional) The sound to play when unwielded
|
||||
* * attacksound (optional) The sound to play when wielded and attacking
|
||||
* * force_multiplier (optional) The force multiplier when wielded, do not use with force_wielded, and force_unwielded
|
||||
* * force_wielded (optional) The force setting when the item is wielded, do not use with force_multiplier
|
||||
* * force_unwielded (optional) The force setting when the item is unwielded, do not use with force_multiplier
|
||||
* * icon_wielded (optional) The icon to be used when wielded
|
||||
*/
|
||||
/datum/component/two_handed/Initialize(require_twohands=FALSE, wieldsound=FALSE, unwieldsound=FALSE, attacksound=FALSE, \
|
||||
force_multiplier=0, force_wielded=0, force_unwielded=0, icon_wielded=FALSE)
|
||||
if(!isitem(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
src.require_twohands = require_twohands
|
||||
src.wieldsound = wieldsound
|
||||
src.unwieldsound = unwieldsound
|
||||
src.attacksound = attacksound
|
||||
src.force_multiplier = force_multiplier
|
||||
src.force_wielded = force_wielded
|
||||
src.force_unwielded = force_unwielded
|
||||
src.icon_wielded = icon_wielded
|
||||
|
||||
// Inherit the new values passed to the component
|
||||
/datum/component/two_handed/InheritComponent(datum/component/two_handed/new_comp, original, require_twohands, wieldsound, unwieldsound, \
|
||||
force_multiplier, force_wielded, force_unwielded, icon_wielded)
|
||||
if(!original)
|
||||
return
|
||||
if(require_twohands)
|
||||
src.require_twohands = require_twohands
|
||||
if(wieldsound)
|
||||
src.wieldsound = wieldsound
|
||||
if(unwieldsound)
|
||||
src.unwieldsound = unwieldsound
|
||||
if(attacksound)
|
||||
src.attacksound = attacksound
|
||||
if(force_multiplier)
|
||||
src.force_multiplier = force_multiplier
|
||||
if(force_wielded)
|
||||
src.force_wielded = force_wielded
|
||||
if(force_unwielded)
|
||||
src.force_unwielded = force_unwielded
|
||||
if(icon_wielded)
|
||||
src.icon_wielded = icon_wielded
|
||||
|
||||
// register signals withthe parent item
|
||||
/datum/component/two_handed/RegisterWithParent()
|
||||
RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, .proc/on_equip)
|
||||
RegisterSignal(parent, COMSIG_ITEM_DROPPED, .proc/on_drop)
|
||||
RegisterSignal(parent, COMSIG_ITEM_ATTACK_SELF, .proc/on_attack_self)
|
||||
RegisterSignal(parent, COMSIG_ITEM_ATTACK, .proc/on_attack)
|
||||
RegisterSignal(parent, COMSIG_ATOM_UPDATE_ICON, .proc/on_update_icon)
|
||||
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/on_moved)
|
||||
RegisterSignal(parent, COMSIG_ITEM_SHARPEN_ACT, .proc/on_sharpen)
|
||||
|
||||
// Remove all siginals registered to the parent item
|
||||
/datum/component/two_handed/UnregisterFromParent()
|
||||
UnregisterSignal(parent, list(COMSIG_ITEM_EQUIPPED,
|
||||
COMSIG_ITEM_DROPPED,
|
||||
COMSIG_ITEM_ATTACK_SELF,
|
||||
COMSIG_ITEM_ATTACK,
|
||||
COMSIG_ATOM_UPDATE_ICON,
|
||||
COMSIG_MOVABLE_MOVED,
|
||||
COMSIG_ITEM_SHARPEN_ACT))
|
||||
|
||||
/// Triggered on equip of the item containing the component
|
||||
/datum/component/two_handed/proc/on_equip(datum/source, mob/user, slot)
|
||||
if(require_twohands && slot == SLOT_HANDS) // force equip the item
|
||||
wield(user)
|
||||
if(!user.is_holding(parent) && wielded && !require_twohands)
|
||||
unwield(user)
|
||||
|
||||
/// Triggered on drop of item containing the component
|
||||
/datum/component/two_handed/proc/on_drop(datum/source, mob/user)
|
||||
if(require_twohands)
|
||||
unwield(user, show_message=TRUE)
|
||||
if(wielded)
|
||||
unwield(user)
|
||||
if(source == offhand_item && !QDELETED(src))
|
||||
qdel(src)
|
||||
|
||||
/// Triggered on attack self of the item containing the component
|
||||
/datum/component/two_handed/proc/on_attack_self(datum/source, mob/user)
|
||||
if(wielded)
|
||||
unwield(user)
|
||||
else
|
||||
wield(user)
|
||||
|
||||
/**
|
||||
* Wield the two handed item in both hands
|
||||
*
|
||||
* vars:
|
||||
* * user The mob/living/carbon that is wielding the item
|
||||
*/
|
||||
/datum/component/two_handed/proc/wield(mob/living/carbon/user)
|
||||
if(wielded)
|
||||
return
|
||||
if(ismonkey(user))
|
||||
to_chat(user, "<span class='warning'>It's too heavy for you to wield fully.</span>")
|
||||
return
|
||||
if(user.get_inactive_held_item())
|
||||
if(require_twohands)
|
||||
to_chat(user, "<span class='notice'>[parent] is too cumbersome to carry in one hand!</span>")
|
||||
user.dropItemToGround(parent, force=TRUE)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You need your other hand to be empty!</span>")
|
||||
return
|
||||
if(user.get_num_arms() < 2)
|
||||
if(require_twohands)
|
||||
user.dropItemToGround(parent, force=TRUE)
|
||||
to_chat(user, "<span class='warning'>You don't have enough intact hands.</span>")
|
||||
return
|
||||
|
||||
// wield update status
|
||||
if(SEND_SIGNAL(parent, COMSIG_TWOHANDED_WIELD, user) & COMPONENT_TWOHANDED_BLOCK_WIELD)
|
||||
return // blocked wield from item
|
||||
wielded = TRUE
|
||||
RegisterSignal(user, COMSIG_MOB_SWAP_HANDS, .proc/on_swap_hands)
|
||||
|
||||
// update item stats and name
|
||||
var/obj/item/parent_item = parent
|
||||
if(force_multiplier)
|
||||
parent_item.force *= force_multiplier
|
||||
else if(force_wielded)
|
||||
parent_item.force = force_wielded
|
||||
if(sharpened_increase)
|
||||
parent_item.force += sharpened_increase
|
||||
parent_item.name = "[parent_item.name] (Wielded)"
|
||||
parent_item.update_icon()
|
||||
|
||||
if(iscyborg(user))
|
||||
to_chat(user, "<span class='notice'>You dedicate your module to [parent].</span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You grab [parent] with both hands.</span>")
|
||||
|
||||
// Play sound if one is set
|
||||
if(wieldsound)
|
||||
playsound(parent_item.loc, wieldsound, 50, TRUE)
|
||||
|
||||
// Let's reserve the other hand
|
||||
offhand_item = new(user)
|
||||
offhand_item.name = "[parent_item.name] - offhand"
|
||||
offhand_item.desc = "Your second grip on [parent_item]."
|
||||
offhand_item.wielded = TRUE
|
||||
RegisterSignal(offhand_item, COMSIG_ITEM_DROPPED, .proc/on_drop)
|
||||
user.put_in_inactive_hand(offhand_item)
|
||||
|
||||
/**
|
||||
* Unwield the two handed item
|
||||
*
|
||||
* vars:
|
||||
* * user The mob/living/carbon that is unwielding the item
|
||||
* * show_message (option) show a message to chat on unwield
|
||||
*/
|
||||
/datum/component/two_handed/proc/unwield(mob/living/carbon/user, show_message=TRUE)
|
||||
if(!wielded || !user)
|
||||
return
|
||||
|
||||
// wield update status
|
||||
wielded = FALSE
|
||||
UnregisterSignal(user, COMSIG_MOB_SWAP_HANDS)
|
||||
SEND_SIGNAL(parent, COMSIG_TWOHANDED_UNWIELD, user)
|
||||
|
||||
// update item stats
|
||||
var/obj/item/parent_item = parent
|
||||
if(sharpened_increase)
|
||||
parent_item.force -= sharpened_increase
|
||||
if(force_multiplier)
|
||||
parent_item.force /= force_multiplier
|
||||
else if(force_unwielded)
|
||||
parent_item.force = force_unwielded
|
||||
|
||||
// update the items name to remove the wielded status
|
||||
var/sf = findtext(parent_item.name, " (Wielded)", -10) // 10 == length(" (Wielded)")
|
||||
if(sf)
|
||||
parent_item.name = copytext(parent_item.name, 1, sf)
|
||||
else
|
||||
parent_item.name = "[initial(parent_item.name)]"
|
||||
|
||||
// Update icons
|
||||
parent_item.update_icon()
|
||||
if(user.get_item_by_slot(ITEM_SLOT_BACK) == parent)
|
||||
user.update_inv_back()
|
||||
else
|
||||
user.update_inv_hands()
|
||||
|
||||
// if the item requires two handed drop the item on unwield
|
||||
if(require_twohands)
|
||||
user.dropItemToGround(parent, force=TRUE)
|
||||
|
||||
// Show message if requested
|
||||
if(show_message)
|
||||
if(iscyborg(user))
|
||||
to_chat(user, "<span class='notice'>You free up your module.</span>")
|
||||
else if(require_twohands)
|
||||
to_chat(user, "<span class='notice'>You drop [parent].</span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You are now carrying [parent] with one hand.</span>")
|
||||
|
||||
// Play sound if set
|
||||
if(unwieldsound)
|
||||
playsound(parent_item.loc, unwieldsound, 50, TRUE)
|
||||
|
||||
// Remove the object in the offhand
|
||||
if(offhand_item)
|
||||
UnregisterSignal(offhand_item, COMSIG_ITEM_DROPPED)
|
||||
qdel(offhand_item)
|
||||
// Clear any old refrence to an item that should be gone now
|
||||
offhand_item = null
|
||||
|
||||
/**
|
||||
* on_attack triggers on attack with the parent item
|
||||
*/
|
||||
/datum/component/two_handed/proc/on_attack(obj/item/source, mob/living/target, mob/living/user)
|
||||
if(wielded && attacksound)
|
||||
var/obj/item/parent_item = parent
|
||||
playsound(parent_item.loc, attacksound, 50, TRUE)
|
||||
|
||||
/**
|
||||
* on_update_icon triggers on call to update parent items icon
|
||||
*
|
||||
* Updates the icon using icon_wielded if set
|
||||
*/
|
||||
/datum/component/two_handed/proc/on_update_icon(datum/source)
|
||||
if(icon_wielded && wielded)
|
||||
var/obj/item/parent_item = parent
|
||||
if(parent_item)
|
||||
parent_item.icon_state = icon_wielded
|
||||
return COMSIG_ATOM_NO_UPDATE_ICON_STATE
|
||||
|
||||
/**
|
||||
* on_moved Triggers on item moved
|
||||
*/
|
||||
/datum/component/two_handed/proc/on_moved(datum/source, mob/user, dir)
|
||||
unwield(user)
|
||||
|
||||
/**
|
||||
* on_swap_hands Triggers on swapping hands, blocks swap if the other hand is busy
|
||||
*/
|
||||
/datum/component/two_handed/proc/on_swap_hands(mob/user, obj/item/held_item)
|
||||
if(!held_item)
|
||||
return
|
||||
if(held_item == parent)
|
||||
return COMPONENT_BLOCK_SWAP
|
||||
|
||||
/**
|
||||
* on_sharpen Triggers on usage of a sharpening stone on the item
|
||||
*/
|
||||
/datum/component/two_handed/proc/on_sharpen(obj/item/item, amount, max_amount)
|
||||
if(!item)
|
||||
return COMPONENT_BLOCK_SHARPEN_BLOCKED
|
||||
if(sharpened_increase)
|
||||
return COMPONENT_BLOCK_SHARPEN_ALREADY
|
||||
var/wielded_val = 0
|
||||
if(force_multiplier)
|
||||
var/obj/item/parent_item = parent
|
||||
if(wielded)
|
||||
wielded_val = parent_item.force
|
||||
else
|
||||
wielded_val = parent_item.force * force_multiplier
|
||||
else
|
||||
wielded_val = force_wielded
|
||||
if(wielded_val > max_amount)
|
||||
return COMPONENT_BLOCK_SHARPEN_MAXED
|
||||
sharpened_increase = min(amount, (max_amount - wielded_val))
|
||||
return COMPONENT_BLOCK_SHARPEN_APPLIED
|
||||
|
||||
/**
|
||||
* The offhand dummy item for two handed items
|
||||
*
|
||||
*/
|
||||
/obj/item/offhand
|
||||
name = "offhand"
|
||||
icon_state = "offhand"
|
||||
w_class = WEIGHT_CLASS_HUGE
|
||||
item_flags = ABSTRACT
|
||||
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
|
||||
var/wielded = FALSE // Off Hand tracking of wielded status
|
||||
|
||||
/obj/item/offhand/Destroy()
|
||||
wielded = FALSE
|
||||
return ..()
|
||||
|
||||
/obj/item/offhand/equipped(mob/user, slot)
|
||||
. = ..()
|
||||
if(wielded && !user.is_holding(src) && !QDELETED(src))
|
||||
qdel(src)
|
||||
@@ -20,11 +20,11 @@
|
||||
|
||||
/datum/disease/transformation/Copy()
|
||||
var/datum/disease/transformation/D = ..()
|
||||
D.stage1 = stage1?.Copy()
|
||||
D.stage2 = stage2?.Copy()
|
||||
D.stage3 = stage3?.Copy()
|
||||
D.stage4 = stage4?.Copy()
|
||||
D.stage5 = stage5?.Copy()
|
||||
D.stage1 = stage1.Copy()
|
||||
D.stage2 = stage2.Copy()
|
||||
D.stage3 = stage3.Copy()
|
||||
D.stage4 = stage4.Copy()
|
||||
D.stage5 = stage5.Copy()
|
||||
D.new_form = D.new_form
|
||||
return D
|
||||
|
||||
@@ -52,9 +52,9 @@
|
||||
to_chat(affected_mob, pick(stage5))
|
||||
if(QDELETED(affected_mob))
|
||||
return
|
||||
if(affected_mob.mob_transforming)
|
||||
if(affected_mob.notransform)
|
||||
return
|
||||
affected_mob.mob_transforming = 1
|
||||
affected_mob.notransform = 1
|
||||
for(var/obj/item/W in affected_mob.get_equipped_items(TRUE))
|
||||
affected_mob.dropItemToGround(W)
|
||||
for(var/obj/item/I in affected_mob.held_items)
|
||||
|
||||
@@ -19,13 +19,11 @@
|
||||
SHOULD_CALL_PARENT(1)
|
||||
if(type == /datum/element)
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
SEND_SIGNAL(target, COMSIG_ELEMENT_ATTACH, src)
|
||||
if(element_flags & ELEMENT_DETACH)
|
||||
RegisterSignal(target, COMSIG_PARENT_QDELETING, .proc/Detach, override = TRUE)
|
||||
|
||||
/// Deactivates the functionality defines by the element on the given datum
|
||||
/datum/element/proc/Detach(datum/source, force)
|
||||
SEND_SIGNAL(source, COMSIG_ELEMENT_DETACH, src)
|
||||
SHOULD_CALL_PARENT(1)
|
||||
UnregisterSignal(source, COMSIG_PARENT_QDELETING)
|
||||
|
||||
|
||||
@@ -8,11 +8,8 @@
|
||||
if(. == ELEMENT_INCOMPATIBLE || !isatom(target) || isarea(target))
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
beauty = beautyamount
|
||||
|
||||
if(ismovable(target))
|
||||
RegisterSignal(target, COMSIG_ENTER_AREA, .proc/enter_area)
|
||||
RegisterSignal(target, COMSIG_EXIT_AREA, .proc/exit_area)
|
||||
|
||||
RegisterSignal(target, COMSIG_ENTER_AREA, .proc/enter_area)
|
||||
RegisterSignal(target, COMSIG_EXIT_AREA, .proc/exit_area)
|
||||
var/area/A = get_area(target)
|
||||
if(A)
|
||||
enter_area(null, A)
|
||||
|
||||
@@ -1,227 +0,0 @@
|
||||
/*
|
||||
The presence of this element allows an item (or a projectile carrying an item) to embed itself in a human or turf when it is thrown into a target (whether by hand, gun, or explosive wave) with either
|
||||
at least 4 throwspeed (EMBED_THROWSPEED_THRESHOLD) or ignore_throwspeed_threshold set to TRUE. Items meant to be used as shrapnel for projectiles should have ignore_throwspeed_threshold set to true.
|
||||
|
||||
Whether we're dealing with a direct /obj/item (throwing a knife at someone) or an /obj/projectile with a shrapnel_type, how we handle things plays out the same, with one extra step separating them.
|
||||
Items simply make their COMSIG_MOVABLE_IMPACT or COMSIG_MOVABLE_IMPACT_ZONE check (against a closed turf or a carbon, respectively), while projectiles check on COMSIG_PROJECTILE_SELF_ON_HIT.
|
||||
Upon a projectile hitting a valid target, it spawns whatever type of payload it has defined, then has that try to embed itself in the target on its own.
|
||||
|
||||
Otherwise non-embeddable or stickable items can be made embeddable/stickable through wizard events/sticky tape/admin memes.
|
||||
*/
|
||||
|
||||
#define STANDARD_WALL_HARDNESS 40
|
||||
|
||||
/datum/element/embed
|
||||
element_flags = ELEMENT_BESPOKE
|
||||
id_arg_index = 2
|
||||
var/initialized = FALSE /// whether we can skip assigning all the vars (since these are bespoke elements, we don't have to reset the vars every time we attach to something, we already know what we are!)
|
||||
|
||||
// all of this stuff is explained in _DEFINES/combat.dm
|
||||
var/embed_chance
|
||||
var/fall_chance
|
||||
var/pain_chance
|
||||
var/pain_mult
|
||||
var/remove_pain_mult
|
||||
var/impact_pain_mult
|
||||
var/rip_time
|
||||
var/ignore_throwspeed_threshold
|
||||
var/jostle_chance
|
||||
var/jostle_pain_mult
|
||||
var/pain_stam_pct
|
||||
var/payload_type
|
||||
var/embed_chance_turf_mod
|
||||
|
||||
/datum/element/embed/Attach(datum/target, embed_chance, fall_chance, pain_chance, pain_mult, remove_pain_mult, impact_pain_mult, rip_time, ignore_throwspeed_threshold, jostle_chance, jostle_pain_mult, pain_stam_pct, embed_chance_turf_mod, projectile_payload=/obj/item/shard)
|
||||
. = ..()
|
||||
|
||||
if(!isitem(target) && !isprojectile(target))
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
|
||||
if(isitem(target))
|
||||
RegisterSignal(target, COMSIG_MOVABLE_IMPACT_ZONE, .proc/checkEmbedMob)
|
||||
RegisterSignal(target, COMSIG_MOVABLE_IMPACT, .proc/checkEmbedOther)
|
||||
RegisterSignal(target, COMSIG_ELEMENT_ATTACH, .proc/severancePackage)
|
||||
RegisterSignal(target, COMSIG_PARENT_EXAMINE, .proc/examined)
|
||||
RegisterSignal(target, COMSIG_EMBED_TRY_FORCE, .proc/tryForceEmbed)
|
||||
RegisterSignal(target, COMSIG_ITEM_DISABLE_EMBED, .proc/detachFromWeapon)
|
||||
if(!initialized)
|
||||
src.embed_chance = embed_chance
|
||||
src.fall_chance = fall_chance
|
||||
src.pain_chance = pain_chance
|
||||
src.pain_mult = pain_mult
|
||||
src.remove_pain_mult = remove_pain_mult
|
||||
src.rip_time = rip_time
|
||||
src.impact_pain_mult = impact_pain_mult
|
||||
src.ignore_throwspeed_threshold = ignore_throwspeed_threshold
|
||||
src.jostle_chance = jostle_chance
|
||||
src.jostle_pain_mult = jostle_pain_mult
|
||||
src.pain_stam_pct = pain_stam_pct
|
||||
src.embed_chance_turf_mod = embed_chance_turf_mod
|
||||
initialized = TRUE
|
||||
else
|
||||
payload_type = projectile_payload
|
||||
RegisterSignal(target, COMSIG_PROJECTILE_SELF_ON_HIT, .proc/checkEmbedProjectile)
|
||||
|
||||
|
||||
/datum/element/embed/Detach(obj/target)
|
||||
. = ..()
|
||||
if(isitem(target))
|
||||
UnregisterSignal(target, list(COMSIG_MOVABLE_IMPACT_ZONE, COMSIG_ELEMENT_ATTACH, COMSIG_MOVABLE_IMPACT, COMSIG_PARENT_EXAMINE, COMSIG_EMBED_TRY_FORCE, COMSIG_ITEM_DISABLE_EMBED))
|
||||
else
|
||||
UnregisterSignal(target, list(COMSIG_PROJECTILE_SELF_ON_HIT))
|
||||
|
||||
|
||||
/// Checking to see if we're gonna embed into a human
|
||||
/datum/element/embed/proc/checkEmbedMob(obj/item/weapon, mob/living/carbon/victim, hit_zone, datum/thrownthing/throwingdatum, blocked = FALSE, forced = FALSE)
|
||||
if(blocked || !istype(victim) || HAS_TRAIT(victim, TRAIT_PIERCEIMMUNE))
|
||||
return
|
||||
|
||||
var/actual_chance = embed_chance
|
||||
|
||||
if(!weapon.isEmbedHarmless()) // all the armor in the world won't save you from a kick me sign
|
||||
var/armor = max(victim.run_armor_check(hit_zone, "bullet", silent=TRUE), victim.run_armor_check(hit_zone, "bomb", silent=TRUE)) // we'll be nice and take the better of bullet and bomb armor
|
||||
|
||||
if(armor) // we only care about armor penetration if there's actually armor to penetrate
|
||||
var/pen_mod = -armor + weapon.armour_penetration // even a little bit of armor can make a big difference for shrapnel with large negative armor pen
|
||||
actual_chance += pen_mod // doing the armor pen as a separate calc just in case this ever gets expanded on
|
||||
if(actual_chance <= 0)
|
||||
victim.visible_message("<span class='danger'>[weapon] bounces off [victim]'s armor!</span>", "<span class='notice'>[weapon] bounces off your armor!</span>", vision_distance = COMBAT_MESSAGE_RANGE)
|
||||
return
|
||||
|
||||
var/roll_embed = prob(actual_chance)
|
||||
var/pass = forced || ((((throwingdatum ? throwingdatum.speed : weapon.throw_speed) >= EMBED_THROWSPEED_THRESHOLD) || ignore_throwspeed_threshold) && roll_embed && (!HAS_TRAIT(victim, TRAIT_AUTO_CATCH_ITEM) || victim.incapacitated() || victim.get_active_held_item()))
|
||||
if(!pass)
|
||||
return
|
||||
|
||||
var/obj/item/bodypart/limb = victim.get_bodypart(hit_zone) || pick(victim.bodyparts)
|
||||
victim.AddComponent(/datum/component/embedded,\
|
||||
weapon,\
|
||||
throwingdatum,\
|
||||
part = limb,\
|
||||
embed_chance = embed_chance,\
|
||||
fall_chance = fall_chance,\
|
||||
pain_chance = pain_chance,\
|
||||
pain_mult = pain_mult,\
|
||||
remove_pain_mult = remove_pain_mult,\
|
||||
rip_time = rip_time,\
|
||||
ignore_throwspeed_threshold = ignore_throwspeed_threshold,\
|
||||
jostle_chance = jostle_chance,\
|
||||
jostle_pain_mult = jostle_pain_mult,\
|
||||
pain_stam_pct = pain_stam_pct,\
|
||||
embed_chance_turf_mod = embed_chance_turf_mod)
|
||||
|
||||
return TRUE
|
||||
|
||||
/// We need the hit_zone if we're embedding into a human, so this proc only handles if we're embedding into a turf
|
||||
/datum/element/embed/proc/checkEmbedOther(obj/item/weapon, turf/closed/hit, datum/thrownthing/throwingdatum, forced=FALSE)
|
||||
if(!istype(hit))
|
||||
return
|
||||
|
||||
var/chance = embed_chance + embed_chance_turf_mod
|
||||
if(iswallturf(hit))
|
||||
var/turf/closed/wall/W = hit
|
||||
chance += 2 * (W.hardness - STANDARD_WALL_HARDNESS)
|
||||
|
||||
if(!forced && chance <= 0 || embed_chance_turf_mod <= -100)
|
||||
return
|
||||
|
||||
var/pass = ((((throwingdatum ? throwingdatum.speed : weapon.throw_speed) >= EMBED_THROWSPEED_THRESHOLD) || ignore_throwspeed_threshold) && prob(chance))
|
||||
if(!pass)
|
||||
return
|
||||
|
||||
hit.AddComponent(/datum/component/embedded,\
|
||||
weapon,\
|
||||
throwingdatum,\
|
||||
embed_chance = embed_chance,\
|
||||
fall_chance = fall_chance,\
|
||||
pain_chance = pain_chance,\
|
||||
pain_mult = pain_mult,\
|
||||
remove_pain_mult = remove_pain_mult,\
|
||||
rip_time = rip_time,\
|
||||
ignore_throwspeed_threshold = ignore_throwspeed_threshold,\
|
||||
jostle_chance = jostle_chance,\
|
||||
jostle_pain_mult = jostle_pain_mult,\
|
||||
pain_stam_pct = pain_stam_pct,\
|
||||
embed_chance_turf_mod = embed_chance_turf_mod)
|
||||
|
||||
return TRUE
|
||||
|
||||
///A different embed element has been attached, so we'll detach and let them handle things
|
||||
/datum/element/embed/proc/severancePackage(obj/item/weapon, datum/element/E)
|
||||
if(istype(E, /datum/element/embed))
|
||||
Detach(weapon)
|
||||
|
||||
///If we don't want to be embeddable anymore (deactivating an e-dagger for instance)
|
||||
/datum/element/embed/proc/detachFromWeapon(obj/weapon)
|
||||
Detach(weapon)
|
||||
|
||||
///Someone inspected our embeddable item
|
||||
/datum/element/embed/proc/examined(obj/item/I, mob/user, list/examine_list)
|
||||
if(I.isEmbedHarmless())
|
||||
examine_list += "[I] feels sticky, and could probably get stuck to someone if thrown properly!"
|
||||
else
|
||||
examine_list += "[I] has a fine point, and could probably embed in someone if thrown properly!"
|
||||
|
||||
/**
|
||||
* checkEmbedProjectile() is what we get when a projectile with a defined shrapnel_type impacts a target.
|
||||
*
|
||||
* If we hit a valid target (carbon or closed turf), we create the shrapnel_type object and immediately call tryEmbed() on it, targeting what we impacted. That will lead
|
||||
* it to call tryForceEmbed() on its own embed element (it's out of our hands here, our projectile is done), where it will run through all the checks it needs to.
|
||||
*/
|
||||
/datum/element/embed/proc/checkEmbedProjectile(obj/item/projectile/P, atom/movable/firer, atom/hit, angle, hit_zone)
|
||||
if(!iscarbon(hit) && !isclosedturf(hit))
|
||||
Detach(P)
|
||||
return // we don't care
|
||||
|
||||
var/obj/item/payload = new payload_type(get_turf(hit))
|
||||
var/did_embed
|
||||
if(iscarbon(hit))
|
||||
var/mob/living/carbon/C = hit
|
||||
var/obj/item/bodypart/limb
|
||||
limb = C.get_bodypart(hit_zone)
|
||||
if(!limb)
|
||||
limb = C.get_bodypart()
|
||||
did_embed = payload.tryEmbed(limb)
|
||||
else
|
||||
did_embed = payload.tryEmbed(hit)
|
||||
|
||||
if(!did_embed)
|
||||
payload.failedEmbed()
|
||||
Detach(P)
|
||||
|
||||
/**
|
||||
* tryForceEmbed() is called here when we fire COMSIG_EMBED_TRY_FORCE from [/obj/item/proc/tryEmbed]. Mostly, this means we're a piece of shrapnel from a projectile that just impacted something, and we're trying to embed in it.
|
||||
*
|
||||
* The reason for this extra mucking about is avoiding having to do an extra hitby(), and annoying the target by impacting them once with the projectile, then again with the shrapnel (which likely represents said bullet), and possibly
|
||||
* AGAIN if we actually embed. This way, we save on at least one message. Runs the standard embed checks on the mob/turf.
|
||||
*
|
||||
* Arguments:
|
||||
* * I- what we're trying to embed, obviously
|
||||
* * target- what we're trying to shish-kabob, either a bodypart, a carbon, or a closed turf
|
||||
* * hit_zone- if our target is a carbon, try to hit them in this zone, if we don't have one, pick a random one. If our target is a bodypart, we already know where we're hitting.
|
||||
* * forced- if we want this to succeed 100%
|
||||
*/
|
||||
/datum/element/embed/proc/tryForceEmbed(obj/item/I, atom/target, hit_zone, forced=FALSE)
|
||||
var/obj/item/bodypart/limb
|
||||
var/mob/living/carbon/C
|
||||
var/turf/closed/T
|
||||
|
||||
if(!forced && !prob(embed_chance))
|
||||
return
|
||||
|
||||
if(iscarbon(target))
|
||||
C = target
|
||||
if(!hit_zone)
|
||||
limb = pick(C.bodyparts)
|
||||
hit_zone = limb.body_zone
|
||||
else if(isbodypart(target))
|
||||
limb = target
|
||||
hit_zone = limb.body_zone
|
||||
C = limb.owner
|
||||
else if(isclosedturf(target))
|
||||
T = target
|
||||
|
||||
if(C)
|
||||
return checkEmbedMob(I, C, hit_zone, forced=TRUE)
|
||||
else if(T)
|
||||
return checkEmbedOther(I, T, forced=TRUE)
|
||||
@@ -117,9 +117,9 @@ GLOBAL_LIST_EMPTY(mobs_with_editable_flavor_text) //et tu, hacky code
|
||||
return FALSE
|
||||
|
||||
var/lower_name = lowertext(flavor_name)
|
||||
var/new_text = stripped_multiline_input(user, "Set the [lower_name] displayed on 'examine'. [addendum]", flavor_name, html_decode(texts_by_atom[usr]), max_len, TRUE)
|
||||
var/new_text = stripped_multiline_input(user, "Set the [lower_name] displayed on 'examine'. [addendum]", flavor_name, texts_by_atom[usr], max_len, TRUE)
|
||||
if(!isnull(new_text) && (user in texts_by_atom))
|
||||
texts_by_atom[user] = new_text
|
||||
texts_by_atom[user] = html_decode(new_text)
|
||||
to_chat(src, "Your [lower_name] has been updated.")
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
#define EMBEDID "embed-[embed_chance]-[embedded_fall_chance]-[embedded_pain_chance]-[embedded_pain_multiplier]-[embedded_fall_pain_multiplier]-[embedded_impact_pain_multiplier]-[embedded_unsafe_removal_pain_multiplier]-[embedded_unsafe_removal_time]"
|
||||
|
||||
/proc/getEmbeddingBehavior(embed_chance = EMBED_CHANCE,
|
||||
embedded_fall_chance = EMBEDDED_ITEM_FALLOUT,
|
||||
embedded_pain_chance = EMBEDDED_PAIN_CHANCE,
|
||||
embedded_pain_multiplier = EMBEDDED_PAIN_MULTIPLIER,
|
||||
embedded_fall_pain_multiplier = EMBEDDED_FALL_PAIN_MULTIPLIER,
|
||||
embedded_impact_pain_multiplier = EMBEDDED_IMPACT_PAIN_MULTIPLIER,
|
||||
embedded_unsafe_removal_pain_multiplier = EMBEDDED_UNSAFE_REMOVAL_PAIN_MULTIPLIER,
|
||||
embedded_unsafe_removal_time = EMBEDDED_UNSAFE_REMOVAL_TIME)
|
||||
. = locate(EMBEDID)
|
||||
if (!.)
|
||||
. = new /datum/embedding_behavior(embed_chance, embedded_fall_chance, embedded_pain_chance, embedded_pain_multiplier, embedded_fall_pain_multiplier, embedded_impact_pain_multiplier, embedded_unsafe_removal_pain_multiplier, embedded_unsafe_removal_time)
|
||||
|
||||
/datum/embedding_behavior
|
||||
var/embed_chance
|
||||
var/embedded_fall_chance
|
||||
var/embedded_pain_chance
|
||||
var/embedded_pain_multiplier //The coefficient of multiplication for the damage this item does while embedded (this*w_class)
|
||||
var/embedded_fall_pain_multiplier //The coefficient of multiplication for the damage this item does when falling out of a limb (this*w_class)
|
||||
var/embedded_impact_pain_multiplier //The coefficient of multiplication for the damage this item does when first embedded (this*w_class)
|
||||
var/embedded_unsafe_removal_pain_multiplier //The coefficient of multiplication for the damage removing this without surgery causes (this*w_class)
|
||||
var/embedded_unsafe_removal_time //A time in ticks, multiplied by the w_class.
|
||||
|
||||
/datum/embedding_behavior/New(embed_chance = EMBED_CHANCE,
|
||||
embedded_fall_chance = EMBEDDED_ITEM_FALLOUT,
|
||||
embedded_pain_chance = EMBEDDED_PAIN_CHANCE,
|
||||
embedded_pain_multiplier = EMBEDDED_PAIN_MULTIPLIER,
|
||||
embedded_fall_pain_multiplier = EMBEDDED_FALL_PAIN_MULTIPLIER,
|
||||
embedded_impact_pain_multiplier = EMBEDDED_IMPACT_PAIN_MULTIPLIER,
|
||||
embedded_unsafe_removal_pain_multiplier = EMBEDDED_UNSAFE_REMOVAL_PAIN_MULTIPLIER,
|
||||
embedded_unsafe_removal_time = EMBEDDED_UNSAFE_REMOVAL_TIME)
|
||||
src.embed_chance = embed_chance
|
||||
src.embedded_fall_chance = embedded_fall_chance
|
||||
src.embedded_pain_chance = embedded_pain_chance
|
||||
src.embedded_pain_multiplier = embedded_pain_multiplier
|
||||
src.embedded_fall_pain_multiplier = embedded_fall_pain_multiplier
|
||||
src.embedded_impact_pain_multiplier = embedded_impact_pain_multiplier
|
||||
src.embedded_unsafe_removal_pain_multiplier = embedded_unsafe_removal_pain_multiplier
|
||||
src.embedded_unsafe_removal_time = embedded_unsafe_removal_time
|
||||
tag = EMBEDID
|
||||
|
||||
/datum/embedding_behavior/proc/setRating(embed_chance, embedded_fall_chance, embedded_pain_chance, embedded_pain_multiplier, embedded_fall_pain_multiplier, embedded_impact_pain_multiplier, embedded_unsafe_removal_pain_multiplier, embedded_unsafe_removal_time)
|
||||
return getEmbeddingBehavior((isnull(embed_chance) ? src.embed_chance : embed_chance),\
|
||||
(isnull(embedded_fall_chance) ? src.embedded_fall_chance : embedded_fall_chance),\
|
||||
(isnull(embedded_pain_chance) ? src.embedded_pain_chance : embedded_pain_chance),\
|
||||
(isnull(embedded_pain_multiplier) ? src.embedded_pain_multiplier : embedded_pain_multiplier),\
|
||||
(isnull(embedded_fall_pain_multiplier) ? src.embedded_fall_pain_multiplier : embedded_fall_pain_multiplier),\
|
||||
(isnull(embedded_impact_pain_multiplier) ? src.embedded_impact_pain_multiplier : embedded_impact_pain_multiplier),\
|
||||
(isnull(embedded_unsafe_removal_pain_multiplier) ? src.embedded_unsafe_removal_pain_multiplier : embedded_unsafe_removal_pain_multiplier),\
|
||||
(isnull(embedded_unsafe_removal_time) ? src.embedded_unsafe_removal_time : embedded_unsafe_removal_time))
|
||||
|
||||
#undef EMBEDID
|
||||
+1
-2
@@ -27,8 +27,7 @@ GLOBAL_LIST_INIT(huds, list(
|
||||
ANTAG_HUD_SOULLESS = new/datum/atom_hud/antag/hidden(),
|
||||
ANTAG_HUD_CLOCKWORK = new/datum/atom_hud/antag(),
|
||||
ANTAG_HUD_BROTHER = new/datum/atom_hud/antag/hidden(),
|
||||
ANTAG_HUD_BLOODSUCKER = new/datum/atom_hud/antag/bloodsucker(),
|
||||
ANTAG_HUD_FUGITIVE = new/datum/atom_hud/antag()
|
||||
ANTAG_HUD_BLOODSUCKER = new/datum/atom_hud/antag/bloodsucker()
|
||||
))
|
||||
|
||||
/datum/atom_hud
|
||||
|
||||
@@ -23,14 +23,10 @@
|
||||
var/end_sound
|
||||
var/chance
|
||||
var/volume = 100
|
||||
var/vary = FALSE
|
||||
var/max_loops
|
||||
var/direct
|
||||
var/extra_range = 0
|
||||
var/falloff
|
||||
|
||||
var/timerid
|
||||
var/init_timerid
|
||||
|
||||
/datum/looping_sound/New(list/_output_atoms=list(), start_immediately=FALSE, _direct=FALSE)
|
||||
if(!mid_sounds)
|
||||
@@ -51,15 +47,13 @@
|
||||
/datum/looping_sound/proc/start(atom/add_thing)
|
||||
if(add_thing)
|
||||
output_atoms |= add_thing
|
||||
if(timerid || init_timerid)
|
||||
if(timerid)
|
||||
return
|
||||
on_start()
|
||||
|
||||
/datum/looping_sound/proc/stop(atom/remove_thing)
|
||||
if(remove_thing)
|
||||
output_atoms -= remove_thing
|
||||
if(init_timerid)
|
||||
deltimer(init_timerid)
|
||||
if(!timerid)
|
||||
return
|
||||
on_stop()
|
||||
@@ -86,7 +80,7 @@
|
||||
if(direct)
|
||||
SEND_SOUND(thing, S)
|
||||
else
|
||||
playsound(thing, S, volume, vary, extra_range, falloff)
|
||||
playsound(thing, S, volume)
|
||||
|
||||
/datum/looping_sound/proc/get_sound(starttime, _mid_sounds)
|
||||
. = _mid_sounds || mid_sounds
|
||||
@@ -98,7 +92,7 @@
|
||||
if(start_sound)
|
||||
play(start_sound)
|
||||
start_wait = start_length
|
||||
init_timerid = addtimer(CALLBACK(src, .proc/sound_loop), start_wait, TIMER_CLIENT_TIME | TIMER_STOPPABLE)
|
||||
addtimer(CALLBACK(src, .proc/sound_loop), start_wait, TIMER_CLIENT_TIME)
|
||||
|
||||
/datum/looping_sound/proc/on_stop()
|
||||
if(end_sound)
|
||||
|
||||
@@ -10,10 +10,6 @@
|
||||
var/help_verb
|
||||
var/pacifism_check = TRUE //are the martial arts combos/attacks unable to be used by pacifist.
|
||||
var/allow_temp_override = TRUE //if this martial art can be overridden by temporary martial arts
|
||||
/// Can we be used to unarmed parry?
|
||||
var/can_martial_parry = FALSE
|
||||
/// Set this variable to something not null, this'll be the preferred unarmed parry in most cases if [can_martial_parry] is TRUE. YOU MUST RUN [get_block_parry_data(this)] INSTEAD OF DIRECTLY ACCESSING!
|
||||
var/datum/block_parry_data/block_parry_data
|
||||
var/pugilist = FALSE
|
||||
|
||||
/datum/martial_art/proc/disarm_act(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
@@ -95,4 +91,4 @@
|
||||
|
||||
///Gets called when a projectile hits the owner. Returning anything other than BULLET_ACT_HIT will stop the projectile from hitting the mob.
|
||||
/datum/martial_art/proc/on_projectile_hit(mob/living/carbon/human/A, obj/item/projectile/P, def_zone)
|
||||
return BULLET_ACT_HIT
|
||||
return BULLET_ACT_HIT
|
||||
@@ -58,15 +58,17 @@
|
||||
var/datum/martial_art/boxing/style = new
|
||||
|
||||
/obj/item/clothing/gloves/boxing/equipped(mob/user, slot)
|
||||
. = ..()
|
||||
if(ishuman(user) && slot == SLOT_GLOVES)
|
||||
if(!ishuman(user))
|
||||
return
|
||||
if(slot == SLOT_GLOVES)
|
||||
var/mob/living/carbon/human/H = user
|
||||
style.teach(H,TRUE)
|
||||
return
|
||||
|
||||
/obj/item/clothing/gloves/boxing/dropped(mob/user)
|
||||
. = ..()
|
||||
if(!ishuman(user))
|
||||
return
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(H.get_item_by_slot(SLOT_GLOVES) == src)
|
||||
style.remove(H)
|
||||
return
|
||||
|
||||
@@ -196,13 +196,13 @@
|
||||
var/datum/martial_art/krav_maga/style = new
|
||||
|
||||
/obj/item/clothing/gloves/krav_maga/equipped(mob/user, slot)
|
||||
. = ..()
|
||||
if(ishuman(user) && slot == SLOT_GLOVES)
|
||||
if(!ishuman(user))
|
||||
return
|
||||
if(slot == SLOT_GLOVES)
|
||||
var/mob/living/carbon/human/H = user
|
||||
style.teach(H,1)
|
||||
|
||||
/obj/item/clothing/gloves/krav_maga/dropped(mob/user)
|
||||
. = ..()
|
||||
if(!ishuman(user))
|
||||
return
|
||||
var/mob/living/carbon/human/H = user
|
||||
|
||||
@@ -180,12 +180,14 @@
|
||||
to_chat(usr, "<span class='notice'>Keelhaul</span>: Harm Grab. Kick opponents to the floor. Against prone targets, deal additional stamina damage and disarm them.")
|
||||
to_chat(usr, "<span class='notice'>In addition, your body has become incredibly resilient to most forms of attack. Weapons cannot readily pierce your hardened skin, and you are highly resistant to stuns and knockdowns, and can block all projectiles in Throw Mode. However, you are not invincible, and sustained damage will take it's toll. Avoid heat at all costs!</span>")
|
||||
|
||||
/obj/item/staff/bostaff
|
||||
/obj/item/twohanded/bostaff
|
||||
name = "bo staff"
|
||||
desc = "A long, tall staff made of polished wood. Traditionally used in ancient old-Earth martial arts. Can be wielded to both kill and incapacitate."
|
||||
force = 10
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
slot_flags = ITEM_SLOT_BACK
|
||||
force_unwielded = 10
|
||||
force_wielded = 24
|
||||
throwforce = 20
|
||||
throw_speed = 2
|
||||
attack_verb = list("smashed", "slammed", "whacked", "thwacked")
|
||||
@@ -194,29 +196,11 @@
|
||||
lefthand_file = 'icons/mob/inhands/weapons/staves_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi'
|
||||
block_chance = 50
|
||||
var/wielded = FALSE // track wielded status on item
|
||||
|
||||
/obj/item/staff/bostaff/Initialize()
|
||||
. = ..()
|
||||
RegisterSignal(src, COMSIG_TWOHANDED_WIELD, .proc/on_wield)
|
||||
RegisterSignal(src, COMSIG_TWOHANDED_UNWIELD, .proc/on_unwield)
|
||||
/obj/item/twohanded/bostaff/update_icon_state()
|
||||
icon_state = "bostaff[wielded]"
|
||||
|
||||
/obj/item/staff/bostaff/ComponentInitialize()
|
||||
. = ..()
|
||||
AddComponent(/datum/component/two_handed, force_unwielded=10, force_wielded=24, icon_wielded="bostaff1")
|
||||
|
||||
/// triggered on wield of two handed item
|
||||
/obj/item/staff/bostaff/proc/on_wield(obj/item/source, mob/user)
|
||||
wielded = TRUE
|
||||
|
||||
/// triggered on unwield of two handed item
|
||||
/obj/item/staff/bostaff/proc/on_unwield(obj/item/source, mob/user)
|
||||
wielded = FALSE
|
||||
|
||||
/obj/item/staff/bostaff/update_icon_state()
|
||||
icon_state = "bostaff0"
|
||||
|
||||
/obj/item/staff/bostaff/attack(mob/target, mob/living/user)
|
||||
/obj/item/twohanded/bostaff/attack(mob/target, mob/living/user)
|
||||
add_fingerprint(user)
|
||||
if((HAS_TRAIT(user, TRAIT_CLUMSY)) && prob(50))
|
||||
to_chat(user, "<span class ='warning'>You club yourself over the head with [src].</span>")
|
||||
@@ -265,7 +249,7 @@
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/staff/bostaff/run_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
|
||||
/obj/item/twohanded/bostaff/run_block(mob/living/owner, atom/object, damage, attack_text, attack_type, armour_penetration, mob/attacker, def_zone, final_block_chance, list/block_return)
|
||||
if(!wielded)
|
||||
return BLOCK_NONE
|
||||
return ..()
|
||||
|
||||
@@ -377,7 +377,7 @@
|
||||
var/turf/ST = null
|
||||
var/falling = 0
|
||||
var/damage = damage_roll(A,D)
|
||||
|
||||
|
||||
for (var/obj/O in oview(1, A))
|
||||
if (O.density == 1)
|
||||
if (O == A)
|
||||
@@ -472,18 +472,20 @@
|
||||
var/datum/martial_art/wrestling/style = new
|
||||
|
||||
/obj/item/storage/belt/champion/wrestling/equipped(mob/user, slot)
|
||||
. = ..()
|
||||
if(ishuman(user) && slot == SLOT_BELT)
|
||||
if(!ishuman(user))
|
||||
return
|
||||
if(slot == SLOT_BELT)
|
||||
var/mob/living/carbon/human/H = user
|
||||
style.teach(H,1)
|
||||
return
|
||||
|
||||
/obj/item/storage/belt/champion/wrestling/dropped(mob/user)
|
||||
. = ..()
|
||||
if(!ishuman(user))
|
||||
return
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(H.get_item_by_slot(SLOT_BELT) == src)
|
||||
style.remove(H)
|
||||
return
|
||||
|
||||
//Subtype of wrestling, reserved for the wrestling belts found in the holodeck
|
||||
/datum/martial_art/wrestling/holodeck
|
||||
|
||||
@@ -6,6 +6,8 @@ Simple datum which is instanced once per type and is used for every object of sa
|
||||
/datum/material
|
||||
var/name = "material"
|
||||
var/desc = "its..stuff."
|
||||
///Var that's mostly used by science machines to identify specific materials, should most likely be phased out at some point
|
||||
var/id = "mat"
|
||||
///Base color of the material, is used for greyscale. Item isn't changed in color if this is null.
|
||||
var/color
|
||||
///Base alpha of the material, is used for greyscale icons.
|
||||
@@ -24,20 +26,6 @@ Simple datum which is instanced once per type and is used for every object of sa
|
||||
var/armor_modifiers = list("melee" = 1, "bullet" = 1, "laser" = 1, "energy" = 1, "bomb" = 1, "bio" = 1, "rad" = 1, "fire" = 1, "acid" = 1)
|
||||
///How beautiful is this material per unit?
|
||||
var/beauty_modifier = 0
|
||||
///Can be used to override the sound items make, lets add some SLOSHing.
|
||||
var/item_sound_override
|
||||
///Can be used to override the stepsound a turf makes. MORE SLOOOSH
|
||||
var/turf_sound_override
|
||||
///what texture icon state to overlay
|
||||
var/texture_layer_icon_state
|
||||
///a cached filter for the texture icon
|
||||
var/cached_texture_filter
|
||||
|
||||
/datum/material/New()
|
||||
. = ..()
|
||||
if(texture_layer_icon_state)
|
||||
var/texture_icon = icon('icons/materials/composite.dmi', texture_layer_icon_state)
|
||||
cached_texture_filter = filter(type="layer", icon=texture_icon, blend_mode = BLEND_INSET_OVERLAY)
|
||||
|
||||
///This proc is called when the material is added to an object.
|
||||
/datum/material/proc/on_applied(atom/source, amount, material_flags)
|
||||
@@ -46,27 +34,16 @@ Simple datum which is instanced once per type and is used for every object of sa
|
||||
source.add_atom_colour(color, FIXED_COLOUR_PRIORITY)
|
||||
if(alpha)
|
||||
source.alpha = alpha
|
||||
if(texture_layer_icon_state)
|
||||
ADD_KEEP_TOGETHER(source, MATERIAL_SOURCE(src))
|
||||
source.filters += cached_texture_filter
|
||||
|
||||
if(material_flags & MATERIAL_ADD_PREFIX)
|
||||
source.name = "[name] [source.name]"
|
||||
|
||||
if(beauty_modifier)
|
||||
addtimer(CALLBACK(source, /datum.proc/_AddElement, list(/datum/element/beauty, beauty_modifier * amount)), 0)
|
||||
|
||||
if(istype(source, /obj)) //objs
|
||||
on_applied_obj(source, amount, material_flags)
|
||||
|
||||
else if(isturf(source, /turf)) //turfs
|
||||
on_applied_turf(source, amount, material_flags)
|
||||
if(beauty_modifier)
|
||||
addtimer(CALLBACK(source, /datum.proc/_AddElement, list(/datum/element/beauty, beauty_modifier * amount)), 0)
|
||||
|
||||
source.mat_update_desc(src)
|
||||
|
||||
///This proc is called when a material updates an object's description
|
||||
/atom/proc/mat_update_desc(/datum/material/mat)
|
||||
return
|
||||
///This proc is called when the material is added to an object specifically.
|
||||
/datum/material/proc/on_applied_obj(var/obj/o, amount, material_flags)
|
||||
if(material_flags & MATERIAL_AFFECT_STATISTICS)
|
||||
@@ -84,24 +61,6 @@ Simple datum which is instanced once per type and is used for every object of sa
|
||||
for(var/i in current_armor)
|
||||
temp_armor_list[i] = current_armor[i] * armor_modifiers[i]
|
||||
o.armor = getArmor(arglist(temp_armor_list))
|
||||
if(!isitem(o))
|
||||
return
|
||||
var/obj/item/I = o
|
||||
if(!item_sound_override)
|
||||
return
|
||||
I.hitsound = item_sound_override
|
||||
I.usesound = item_sound_override
|
||||
I.throwhitsound = item_sound_override
|
||||
|
||||
/datum/material/proc/on_applied_turf(var/turf/T, amount, material_flags)
|
||||
if(isopenturf(T))
|
||||
if(!turf_sound_override)
|
||||
return
|
||||
var/turf/open/O = T
|
||||
O.footstep = turf_sound_override
|
||||
O.barefootstep = turf_sound_override
|
||||
O.clawfootstep = turf_sound_override
|
||||
O.heavyfootstep = turf_sound_override
|
||||
|
||||
///This proc is called when the material is removed from an object.
|
||||
/datum/material/proc/on_removed(atom/source, material_flags)
|
||||
@@ -109,9 +68,6 @@ Simple datum which is instanced once per type and is used for every object of sa
|
||||
if(color)
|
||||
source.remove_atom_colour(FIXED_COLOUR_PRIORITY, color)
|
||||
source.alpha = initial(source.alpha)
|
||||
if(texture_layer_icon_state)
|
||||
source.filters -= cached_texture_filter
|
||||
REMOVE_KEEP_TOGETHER(source, MATERIAL_SOURCE(src))
|
||||
|
||||
if(material_flags & MATERIAL_ADD_PREFIX)
|
||||
source.name = initial(source.name)
|
||||
@@ -119,16 +75,10 @@ Simple datum which is instanced once per type and is used for every object of sa
|
||||
if(istype(source, /obj)) //objs
|
||||
on_removed_obj(source, material_flags)
|
||||
|
||||
else if(istype(source, /turf)) //turfs
|
||||
on_removed_turf(source, material_flags)
|
||||
|
||||
///This proc is called when the material is removed from an object specifically.
|
||||
/datum/material/proc/on_removed_obj(obj/o, material_flags)
|
||||
/datum/material/proc/on_removed_obj(var/obj/o, amount, material_flags)
|
||||
if(material_flags & MATERIAL_AFFECT_STATISTICS)
|
||||
var/new_max_integrity = initial(o.max_integrity)
|
||||
o.modify_max_integrity(new_max_integrity)
|
||||
o.force = initial(o.force)
|
||||
o.throwforce = initial(o.throwforce)
|
||||
|
||||
/datum/material/proc/on_removed_turf(turf/T, material_flags)
|
||||
return
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
///Has no special properties.
|
||||
/datum/material/iron
|
||||
name = "iron"
|
||||
id = "iron"
|
||||
desc = "Common iron ore often found in sedimentary and igneous layers of the crust."
|
||||
color = "#878687"
|
||||
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/metal
|
||||
value_per_unit = 0.0025
|
||||
|
||||
///Breaks extremely easily but is transparent.
|
||||
/datum/material/glass
|
||||
name = "glass"
|
||||
id = "glass"
|
||||
desc = "Glass forged by melting sand."
|
||||
color = "#88cdf1"
|
||||
alpha = 150
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE)
|
||||
integrity_modifier = 0.1
|
||||
sheet_type = /obj/item/stack/sheet/glass
|
||||
value_per_unit = 0.0025
|
||||
@@ -28,9 +30,10 @@ Unless you know what you're doing, only use the first three numbers. They're in
|
||||
///Has no special properties. Could be good against vampires in the future perhaps.
|
||||
/datum/material/silver
|
||||
name = "silver"
|
||||
id = "silver"
|
||||
desc = "Silver"
|
||||
color = list(255/255, 284/255, 302/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0)
|
||||
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/mineral/silver
|
||||
value_per_unit = 0.025
|
||||
beauty_modifier = 0.075
|
||||
@@ -38,10 +41,11 @@ Unless you know what you're doing, only use the first three numbers. They're in
|
||||
///Slight force increase
|
||||
/datum/material/gold
|
||||
name = "gold"
|
||||
id = "gold"
|
||||
desc = "Gold"
|
||||
color = list(340/255, 240/255, 50/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0) //gold is shiny, but not as bright as bananium
|
||||
strength_modifier = 1.2
|
||||
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/mineral/gold
|
||||
value_per_unit = 0.0625
|
||||
beauty_modifier = 0.15
|
||||
@@ -50,10 +54,11 @@ Unless you know what you're doing, only use the first three numbers. They're in
|
||||
///Has no special properties
|
||||
/datum/material/diamond
|
||||
name = "diamond"
|
||||
id = "diamond"
|
||||
desc = "Highly pressurized carbon"
|
||||
color = list(48/255, 272/255, 301/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0)
|
||||
alpha = 132
|
||||
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/mineral/diamond
|
||||
value_per_unit = 0.25
|
||||
beauty_modifier = 0.3
|
||||
@@ -62,9 +67,10 @@ Unless you know what you're doing, only use the first three numbers. They're in
|
||||
///Is slightly radioactive
|
||||
/datum/material/uranium
|
||||
name = "uranium"
|
||||
id = "uranium"
|
||||
desc = "Uranium"
|
||||
color = rgb(48, 237, 26)
|
||||
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/mineral/uranium
|
||||
value_per_unit = 0.05
|
||||
beauty_modifier = 0.3 //It shines so beautiful
|
||||
@@ -82,9 +88,10 @@ Unless you know what you're doing, only use the first three numbers. They're in
|
||||
///Adds firestacks on hit (Still needs support to turn into gas on destruction)
|
||||
/datum/material/plasma
|
||||
name = "plasma"
|
||||
id = "plasma"
|
||||
desc = "Isn't plasma a state of matter? Oh whatever."
|
||||
color = list(298/255, 46/255, 352/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0)
|
||||
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/mineral/plasma
|
||||
value_per_unit = 0.1
|
||||
beauty_modifier = 0.15
|
||||
@@ -104,6 +111,7 @@ Unless you know what you're doing, only use the first three numbers. They're in
|
||||
///Can cause bluespace effects on use. (Teleportation) (Not yet implemented)
|
||||
/datum/material/bluespace
|
||||
name = "bluespace crystal"
|
||||
id = "bluespace_crystal"
|
||||
desc = "Crystals with bluespace properties"
|
||||
color = list(119/255, 217/255, 396/255,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0)
|
||||
alpha = 200
|
||||
@@ -115,9 +123,10 @@ Unless you know what you're doing, only use the first three numbers. They're in
|
||||
///Honks and slips
|
||||
/datum/material/bananium
|
||||
name = "bananium"
|
||||
id = "bananium"
|
||||
desc = "Material with hilarious properties"
|
||||
color = list(460/255, 464/255, 0, 0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0) //obnoxiously bright yellow
|
||||
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/mineral/bananium
|
||||
value_per_unit = 0.5
|
||||
beauty_modifier = 0.5
|
||||
@@ -137,10 +146,11 @@ Unless you know what you're doing, only use the first three numbers. They're in
|
||||
///Mediocre force increase
|
||||
/datum/material/titanium
|
||||
name = "titanium"
|
||||
id = "titanium"
|
||||
desc = "Titanium"
|
||||
color = "#b3c0c7"
|
||||
strength_modifier = 1.3
|
||||
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
categories = list(MAT_CATEGORY_ORE = TRUE, MAT_CATEGORY_RIGID = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/mineral/titanium
|
||||
value_per_unit = 0.0625
|
||||
beauty_modifier = 0.05
|
||||
@@ -148,10 +158,11 @@ Unless you know what you're doing, only use the first three numbers. They're in
|
||||
|
||||
/datum/material/runite
|
||||
name = "runite"
|
||||
id = "runite"
|
||||
desc = "Runite"
|
||||
color = "#3F9995"
|
||||
strength_modifier = 1.3
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/mineral/runite
|
||||
beauty_modifier = 0.5
|
||||
armor_modifiers = list("melee" = 1.35, "bullet" = 2, "laser" = 0.5, "energy" = 1.25, "bomb" = 1.25, "bio" = 1, "rad" = 1, "fire" = 1.4, "acid" = 1) //rune is weak against magic lasers but strong against bullets. This is the combat triangle.
|
||||
@@ -159,6 +170,7 @@ Unless you know what you're doing, only use the first three numbers. They're in
|
||||
///Force decrease
|
||||
/datum/material/plastic
|
||||
name = "plastic"
|
||||
id = "plastic"
|
||||
desc = "Plastic"
|
||||
color = "#caccd9"
|
||||
strength_modifier = 0.85
|
||||
@@ -170,6 +182,7 @@ Unless you know what you're doing, only use the first three numbers. They're in
|
||||
///Force decrease and mushy sound effect. (Not yet implemented)
|
||||
/datum/material/biomass
|
||||
name = "biomass"
|
||||
id = "biomass"
|
||||
desc = "Organic matter"
|
||||
color = "#735b4d"
|
||||
strength_modifier = 0.8
|
||||
@@ -177,11 +190,12 @@ Unless you know what you're doing, only use the first three numbers. They're in
|
||||
|
||||
/datum/material/wood
|
||||
name = "wood"
|
||||
id = "wood"
|
||||
desc = "Flexible, durable, but flamable. Hard to come across in space."
|
||||
color = "#bb8e53"
|
||||
strength_modifier = 0.5
|
||||
sheet_type = /obj/item/stack/sheet/mineral/wood
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE)
|
||||
value_per_unit = 0.06
|
||||
beauty_modifier = 0.1
|
||||
armor_modifiers = list("melee" = 1.1, "bullet" = 1.1, "laser" = 0.4, "energy" = 0.4, "bomb" = 1, "bio" = 0.2, "rad" = 0, "fire" = 0, "acid" = 0.3)
|
||||
@@ -201,10 +215,11 @@ Unless you know what you're doing, only use the first three numbers. They're in
|
||||
///Stronk force increase
|
||||
/datum/material/adamantine
|
||||
name = "adamantine"
|
||||
id = "adamantine"
|
||||
desc = "A powerful material made out of magic, I mean science!"
|
||||
color = "#6d7e8e"
|
||||
strength_modifier = 1.5
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/mineral/adamantine
|
||||
value_per_unit = 0.25
|
||||
beauty_modifier = 0.4
|
||||
@@ -213,9 +228,10 @@ Unless you know what you're doing, only use the first three numbers. They're in
|
||||
///RPG Magic. (Admin only)
|
||||
/datum/material/mythril
|
||||
name = "mythril"
|
||||
id = "mythril"
|
||||
desc = "How this even exists is byond me"
|
||||
color = "#f2d5d7"
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/mineral/mythril
|
||||
value_per_unit = 0.75
|
||||
beauty_modifier = 0.5
|
||||
@@ -230,134 +246,3 @@ Unless you know what you're doing, only use the first three numbers. They're in
|
||||
. = ..()
|
||||
if(istype(source, /obj/item))
|
||||
qdel(source.GetComponent(/datum/component/fantasy))
|
||||
|
||||
//I don't like sand. It's coarse, and rough, and irritating, and it gets everywhere.
|
||||
/datum/material/sand
|
||||
name = "sand"
|
||||
desc = "You know, it's amazing just how structurally sound sand can be."
|
||||
color = "#EDC9AF"
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/sandblock
|
||||
value_per_unit = 0.001
|
||||
strength_modifier = 0.5
|
||||
integrity_modifier = 0.1
|
||||
armor_modifiers = list("melee" = 0.25, "bullet" = 0.25, "laser" = 1.25, "energy" = 0.25, "bomb" = 0.25, "bio" = 0.25, "rad" = 1.5, "fire" = 1.5, "acid" = 1.5)
|
||||
beauty_modifier = 0.25
|
||||
turf_sound_override = FOOTSTEP_SAND
|
||||
texture_layer_icon_state = "sand"
|
||||
|
||||
//And now for our lavaland dwelling friends, sand, but in stone form! Truly revolutionary.
|
||||
/datum/material/sandstone
|
||||
name = "sandstone"
|
||||
desc = "Bialtaakid 'ant taerif ma hdha."
|
||||
color = "#B77D31"
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/mineral/sandstone
|
||||
value_per_unit = 0.0025
|
||||
armor_modifiers = list("melee" = 0.5, "bullet" = 0.5, "laser" = 1.25, "energy" = 0.5, "bomb" = 0.5, "bio" = 0.25, "rad" = 1.5, "fire" = 1.5, "acid" = 1.5)
|
||||
beauty_modifier = 0.3
|
||||
turf_sound_override = FOOTSTEP_WOOD
|
||||
texture_layer_icon_state = "brick"
|
||||
|
||||
/datum/material/snow
|
||||
name = "snow"
|
||||
desc = "There's no business like snow business."
|
||||
color = "#FFFFFF"
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/mineral/snow
|
||||
value_per_unit = 0.0025
|
||||
armor_modifiers = list("melee" = 0.25, "bullet" = 0.25, "laser" = 0.25, "energy" = 0.25, "bomb" = 0.25, "bio" = 0.25, "rad" = 1.5, "fire" = 0.25, "acid" = 1.5)
|
||||
beauty_modifier = 0.3
|
||||
turf_sound_override = FOOTSTEP_SAND
|
||||
texture_layer_icon_state = "sand"
|
||||
|
||||
/datum/material/runedmetal
|
||||
name = "runed metal"
|
||||
desc = "Mir'ntrath barhah Nar'sie."
|
||||
color = "#3C3434"
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/runed_metal
|
||||
value_per_unit = 0.75
|
||||
armor_modifiers = list("melee" = 1.2, "bullet" = 1.2, "laser" = 1, "energy" = 1, "bomb" = 1.2, "bio" = 1.2, "rad" = 1.5, "fire" = 1.5, "acid" = 1.5)
|
||||
beauty_modifier = -0.15
|
||||
texture_layer_icon_state = "runed"
|
||||
|
||||
/datum/material/bronze
|
||||
name = "bronze"
|
||||
desc = "Clock Cult? Never heard of it."
|
||||
color = "#92661A"
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/tile/bronze
|
||||
value_per_unit = 0.025
|
||||
armor_modifiers = list("melee" = 1, "bullet" = 1, "laser" = 1, "energy" = 1, "bomb" = 1, "bio" = 1, "rad" = 1.5, "fire" = 1.5, "acid" = 1.5)
|
||||
beauty_modifier = 0.2
|
||||
|
||||
/datum/material/paper
|
||||
name = "paper"
|
||||
desc = "Ten thousand folds of pure starchy power."
|
||||
color = "#E5DCD5"
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/paperframes
|
||||
value_per_unit = 0.0025
|
||||
armor_modifiers = list("melee" = 0.1, "bullet" = 0.1, "laser" = 0.1, "energy" = 0.1, "bomb" = 0.1, "bio" = 0.1, "rad" = 1.5, "fire" = 0, "acid" = 1.5)
|
||||
beauty_modifier = 0.3
|
||||
turf_sound_override = FOOTSTEP_SAND
|
||||
texture_layer_icon_state = "paper"
|
||||
|
||||
/datum/material/paper/on_applied_obj(obj/source, amount, material_flags)
|
||||
. = ..()
|
||||
if(material_flags & MATERIAL_AFFECT_STATISTICS)
|
||||
var/obj/paper = source
|
||||
paper.resistance_flags |= FLAMMABLE
|
||||
paper.obj_flags |= UNIQUE_RENAME
|
||||
|
||||
/datum/material/paper/on_removed_obj(obj/source, material_flags)
|
||||
if(material_flags & MATERIAL_AFFECT_STATISTICS)
|
||||
var/obj/paper = source
|
||||
paper.resistance_flags &= ~FLAMMABLE
|
||||
return ..()
|
||||
|
||||
/datum/material/cardboard
|
||||
name = "cardboard"
|
||||
desc = "They say cardboard is used by hobos to make incredible things."
|
||||
color = "#5F625C"
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/cardboard
|
||||
value_per_unit = 0.003
|
||||
armor_modifiers = list("melee" = 0.25, "bullet" = 0.25, "laser" = 0.25, "energy" = 0.25, "bomb" = 0.25, "bio" = 0.25, "rad" = 1.5, "fire" = 0, "acid" = 1.5)
|
||||
beauty_modifier = -0.1
|
||||
|
||||
/datum/material/cardboard/on_applied_obj(obj/source, amount, material_flags)
|
||||
. = ..()
|
||||
if(material_flags & MATERIAL_AFFECT_STATISTICS)
|
||||
var/obj/cardboard = source
|
||||
cardboard.resistance_flags |= FLAMMABLE
|
||||
cardboard.obj_flags |= UNIQUE_RENAME
|
||||
|
||||
/datum/material/cardboard/on_removed_obj(obj/source, material_flags)
|
||||
if(material_flags & MATERIAL_AFFECT_STATISTICS)
|
||||
var/obj/cardboard = source
|
||||
cardboard.resistance_flags &= ~FLAMMABLE
|
||||
return ..()
|
||||
|
||||
/datum/material/bone
|
||||
name = "bone"
|
||||
desc = "Man, building with this will make you the coolest caveman on the block."
|
||||
color = "#e3dac9"
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/bone
|
||||
value_per_unit = 0.05
|
||||
armor_modifiers = list("melee" = 1.2, "bullet" = 0.75, "laser" = 0.75, "energy" = 1.2, "bomb" = 1, "bio" = 1, "rad" = 1.5, "fire" = 1.5, "acid" = 1.5)
|
||||
beauty_modifier = -0.2
|
||||
|
||||
/datum/material/bamboo
|
||||
name = "bamboo"
|
||||
desc = "If it's good enough for pandas, it's good enough for you."
|
||||
color = "#339933"
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/mineral/bamboo
|
||||
value_per_unit = 0.0025
|
||||
armor_modifiers = list("melee" = 0.5, "bullet" = 0.5, "laser" = 0.5, "energy" = 0.5, "bomb" = 0.5, "bio" = 0.51, "rad" = 1.5, "fire" = 0.5, "acid" = 1.5)
|
||||
beauty_modifier = 0.2
|
||||
turf_sound_override = FOOTSTEP_WOOD
|
||||
texture_layer_icon_state = "bamboo"
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
///It's gross, gets the name of it's owner, and is all kinds of fucked up
|
||||
/datum/material/meat
|
||||
name = "meat"
|
||||
desc = "Meat"
|
||||
color = rgb(214, 67, 67)
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/meat
|
||||
value_per_unit = 0.05
|
||||
beauty_modifier = -0.3
|
||||
strength_modifier = 0.7
|
||||
armor_modifiers = list("melee" = 0.3, "bullet" = 0.3, "laser" = 1.2, "energy" = 1.2, "bomb" = 0.3, "bio" = 0, "rad" = 0.7, "fire" = 1, "acid" = 1)
|
||||
item_sound_override = 'sound/effects/meatslap.ogg'
|
||||
turf_sound_override = FOOTSTEP_MEAT
|
||||
texture_layer_icon_state = "meat"
|
||||
|
||||
/datum/material/meat/on_removed(atom/source, material_flags)
|
||||
. = ..()
|
||||
qdel(source.GetComponent(/datum/component/edible))
|
||||
|
||||
/datum/material/meat/on_applied_obj(obj/O, amount, material_flags)
|
||||
. = ..()
|
||||
O.obj_flags |= UNIQUE_RENAME //So you can name it after the person its made from, a depressing comprimise.
|
||||
make_edible(O, amount, material_flags)
|
||||
|
||||
/datum/material/meat/on_applied_turf(turf/T, amount, material_flags)
|
||||
. = ..()
|
||||
make_edible(T, amount, material_flags)
|
||||
|
||||
/datum/material/meat/proc/make_edible(atom/source, amount, material_flags)
|
||||
var/nutriment_count = 3 * (amount / MINERAL_MATERIAL_AMOUNT)
|
||||
var/oil_count = 2 * (amount / MINERAL_MATERIAL_AMOUNT)
|
||||
source.AddComponent(/datum/component/edible, list(/datum/reagent/consumable/nutriment = nutriment_count, /datum/reagent/consumable/cooking_oil = oil_count), null, RAW | MEAT | GROSS, null, 30, list("Fleshy"))
|
||||
@@ -1,30 +0,0 @@
|
||||
/datum/material/pizza
|
||||
name = "pizza"
|
||||
desc = "~Jamme, jamme, n'coppa, jamme ja! Jamme, jamme, n'coppa jamme ja, funi-culi funi-cala funi-culi funi-cala!! Jamme jamme ja funiculi funicula!~"
|
||||
color = "#FF9F23"
|
||||
categories = list(MAT_CATEGORY_RIGID = TRUE, MAT_CATEGORY_BASE_RECIPES = TRUE)
|
||||
sheet_type = /obj/item/stack/sheet/pizza
|
||||
value_per_unit = 0.05
|
||||
beauty_modifier = 0.1
|
||||
strength_modifier = 0.7
|
||||
armor_modifiers = list("melee" = 0.3, "bullet" = 0.3, "laser" = 1.2, "energy" = 1.2, "bomb" = 0.3, "bio" = 0, "rad" = 0.7, "fire" = 1, "acid" = 1)
|
||||
item_sound_override = 'sound/effects/meatslap.ogg'
|
||||
turf_sound_override = FOOTSTEP_MEAT
|
||||
texture_layer_icon_state = "pizza"
|
||||
|
||||
/datum/material/pizza/on_removed(atom/source, material_flags)
|
||||
. = ..()
|
||||
qdel(source.GetComponent(/datum/component/edible))
|
||||
|
||||
/datum/material/pizza/on_applied_obj(obj/O, amount, material_flags)
|
||||
. = ..()
|
||||
make_edible(O, amount, material_flags)
|
||||
|
||||
/datum/material/pizza/on_applied_turf(turf/T, amount, material_flags)
|
||||
. = ..()
|
||||
make_edible(T, amount, material_flags)
|
||||
|
||||
/datum/material/pizza/proc/make_edible(atom/source, amount, material_flags)
|
||||
var/nutriment_count = 3 * (amount / MINERAL_MATERIAL_AMOUNT)
|
||||
var/oil_count = 2 * (amount / MINERAL_MATERIAL_AMOUNT)
|
||||
source.AddComponent(/datum/component/edible, list(/datum/reagent/consumable/nutriment = nutriment_count, /datum/reagent/consumable/cooking_oil = oil_count), null, GRAIN | MEAT | DAIRY | VEGETABLES, null, 30, list("crust", "tomato", "cheese", "meat"))
|
||||
+1
-1
@@ -67,7 +67,7 @@
|
||||
var/datum/skill_holder/skill_holder
|
||||
|
||||
/datum/mind/New(var/key)
|
||||
skill_holder = new(src)
|
||||
skill_holder = new()
|
||||
src.key = key
|
||||
soulOwner = src
|
||||
martial_art = default_martial_art
|
||||
|
||||
@@ -42,7 +42,6 @@
|
||||
school = "evocation"
|
||||
charge_max = 600
|
||||
clothes_req = NONE
|
||||
antimagic_allowed = TRUE
|
||||
range = 20
|
||||
base_icon_state = "fireball"
|
||||
action_icon_state = "fireball0"
|
||||
@@ -123,7 +122,6 @@
|
||||
desc = "A rare genome that attracts odd forces not usually observed. May sometimes pull you in randomly."
|
||||
school = "evocation"
|
||||
clothes_req = NONE
|
||||
antimagic_allowed = TRUE
|
||||
charge_max = 600
|
||||
invocation = "DOOOOOOOOOOOOOOOOOOOOM!!!"
|
||||
invocation_type = "shout"
|
||||
@@ -157,7 +155,6 @@
|
||||
dropmessage = "You let the electricity from your hand dissipate."
|
||||
hand_path = /obj/item/melee/touch_attack/shock
|
||||
charge_max = 400
|
||||
antimagic_allowed = TRUE
|
||||
clothes_req = NONE
|
||||
action_icon_state = "zap"
|
||||
|
||||
@@ -215,7 +212,6 @@
|
||||
desc = "Get a scent off of the item you're currently holding to track it. With an empty hand, you'll track the scent you've remembered."
|
||||
charge_max = 100
|
||||
clothes_req = NONE
|
||||
antimagic_allowed = TRUE
|
||||
range = -1
|
||||
include_user = TRUE
|
||||
action_icon_state = "nose"
|
||||
@@ -294,7 +290,6 @@
|
||||
name = "Drop a limb"
|
||||
desc = "Concentrate to make a random limb pop right off your body."
|
||||
clothes_req = NONE
|
||||
antimagic_allowed = TRUE
|
||||
charge_max = 100
|
||||
action_icon_state = "autotomy"
|
||||
|
||||
@@ -332,7 +327,6 @@
|
||||
name = "Lay Web"
|
||||
desc = "Drops a web. Only you will be able to traverse your web easily, making it pretty good for keeping you safe."
|
||||
clothes_req = NONE
|
||||
antimagic_allowed = TRUE
|
||||
charge_max = 4 SECONDS //the same time to lay a web
|
||||
action_icon = 'icons/mob/actions/actions_genetic.dmi'
|
||||
action_icon_state = "lay_web"
|
||||
@@ -374,7 +368,6 @@
|
||||
name = "Launch spike"
|
||||
desc = "Shoot your tongue out in the direction you're facing, embedding it and dealing damage until they remove it."
|
||||
clothes_req = NONE
|
||||
antimagic_allowed = TRUE
|
||||
charge_max = 100
|
||||
action_icon = 'icons/mob/actions/actions_genetic.dmi'
|
||||
action_icon_state = "spike"
|
||||
@@ -413,8 +406,6 @@
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
sharpness = IS_SHARP
|
||||
var/mob/living/carbon/human/fired_by
|
||||
/// if we missed our target
|
||||
var/missed = TRUE
|
||||
|
||||
/obj/item/hardened_spike/Initialize(mapload, firedby)
|
||||
. = ..()
|
||||
@@ -422,12 +413,13 @@
|
||||
addtimer(CALLBACK(src, .proc/checkembedded), 5 SECONDS)
|
||||
|
||||
/obj/item/hardened_spike/proc/checkembedded()
|
||||
if(missed)
|
||||
unembedded()
|
||||
|
||||
/obj/item/hardened_spike/embedded(atom/target)
|
||||
if(isbodypart(target))
|
||||
missed = FALSE
|
||||
if(ishuman(loc))
|
||||
var/mob/living/carbon/human/embedtest = loc
|
||||
for(var/l in embedtest.bodyparts)
|
||||
var/obj/item/bodypart/limb = l
|
||||
if(src in limb.embedded_objects)
|
||||
return limb
|
||||
unembedded()
|
||||
|
||||
/obj/item/hardened_spike/unembedded()
|
||||
var/turf/T = get_turf(src)
|
||||
@@ -498,7 +490,11 @@
|
||||
|
||||
var/obj/item/bodypart/L = spikey.checkembedded()
|
||||
|
||||
L.embedded_objects -= spikey
|
||||
//this is where it would deal damage, if it transfers chems it removes itself so no damage
|
||||
spikey.forceMove(get_turf(L))
|
||||
transfered.visible_message("<span class='notice'>[spikey] falls out of [transfered]!</span>")
|
||||
|
||||
if(!transfered.has_embedded_objects())
|
||||
transfered.clear_alert("embeddedobject")
|
||||
SEND_SIGNAL(transfered, COMSIG_CLEAR_MOOD_EVENT, "embedded")
|
||||
spikey.unembedded()
|
||||
|
||||
@@ -162,10 +162,6 @@
|
||||
port_id = "pirate"
|
||||
can_be_bought = FALSE
|
||||
|
||||
/datum/map_template/shuttle/hunter
|
||||
port_id = "hunter"
|
||||
can_be_bought = FALSE
|
||||
|
||||
/datum/map_template/shuttle/ruin //For random shuttles in ruins
|
||||
port_id = "ruin"
|
||||
can_be_bought = FALSE
|
||||
@@ -462,10 +458,6 @@
|
||||
suffix = "whiteship_pod"
|
||||
name = "Salvage Pod"
|
||||
|
||||
/datum/map_template/shuttle/whiteship/cog
|
||||
suffix = "cog"
|
||||
name = "NT Prisoner Transport"
|
||||
|
||||
/datum/map_template/shuttle/cargo/box
|
||||
suffix = "box"
|
||||
name = "supply shuttle (Box)"
|
||||
@@ -621,15 +613,3 @@
|
||||
/datum/map_template/shuttle/snowdin/excavation
|
||||
suffix = "excavation"
|
||||
name = "Snowdin Excavation Elevator"
|
||||
|
||||
/datum/map_template/shuttle/hunter/space_cop
|
||||
suffix = "space_cop"
|
||||
name = "Police Spacevan"
|
||||
|
||||
/datum/map_template/shuttle/hunter/russian
|
||||
suffix = "russian"
|
||||
name = "Russian Cargo Ship"
|
||||
|
||||
/datum/map_template/shuttle/hunter/bounty
|
||||
suffix = "bounty"
|
||||
name = "Bounty Hunter Ship"
|
||||
|
||||
@@ -11,66 +11,6 @@
|
||||
if(!mind.skill_holder)
|
||||
to_chat(usr, "<span class='warning'>How do you check the skills of [(usr == src)? "yourself when you are" : "something"] without the capability for skills? (PROBABLY A BUG, PRESS F1.)</span>")
|
||||
return
|
||||
|
||||
mind.skill_holder.ui_interact(src)
|
||||
|
||||
/datum/skill_holder/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.always_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "skillpanel", "[owner.name]'s Skills", 620, 580, master_ui, state)
|
||||
ui.set_autoupdate(FALSE) // This UI is only ever opened by one person, and never is updated outside of user input.
|
||||
ui.open()
|
||||
else if(need_static_data_update)
|
||||
update_static_data(user)
|
||||
need_static_data_update = FALSE
|
||||
|
||||
/datum/skill_holder/ui_static_data(mob/user)
|
||||
. = list()
|
||||
.["skills"] = list()
|
||||
for(var/path in GLOB.skill_datums)
|
||||
var/datum/skill/S = GLOB.skill_datums[path]
|
||||
var/list/dat = S.get_skill_data(src)
|
||||
if(islist(dat["modifiers"]))
|
||||
dat["modifiers"] = jointext(dat["modifiers"], ", ")
|
||||
dat["percent_base"] = (dat["value_base"] / dat["max_value"])
|
||||
dat["percent_mod"] = (dat["value_mod"] / dat["max_value"])
|
||||
.["skills"] += list(dat)
|
||||
|
||||
/datum/skill_holder/ui_data(mob/user)
|
||||
. = list()
|
||||
.["playername"] = owner.name
|
||||
.["see_skill_mods"] = see_skill_mods
|
||||
.["admin"] = check_rights(R_DEBUG, FALSE)
|
||||
|
||||
/datum/skill_holder/ui_act(action, params)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
switch(action)
|
||||
if("toggle_mods")
|
||||
see_skill_mods = !see_skill_mods
|
||||
return TRUE
|
||||
if ("adj_exp")
|
||||
if(!check_rights(R_DEBUG))
|
||||
return
|
||||
var/skill = text2path(params["skill"])
|
||||
var/number = input("Please insert the amount of experience/progress you'd like to add/subtract:") as num|null
|
||||
if (number)
|
||||
owner.set_skill_value(skill, owner.get_skill_value(skill, FALSE) + number)
|
||||
return TRUE
|
||||
if ("set_exp")
|
||||
if(!check_rights(R_DEBUG))
|
||||
return
|
||||
var/skill = text2path(params["skill"])
|
||||
var/number = input("Please insert the number you want to set the player's exp/progress to:") as num|null
|
||||
if (!isnull(number))
|
||||
owner.set_skill_value(skill, number)
|
||||
return TRUE
|
||||
if ("set_lvl")
|
||||
if(!check_rights(R_DEBUG))
|
||||
return
|
||||
var/datum/skill/level/S = GLOB.skill_datums[text2path(params["skill"])]
|
||||
var/number = input("Please insert a whole number between 0[S.associative ? " ([S.unskilled_tier])" : ""] and [S.max_levels][S.associative ? " ([S.levels[S.max_levels]])" : ""] corresponding to the level you'd like to set the player to.") as num|null
|
||||
if (number >= 0 && number <= S.max_levels)
|
||||
owner.set_skill_value(S.type, S.get_skill_level_value(number))
|
||||
return TRUE
|
||||
var/datum/browser/B = new(usr, "skilldisplay_[REF(src)]", "Skills of [src]")
|
||||
B.set_content(mind.skill_html_readout())
|
||||
B.open()
|
||||
|
||||
@@ -8,7 +8,6 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
|
||||
continue
|
||||
S = new path
|
||||
.[S.type] = S
|
||||
. = sortTim(., /proc/cmp_skill_categories, TRUE)
|
||||
|
||||
/**
|
||||
* Skill datums
|
||||
@@ -33,14 +32,8 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
|
||||
var/base_multiplier = 1
|
||||
/// Value added to the base multiplier depending on overall competency compared to maximum value/level.
|
||||
var/competency_multiplier = 1
|
||||
/// Experience gain multiplier gained from using items.
|
||||
var/item_skill_gain_multi = 1
|
||||
/// Skill gain quantisation
|
||||
var/skill_gain_quantisation = 0.1
|
||||
/// A list of ways this skill can affect or be affected through actions and skill modifiers.
|
||||
var/list/skill_traits = list(SKILL_SANITY, SKILL_INTELLIGENCE)
|
||||
/// Index of this skill in the UI
|
||||
var/ui_category = SKILL_UI_CAT_MISC
|
||||
|
||||
/**
|
||||
* Ensures what someone's setting as a value for this skill is valid.
|
||||
@@ -64,28 +57,10 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
|
||||
return new_value > existing
|
||||
|
||||
/**
|
||||
* Get a list of data used in the skill panel menu.
|
||||
* Standard value "render"
|
||||
*/
|
||||
/datum/skill/proc/get_skill_data(datum/skill_holder/H)
|
||||
var/skill_value = H.owner.get_skill_value(type, FALSE)
|
||||
. = list(
|
||||
"name" = name,
|
||||
"desc" = desc,
|
||||
"path" = type,
|
||||
"value_base" = skill_value,
|
||||
"value_mod" = skill_value,
|
||||
"modifiers" = "None",
|
||||
"max_value" = 1 //To avoid division by zero later on.
|
||||
)
|
||||
var/list/mods = LAZYACCESS(H.skill_value_mods, type)
|
||||
if(mods)
|
||||
var/list/mod_names = list()
|
||||
for(var/k in mods)
|
||||
var/datum/skill_modifier/M = GLOB.skill_modifiers[k]
|
||||
mod_names |= M.name
|
||||
skill_value = M.apply_modifier(skill_value, type, H, MODIFIER_TARGET_VALUE)
|
||||
.["value_mod"] = skill_value
|
||||
.["modifiers"] = mod_names //Will be jointext()'d later.
|
||||
/datum/skill/proc/standard_render_value(value, level)
|
||||
return value
|
||||
|
||||
// Just saying, the choice to use different sub-parent-types is to force coders to resolve issues as I won't be implementing custom procs to grab skill levels in a certain context.
|
||||
// Aka: So people don't forget to change checks if they change a skill's progression type.
|
||||
@@ -96,12 +71,10 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
|
||||
competency_thresholds = list(THRESHOLD_COMPETENT = FALSE, THRESHOLD_EXPERT = TRUE, THRESHOLD_MASTER = TRUE)
|
||||
|
||||
/datum/skill/binary/sanitize_value(new_value)
|
||||
return new_value >= 1 ? TRUE : FALSE
|
||||
return new_value? TRUE : FALSE
|
||||
|
||||
/datum/skill/binary/get_skill_data(datum/skill_holder/H)
|
||||
. = ..()
|
||||
.["base_readout"] = .["value_base"] ? "Learned: Yes" : "Learned: No"
|
||||
.["mod_readout"] = .["value_mod"] ? "Learned: Yes" : "Learned: No"
|
||||
/datum/skill/binary/standard_render_value(value, level)
|
||||
return value? "Yes" : "No"
|
||||
|
||||
/datum/skill/numerical
|
||||
abstract_type = /datum/skill/numerical
|
||||
@@ -111,19 +84,14 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
|
||||
var/max_value = 100
|
||||
/// Min value of this skill
|
||||
var/min_value = 0
|
||||
|
||||
/datum/skill/numerical/New()
|
||||
..()
|
||||
skill_gain_quantisation = item_skill_gain_multi = item_skill_gain_multi * (max_value - min_value) * STD_NUM_SKILL_ITEM_GAIN_MULTI
|
||||
/// Display as a percent in standard_render_value?
|
||||
var/display_as_percent = FALSE
|
||||
|
||||
/datum/skill/numerical/sanitize_value(new_value)
|
||||
return clamp(new_value, min_value, max_value)
|
||||
|
||||
/datum/skill/numerical/get_skill_data(datum/skill_holder/H)
|
||||
. = ..()
|
||||
.["base_readout"] = "Skill Progress: \[[.["value_base"]] / [max_value]\]"
|
||||
.["mod_readout"] = "Skill Progress: \[[.["value_mod"]] / [max_value]\]"
|
||||
.["max_value"] = max_value
|
||||
/datum/skill/numerical/standard_render_value(value, level)
|
||||
return display_as_percent? "[round(value/max_value/100, 0.01)]%" : "[value] / [max_value]"
|
||||
|
||||
/datum/skill/enum
|
||||
abstract_type = /datum/skill/enum
|
||||
@@ -155,7 +123,13 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
|
||||
var/max_assoc = ""
|
||||
var/max_assoc_start = 1
|
||||
for(var/lvl in 1 to max_levels)
|
||||
var/value = round(get_skill_level_value(lvl), 1)
|
||||
var/value
|
||||
switch(level_up_method)
|
||||
if(STANDARD_LEVEL_UP)
|
||||
value = XP_LEVEL(standard_xp_lvl_up, xp_lvl_multiplier, lvl)
|
||||
if(DWARFY_LEVEL_UP)
|
||||
value = DORF_XP_LEVEL(standard_xp_lvl_up, xp_lvl_multiplier, lvl)
|
||||
value = round(value, 1)
|
||||
if(!associative)
|
||||
levels += value
|
||||
continue
|
||||
@@ -193,13 +167,8 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
|
||||
else if(. < 0)
|
||||
to_chat(M.current, "<span class='warning'>I feel like I've become worse at [name]!</span>")
|
||||
|
||||
/datum/skill/level/get_skill_data(datum/skill_holder/H)
|
||||
. = ..()
|
||||
var/skill_value_base = .["value_base"]
|
||||
var/skill_value_mod = .["value_mod"]
|
||||
.["level_based"] = TRUE
|
||||
|
||||
var/level = LAZYACCESS(H.skill_levels, type) || 0
|
||||
/datum/skill/level/standard_render_value(value, level)
|
||||
var/current_lvl = associative ? (!level ? unskilled_tier : levels[level]) : level
|
||||
var/current_lvl_xp_sum = 0
|
||||
if(level)
|
||||
current_lvl_xp_sum = associative ? levels[levels[level]] : levels[level]
|
||||
@@ -207,50 +176,8 @@ GLOBAL_LIST_INIT_TYPED(skill_datums, /datum/skill, init_skill_datums())
|
||||
var/next_lvl_xp = associative ? levels[levels[next_index]] : levels[next_index]
|
||||
if(next_lvl_xp > current_lvl_xp_sum)
|
||||
next_lvl_xp -= current_lvl_xp_sum
|
||||
.["lvl_base_num"] = .["lvl_mod_num"] = level
|
||||
.["lvl_base"] = .["lvl_mod"] = associative ? (!level ? unskilled_tier : levels[level]) : level
|
||||
.["base_style"] = .["mod_style"] = "font-weight:bold; color:hsl([(level+1)*(350/max_levels+1)], 50%, 50%)"
|
||||
.["xp_next_lvl_base"] = .["xp_next_lvl_mod"] = "\[[skill_value_base - current_lvl_xp_sum]/[next_lvl_xp]\]"
|
||||
|
||||
.["max_lvl"] = max_levels
|
||||
var/max_value = associative ? levels[levels[max_levels]] : levels[max_levels]
|
||||
.["max_value"] = max_value
|
||||
|
||||
.["base_readout"] = "Overall Skill Progress: \[[skill_value_base]/[max_value]\]"
|
||||
.["mod_readout"] = "Overall Skill Progress: \[[skill_value_mod]/[max_value]\]"
|
||||
|
||||
var/list/mods = LAZYACCESS(H.skill_level_mods, type)
|
||||
if(mods) //I'm not proud of doing the same-ish process twice a row but here we go.
|
||||
var/list/mod_names = .["modifiers"]
|
||||
if(!mod_names)
|
||||
.["modifiers"] = mod_names = list()
|
||||
for(var/k in mods)
|
||||
var/datum/skill_modifier/M = GLOB.skill_modifiers[k]
|
||||
mod_names |= M.name
|
||||
level = M.apply_modifier(level, type, H, MODIFIER_TARGET_LEVEL)
|
||||
|
||||
if(level)
|
||||
current_lvl_xp_sum = associative ? levels[levels[level]] : levels[level]
|
||||
else
|
||||
current_lvl_xp_sum = 0
|
||||
next_index = min(max_levels, level+1)
|
||||
next_lvl_xp = associative ? levels[levels[next_index]] : levels[next_index]
|
||||
if(next_lvl_xp > current_lvl_xp_sum)
|
||||
next_lvl_xp -= current_lvl_xp_sum
|
||||
.["lvl_mod_num"] = level
|
||||
.["lvl_mod"] = associative ? (!level ? unskilled_tier : levels[level]) : level
|
||||
.["mod_style"] = "font-weight:bold; color:hsl([(level+1)*(300/(max_levels+1))], 50%, 50%)"
|
||||
.["xp_next_lvl_mod"] = "\[[skill_value_mod - current_lvl_xp_sum]/[next_lvl_xp]\]"
|
||||
|
||||
/**
|
||||
* Gets the base value required to reach a level specified by the 'num' arg.
|
||||
*/
|
||||
/datum/skill/level/proc/get_skill_level_value(num)
|
||||
switch(level_up_method)
|
||||
if(STANDARD_LEVEL_UP)
|
||||
. = XP_LEVEL(standard_xp_lvl_up, xp_lvl_multiplier, num)
|
||||
if(DWARFY_LEVEL_UP)
|
||||
. = DORF_XP_LEVEL(standard_xp_lvl_up, xp_lvl_multiplier, num)
|
||||
return "[associative ? current_lvl : "Lvl. [current_lvl]"] ([value - current_lvl_xp_sum]/[next_lvl_xp])[level == max_levels ? " \[MAX!\]" : ""]"
|
||||
|
||||
/datum/skill/level/job
|
||||
abstract_type = /datum/skill/level/job
|
||||
|
||||
@@ -20,18 +20,6 @@
|
||||
var/list/original_values
|
||||
var/list/original_affinities
|
||||
var/list/original_levels
|
||||
/// The mind datum this skill is associated with, only used for the check_skills UI
|
||||
var/datum/mind/owner
|
||||
/// For UI updates.
|
||||
var/need_static_data_update = TRUE
|
||||
/// Whether modifiers and final skill values or only base values are displayed.
|
||||
var/see_skill_mods = TRUE
|
||||
/// The current selected skill category.
|
||||
var/selected_category
|
||||
|
||||
/datum/skill_holder/New(owner)
|
||||
..()
|
||||
src.owner = owner
|
||||
|
||||
/**
|
||||
* Grabs the value of a skill.
|
||||
@@ -94,7 +82,6 @@
|
||||
if(!isnull(value))
|
||||
LAZYINITLIST(skill_holder.skills)
|
||||
S.set_skill_value(skill_holder, value, src, silent)
|
||||
skill_holder.need_static_data_update = TRUE
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
@@ -120,9 +107,11 @@
|
||||
CRASH("You cannot auto increment a non numerical(experience skill!")
|
||||
var/current = get_skill_value(skill, FALSE)
|
||||
var/affinity = get_skill_affinity(skill)
|
||||
var/target_value = round(current + (value * affinity), S.skill_gain_quantisation)
|
||||
if(maximum && target_value >= maximum) //no more experience to gain, early return.
|
||||
return
|
||||
var/target_value = current + (value * affinity)
|
||||
if(maximum)
|
||||
target_value = min(target_value, maximum)
|
||||
if(target_value == maximum) //no more experience to gain, early return.
|
||||
return
|
||||
boost_skill_value_to(skill, target_value, silent, current)
|
||||
|
||||
/**
|
||||
@@ -194,3 +183,18 @@
|
||||
divisor++
|
||||
if(divisor)
|
||||
. = modifier_is_multiplier ? value*(sum/divisor) : value/(sum/divisor)
|
||||
|
||||
/**
|
||||
* Generates a HTML readout of our skills.
|
||||
* Port to tgui-next when?
|
||||
*/
|
||||
/datum/mind/proc/skill_html_readout()
|
||||
var/list/out = list("<center><h1>Skills</h1></center><hr>")
|
||||
out += "<table style=\"width:100%\"><tr><th><b>Skill</b><th><b>Value</b></tr>"
|
||||
for(var/path in GLOB.skill_datums)
|
||||
var/datum/skill/S = GLOB.skill_datums[path]
|
||||
var/skill_value = get_skill_value(path)
|
||||
var/skill_level = get_skill_level(path, round = TRUE)
|
||||
out += "<tr><td><font color='[S.name_color]'>[S.name]</font></td><td>[S.standard_render_value(skill_value, skill_level)]</td></tr>"
|
||||
out += "</table>"
|
||||
return out.Join("")
|
||||
|
||||
@@ -7,8 +7,6 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill)
|
||||
* and cause lots of edge cases. These are fairly simple overall... make a subtype though, don't use this one.
|
||||
*/
|
||||
/datum/skill_modifier
|
||||
/// Name and description of the skill modifier, used in the UI
|
||||
var/name = "???"
|
||||
/// flags for this skill modifier.
|
||||
var/modifier_flags = NONE
|
||||
/// target skills, can be a specific skill typepath or a list of skill traits.
|
||||
@@ -112,7 +110,6 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill)
|
||||
if(M.modifier_flags & MODIFIER_SKILL_LEVEL)
|
||||
ADD_MOD_STEP(skill_holder.skill_level_mods, path, skill_holder.original_levels, get_skill_level(path, FALSE))
|
||||
LAZYSET(skill_holder.all_current_skill_modifiers, id, TRUE)
|
||||
skill_holder.need_static_data_update = TRUE
|
||||
|
||||
if(M.modifier_flags & MODIFIER_SKILL_BODYBOUND)
|
||||
M.RegisterSignal(src, COMSIG_MIND_TRANSFER, /datum/skill_modifier.proc/on_mind_transfer)
|
||||
@@ -144,7 +141,6 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill)
|
||||
if(M.modifier_flags & MODIFIER_SKILL_LEVEL && skill_holder.skill_level_mods)
|
||||
REMOVE_MOD_STEP(skill_holder.skill_level_mods, path, skill_holder.original_levels)
|
||||
LAZYREMOVE(skill_holder.all_current_skill_modifiers, id)
|
||||
skill_holder.need_static_data_update = TRUE
|
||||
|
||||
if(!mind_transfer && M.modifier_flags & MODIFIER_SKILL_BODYBOUND)
|
||||
M.UnregisterSignal(src, COMSIG_MIND_TRANSFER)
|
||||
@@ -169,7 +165,11 @@ GLOBAL_LIST_EMPTY(potential_mods_per_skill)
|
||||
var/datum/skill/S = GLOB.skill_datums[skillpath]
|
||||
if(method == MODIFIER_TARGET_VALUE && S.progression_type == SKILL_PROGRESSION_LEVEL)
|
||||
var/datum/skill/level/L = S
|
||||
mod = L.get_skill_level_value(L.competency_thresholds[mod])
|
||||
switch(L.level_up_method)
|
||||
if(STANDARD_LEVEL_UP)
|
||||
mod = XP_LEVEL(L.standard_xp_lvl_up, L.xp_lvl_multiplier, S.competency_thresholds[mod])
|
||||
if(DWARFY_LEVEL_UP)
|
||||
mod = DORF_XP_LEVEL(L.standard_xp_lvl_up, L.xp_lvl_multiplier, S.competency_thresholds[mod])
|
||||
else
|
||||
mod = S.competency_thresholds[mod]
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/datum/skill/level/job/wiring
|
||||
name = "Wiring"
|
||||
desc = "How proficient and knowledged you are at wiring beyond making post-futuristic wire art."
|
||||
desc = "How proficient and knowledged you are at wiring beyond laying cables on the floor."
|
||||
name_color = COLOR_PALE_ORANGE
|
||||
skill_traits = list(SKILL_SANITY, SKILL_INTELLIGENCE, SKILL_USE_TOOL, SKILL_TRAINING_TOOL)
|
||||
ui_category = SKILL_UI_CAT_ENG
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/datum/skill/numerical/surgery
|
||||
name = "Surgery"
|
||||
desc = "How proficient you are at performing surgical procedures."
|
||||
desc = "How proficient you are at doing surgery."
|
||||
name_color = COLOR_PALE_BLUE_GRAY
|
||||
competency_multiplier = 1.5 // 60% surgery speed up at max value of 100, considering the base multiplier.
|
||||
ui_category = SKILL_UI_CAT_MED
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/// Jobbie skill modifiers.
|
||||
|
||||
/datum/skill_modifier/job
|
||||
name = "Job Training"
|
||||
modifier_flags = MODIFIER_SKILL_VALUE|MODIFIER_SKILL_VIRTUE|MODIFIER_SKILL_ORIGIN_DIFF
|
||||
priority = MODIFIER_SKILL_PRIORITY_MAX
|
||||
|
||||
@@ -24,7 +23,7 @@
|
||||
modifier_flags = MODIFIER_SKILL_VALUE|MODIFIER_SKILL_LEVEL|MODIFIER_SKILL_VIRTUE|MODIFIER_SKILL_ORIGIN_DIFF
|
||||
level_mod = JOB_SKILL_TRAINED
|
||||
|
||||
/datum/skill_modifier/job/level/New(id, register = FALSE)
|
||||
/datum/skill_modifier/job/level/New(id)
|
||||
if(level_mod)
|
||||
value_mod = GET_STANDARD_LVL(level_mod)
|
||||
..()
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
/datum/skill_modifier/bad_mood
|
||||
name = "Mood (Dejected)"
|
||||
modifier_flags = MODIFIER_SKILL_VALUE|MODIFIER_SKILL_LEVEL|MODIFIER_SKILL_MULT|MODIFIER_SKILL_BODYBOUND
|
||||
target_skills = list(SKILL_SANITY)
|
||||
|
||||
/datum/skill_modifier/great_mood
|
||||
name = "Mood (Elated)"
|
||||
modifier_flags = MODIFIER_SKILL_AFFINITY|MODIFIER_SKILL_MULT|MODIFIER_SKILL_BODYBOUND
|
||||
target_skills = list(SKILL_SANITY)
|
||||
affinity_mod = 1.2
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
/datum/skill_modifier/brain_damage
|
||||
name = "Brain Damage"
|
||||
target_skills = list(SKILL_INTELLIGENCE)
|
||||
modifier_flags = MODIFIER_SKILL_VALUE|MODIFIER_SKILL_AFFINITY|MODIFIER_SKILL_LEVEL|MODIFIER_SKILL_MULT|MODIFIER_SKILL_BODYBOUND
|
||||
value_mod = 0.85
|
||||
@@ -7,7 +6,6 @@
|
||||
affinity_mod = 0.85
|
||||
|
||||
/datum/skill_modifier/heavy_brain_damage
|
||||
name = "Brain Damage (Severe)"
|
||||
target_skills = list(SKILL_INTELLIGENCE)
|
||||
modifier_flags = MODIFIER_SKILL_VALUE|MODIFIER_SKILL_AFFINITY|MODIFIER_SKILL_LEVEL|MODIFIER_SKILL_BODYBOUND|MODIFIER_SKILL_HANDICAP|MODIFIER_USE_THRESHOLDS
|
||||
priority = MODIFIER_SKILL_PRIORITY_LOW
|
||||
|
||||
@@ -81,11 +81,11 @@
|
||||
owner.adjustStaminaLoss(-0.5) //reduce stamina loss by 0.5 per tick, 10 per 2 seconds
|
||||
if(human_owner && human_owner.drunkenness)
|
||||
human_owner.drunkenness *= 0.997 //reduce drunkenness by 0.3% per tick, 6% per 2 seconds
|
||||
if(carbon_owner && !carbon_owner.dreaming && prob(2))
|
||||
carbon_owner.dream()
|
||||
// 2% per second, tick interval is in deciseconds
|
||||
if(prob((tick_interval+1) * 0.2) && owner.health > owner.crit_threshold)
|
||||
owner.emote("snore")
|
||||
if(prob(20))
|
||||
if(carbon_owner)
|
||||
carbon_owner.handle_dreams()
|
||||
if(prob(10) && owner.health > owner.crit_threshold)
|
||||
owner.emote("snore")
|
||||
|
||||
/datum/status_effect/staggered
|
||||
id = "staggered"
|
||||
@@ -365,9 +365,9 @@
|
||||
status_type = STATUS_EFFECT_REPLACE
|
||||
alert_type = null
|
||||
var/mutable_appearance/marked_underlay
|
||||
var/obj/item/kinetic_crusher/hammer_synced
|
||||
var/obj/item/twohanded/kinetic_crusher/hammer_synced
|
||||
|
||||
/datum/status_effect/crusher_mark/on_creation(mob/living/new_owner, obj/item/kinetic_crusher/new_hammer_synced)
|
||||
/datum/status_effect/crusher_mark/on_creation(mob/living/new_owner, obj/item/twohanded/kinetic_crusher/new_hammer_synced)
|
||||
. = ..()
|
||||
if(.)
|
||||
hammer_synced = new_hammer_synced
|
||||
@@ -711,9 +711,8 @@ datum/status_effect/pacify
|
||||
if(hearing_args[HEARING_SPEAKER] == owner)
|
||||
return
|
||||
var/mob/living/carbon/C = owner
|
||||
var/hypnomsg = uncostumize_say(hearing_args[HEARING_RAW_MESSAGE], hearing_args[HEARING_MESSAGE_MODE])
|
||||
C.cure_trauma_type(/datum/brain_trauma/hypnosis, TRAUMA_RESILIENCE_SURGERY) //clear previous hypnosis
|
||||
addtimer(CALLBACK(C, /mob/living/carbon.proc/gain_trauma, /datum/brain_trauma/hypnosis, TRAUMA_RESILIENCE_SURGERY, hypnomsg), 10)
|
||||
addtimer(CALLBACK(C, /mob/living/carbon.proc/gain_trauma, /datum/brain_trauma/hypnosis, TRAUMA_RESILIENCE_SURGERY, hearing_args[HEARING_RAW_MESSAGE]), 10)
|
||||
addtimer(CALLBACK(C, /mob/living.proc/Stun, 60, TRUE, TRUE), 15) //Take some time to think about it
|
||||
qdel(src)
|
||||
|
||||
@@ -796,44 +795,3 @@ datum/status_effect/pacify
|
||||
name = "Genetic Breakdown"
|
||||
desc = "I don't feel so good. Your body can't handle the mutations! You have one minute to remove your mutations, or you will be met with a horrible fate."
|
||||
icon_state = "dna_melt"
|
||||
|
||||
/datum/status_effect/fake_virus
|
||||
id = "fake_virus"
|
||||
duration = 1800//3 minutes
|
||||
status_type = STATUS_EFFECT_REPLACE
|
||||
tick_interval = 1
|
||||
alert_type = null
|
||||
var/msg_stage = 0//so you dont get the most intense messages immediately
|
||||
|
||||
/datum/status_effect/fake_virus/tick()
|
||||
var/fake_msg = ""
|
||||
var/fake_emote = ""
|
||||
switch(msg_stage)
|
||||
if(0 to 300)
|
||||
if(prob(1))
|
||||
fake_msg = pick("<span class='warning'>[pick("Your head hurts.", "Your head pounds.")]</span>",
|
||||
"<span class='warning'>[pick("You're having difficulty breathing.", "Your breathing becomes heavy.")]</span>",
|
||||
"<span class='warning'>[pick("You feel dizzy.", "Your head spins.")]</span>",
|
||||
"<span notice='warning'>[pick("You swallow excess mucus.", "You lightly cough.")]</span>",
|
||||
"<span class='warning'>[pick("Your head hurts.", "Your mind blanks for a moment.")]</span>",
|
||||
"<span class='warning'>[pick("Your throat hurts.", "You clear your throat.")]</span>")
|
||||
if(301 to 600)
|
||||
if(prob(2))
|
||||
fake_msg = pick("<span class='warning'>[pick("Your head hurts a lot.", "Your head pounds incessantly.")]</span>",
|
||||
"<span class='warning'>[pick("Your windpipe feels like a straw.", "Your breathing becomes tremendously difficult.")]</span>",
|
||||
"<span class='warning'>You feel very [pick("dizzy","woozy","faint")].</span>",
|
||||
"<span class='warning'>[pick("You hear a ringing in your ear.", "Your ears pop.")]</span>",
|
||||
"<span class='warning'>You nod off for a moment.</span>")
|
||||
else
|
||||
if(prob(3))
|
||||
if(prob(50))// coin flip to throw a message or an emote
|
||||
fake_msg = pick("<span class='userdanger'>[pick("Your head hurts!", "You feel a burning knife inside your brain!", "A wave of pain fills your head!")]</span>",
|
||||
"<span class='userdanger'>[pick("Your lungs hurt!", "It hurts to breathe!")]</span>",
|
||||
"<span class='warning'>[pick("You feel nauseated.", "You feel like you're going to throw up!")]</span>")
|
||||
else
|
||||
fake_emote = pick("cough", "sniff", "sneeze")
|
||||
if(fake_emote)
|
||||
owner.emote(fake_emote)
|
||||
else if(fake_msg)
|
||||
to_chat(owner, fake_msg)
|
||||
msg_stage++
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
var/id = "effect" //Used for screen alerts.
|
||||
var/duration = -1 //How long the status effect lasts in DECISECONDS. Enter -1 for an effect that never ends unless removed through some means.
|
||||
var/tick_interval = 10 //How many deciseconds between ticks, approximately. Leave at 10 for every second.
|
||||
var/next_tick //The scheduled time for the next tick.
|
||||
var/mob/living/owner //The mob affected by the status effect.
|
||||
var/on_remove_on_mob_delete = FALSE //if we call on_remove() when the mob is deleted
|
||||
var/examine_text //If defined, this text will appear when the mob is examined - to use he, she etc. use "SUBJECTPRONOUN" and replace it in the examines themselves
|
||||
@@ -32,7 +31,7 @@
|
||||
return
|
||||
if(duration != -1)
|
||||
duration = world.time + duration
|
||||
next_tick = world.time + tick_interval
|
||||
tick_interval = world.time + tick_interval
|
||||
if(alert_type)
|
||||
var/obj/screen/alert/status_effect/A = owner.throw_alert(id, alert_type)
|
||||
A.attached_effect = src //so the alert can reference us, if it needs to
|
||||
@@ -53,9 +52,9 @@
|
||||
if(!owner)
|
||||
qdel(src)
|
||||
return
|
||||
if(next_tick < world.time)
|
||||
if(tick_interval < world.time)
|
||||
tick()
|
||||
next_tick = world.time + tick_interval
|
||||
tick_interval = world.time + initial(tick_interval)
|
||||
if(duration != -1 && duration < world.time)
|
||||
qdel(src)
|
||||
|
||||
@@ -222,7 +221,7 @@
|
||||
threshold_crossed = FALSE //resets threshold effect if we fall below threshold so threshold effect can trigger again
|
||||
on_threshold_drop()
|
||||
if(stacks_added > 0)
|
||||
next_tick += delay_before_decay //refreshes time until decay
|
||||
tick_interval += delay_before_decay //refreshes time until decay
|
||||
stacks = min(stacks, max_stacks)
|
||||
status_overlay.icon_state = "[overlay_state][stacks]"
|
||||
status_underlay.icon_state = "[underlay_state][stacks]"
|
||||
|
||||
@@ -75,8 +75,8 @@
|
||||
|
||||
|
||||
/datum/wires/explosive/gibtonite
|
||||
holder_type = /obj/item/gibtonite
|
||||
holder_type = /obj/item/twohanded/required/gibtonite
|
||||
|
||||
/datum/wires/explosive/gibtonite/explode()
|
||||
var/obj/item/gibtonite/P = holder
|
||||
var/obj/item/twohanded/required/gibtonite/P = holder
|
||||
P.GibtoniteReaction(null, 2)
|
||||
@@ -74,25 +74,6 @@
|
||||
for(var/client/C in GLOB.clients)
|
||||
C.AnnouncePR(final_composed)
|
||||
|
||||
/datum/world_topic/auto_bunker_passthrough
|
||||
keyword = "auto_bunker_override"
|
||||
require_comms_key = TRUE
|
||||
|
||||
/datum/world_topic/auto_bunker_passthrough/Run(list/input)
|
||||
if(!CONFIG_GET(flag/allow_cross_server_bunker_override))
|
||||
return "Function Disabled"
|
||||
var/ckeytobypass = input["ckey"]
|
||||
var/is_new_ckey = !(ckey(ckeytobypass) in GLOB.bunker_passthrough)
|
||||
var/sender = input["source"] || "UNKNOWN"
|
||||
GLOB.bunker_passthrough |= ckey(ckeytobypass)
|
||||
GLOB.bunker_passthrough[ckey(ckeytobypass)] = world.realtime
|
||||
SSpersistence.SavePanicBunker() //we can do this every time, it's okay
|
||||
if(!is_new_ckey)
|
||||
log_admin("AUTO BUNKER: [ckeytobypass] given access (incoming comms from [sender]).")
|
||||
message_admins("AUTO BUNKER: [ckeytobypass] given access (incoming comms from [sender]).")
|
||||
send2irc("Panic Bunker", "AUTO BUNKER: [ckeytobypass] given access (incoming comms from [sender]).")
|
||||
return "Success"
|
||||
|
||||
/datum/world_topic/ahelp_relay
|
||||
keyword = "Ahelp"
|
||||
require_comms_key = TRUE
|
||||
|
||||
Reference in New Issue
Block a user