Merge branch 'master' into plumb

This commit is contained in:
lolman360
2020-08-09 22:48:18 +10:00
committed by GitHub
1405 changed files with 39348 additions and 21867 deletions
+6 -3
View File
@@ -2,7 +2,7 @@
var/speed = 80 //time in deciseconds taken to butcher something
var/effectiveness = 100 //percentage effectiveness; numbers above 100 yield extra drops
var/bonus_modifier = 0 //percentage increase to bonus item chance
var/butcher_sound = 'sound/weapons/slice.ogg' //sound played when butchering
var/butcher_sound = 'sound/effects/butcher.ogg' //sound played when butchering
var/butchering_enabled = TRUE
var/can_be_blunt = FALSE
@@ -64,8 +64,11 @@
H.visible_message("<span class='danger'>[user] slits [H]'s throat!</span>", \
"<span class='userdanger'>[user] slits your throat...</span>")
log_combat(user, H, "finishes slicing the throat of")
H.apply_damage(source.force, BRUTE, BODY_ZONE_HEAD)
H.bleed_rate = clamp(H.bleed_rate + 20, 0, 30)
H.apply_damage(source.force, BRUTE, BODY_ZONE_HEAD, wound_bonus=CANT_WOUND) // easy tiger, we'll get to that in a sec
var/obj/item/bodypart/slit_throat = H.get_bodypart(BODY_ZONE_HEAD)
if(slit_throat)
var/datum/wound/slash/critical/screaming_through_a_slit_throat = new
screaming_through_a_slit_throat.apply_wound(slit_throat)
H.apply_status_effect(/datum/status_effect/neck_slice)
/datum/component/butchering/proc/Butcher(mob/living/butcher, mob/living/meat)
+1 -1
View File
@@ -48,7 +48,7 @@
var/damage = rand(min_damage, max_damage)
if(HAS_TRAIT(H, TRAIT_LIGHT_STEP))
damage *= 0.75
H.apply_damage(damage, BRUTE, picked_def_zone)
H.apply_damage(damage, BRUTE, picked_def_zone, wound_bonus = CANT_WOUND)
if(cooldown < world.time - 10) //cooldown to avoid message spam.
if(!H.incapacitated(ignore_restraints = TRUE))
+11 -13
View File
@@ -203,9 +203,9 @@
Set var amt to the value current cycle req is pointing to, its amount of type we need to delete
Get var/surroundings list of things accessable to crafting by get_environment()
Check the type of the current cycle req
If its reagent then do a while loop, inside it try to locate() reagent containers, inside such containers try to locate needed reagent, if there isnt remove thing from surroundings
If its reagent then do a while loop, inside it try to locate() reagent containers, inside such containers try to locate needed reagent, if there isn't remove thing from surroundings
If there is enough reagent in the search result then delete the needed amount, create the same type of reagent with the same data var and put it into deletion list
If there isnt enough take all of that reagent from the container, put into deletion list, substract the amt var by the volume of reagent, remove the container from surroundings list and keep searching
If there isn't enough take all of that reagent from the container, put into deletion list, substract the amt var by the volume of reagent, remove the container from surroundings list and keep searching
While doing above stuff check deletion list if it already has such reagnet, if yes merge instead of adding second one
If its stack check if it has enough amount
If yes create new stack with the needed amount and put in into deletion list, substract taken amount from the stack
@@ -216,7 +216,7 @@
Then do a loop over parts var of the recipe
Do similar stuff to what we have done above, but now in deletion list, until the parts conditions are satisfied keep taking from the deletion list and putting it into parts list for return
After its done loop over deletion list and delete all the shit that wasnt taken by parts loop
After its done loop over deletion list and delete all the shit that wasn't taken by parts loop
del_reqs return the list of parts resulting object will receive as argument of CheckParts proc, on the atom level it will add them all to the contents, on all other levels it calls ..() and does whatever is needed afterwards but from contents list already
*/
@@ -323,9 +323,12 @@
if(user == parent)
ui_interact(user)
/datum/component/personal_crafting/ui_state(mob/user)
return GLOB.not_incapacitated_turf_state
//For the UI related things we're going to assume the user is a mob rather than typesetting it to an atom as the UI isn't generated if the parent is an atom
/datum/component/personal_crafting/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.not_incapacitated_turf_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
/datum/component/personal_crafting/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
cur_category = categories[1]
if(islist(categories[cur_category]))
@@ -333,7 +336,7 @@
cur_subcategory = subcats[1]
else
cur_subcategory = CAT_NONE
ui = new(user, src, ui_key, "PersonalCrafting", "Crafting Menu", 700, 800, master_ui, state)
ui = new(user, src, "PersonalCrafting")
ui.open()
/datum/component/personal_crafting/ui_data(mob/user)
@@ -413,13 +416,8 @@
display_compact = !display_compact
. = TRUE
if("set_category")
if(!isnull(params["category"]))
cur_category = params["category"]
if(!isnull(params["subcategory"]))
if(params["subcategory"] == "0")
cur_subcategory = ""
else
cur_subcategory = params["subcategory"]
cur_category = params["category"]
cur_subcategory = params["subcategory"] || ""
. = TRUE
/datum/component/personal_crafting/proc/build_recipe_data(datum/crafting_recipe/R)
@@ -263,6 +263,14 @@
time = 30
category = CAT_CLOTHING
/datum/crafting_recipe/durathread_reinforcement_kit
name = "Durathread Reinforcement Kit"
result = /obj/item/armorkit
reqs = list(/obj/item/stack/sheet/durathread = 4)
tools = list(/obj/item/stack/sheet/mineral/titanium, TOOL_WIRECUTTER) // tough needle for a tough fabric
time = 40
category = CAT_CLOTHING
/datum/crafting_recipe/durathread_duffelbag
name = "Durathread Dufflebag"
result = /obj/item/storage/backpack/duffelbag/durathread
@@ -324,6 +324,13 @@
result = /obj/item/toy/sword/cx
subcategory = CAT_MISCELLANEOUS
category = CAT_MISC
/datum/crafting_recipe/catgirlplushie
name = "Catgirl Plushie"
reqs = list(/obj/item/toy/plush/hairball = 3)
result = /obj/item/toy/plush/catgirl
subcategory = CAT_MISCELLANEOUS
category = CAT_MISC
////////////
//Unsorted//
+22 -15
View File
@@ -29,7 +29,6 @@
*/
/datum/component/embedded
dupe_mode = COMPONENT_DUPE_ALLOWED
var/obj/item/bodypart/limb
@@ -139,31 +138,37 @@
limb.embedded_objects |= weapon // on the inside... on the inside...
weapon.forceMove(victim)
RegisterSignal(weapon, list(COMSIG_MOVABLE_MOVED, COMSIG_PARENT_QDELETING), .proc/byeItemCarbon)
var/damage = 0
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)
damage = weapon.w_class * impact_pain_mult
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>")
if(damage > 0)
var/armor = victim.run_armor_check(limb.body_zone, "melee", "Your armor has protected your [limb.name].", "Your armor has softened a hit to your [limb.name].",weapon.armour_penetration)
limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage, blocked=armor, sharpness = weapon.get_sharpness())
/// 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
var/damage = weapon.w_class * pain_mult
var/pain_chance_current = jostle_chance
if(victim.m_intent == MOVE_INTENT_WALK || !(victim.mobility_flags & MOBILITY_STAND))
chance *= 0.5
pain_chance_current *= 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)
if(pain_stam_pct && IS_STAMCRIT(victim)) //if it's a less-lethal embed, give them a break if they're already stamcritted
pain_chance_current *= 0.2
damage *= 0.5
if(harmful && prob(pain_chance_current))
limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage, wound_bonus = CANT_WOUND)
to_chat(victim, "<span class='userdanger'>[weapon] embedded in your [limb.name] jostles and stings!</span>")
@@ -173,7 +178,7 @@
if(harmful)
var/damage = weapon.w_class * remove_pain_mult
limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage)
limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage, wound_bonus = CANT_WOUND)
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
@@ -199,7 +204,7 @@
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.
limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage, wound_bonus = CANT_WOUND) //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
@@ -276,14 +281,16 @@
damage *= 0.7
if(harmful && prob(chance))
limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage)
limb.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage, wound_bonus = CANT_WOUND)
to_chat(victim, "<span class='userdanger'>[weapon] embedded in your [limb.name] hurts!</span>")
if(prob(fall_chance))
var/fall_chance_current = fall_chance
if(victim.mobility_flags & ~MOBILITY_STAND)
fall_chance_current *= 0.2
if(prob(fall_chance_current))
fallOutCarbon()
////////////////////////////////////////
//////////////TURF PROCS////////////////
////////////////////////////////////////
+4 -8
View File
@@ -80,19 +80,15 @@ GLOBAL_LIST_EMPTY(GPS_list)
to_chat(user, "<span class='notice'>[parent] is now tracking, and visible to other GPS devices.</span>")
tracking = TRUE
/datum/component/gps/item/ui_interact(mob/user, ui_key = "gps", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state) // Remember to use the appropriate state.
/datum/component/gps/item/ui_interact(mob/user, datum/tgui/ui)
if(emped)
to_chat(user, "<span class='hear'>[parent] fizzles weakly.</span>")
return
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
// Variable window height, depending on how many GPS units there are
// to show, clamped to relatively safe range.
var/gps_window_height = clamp(325 + GLOB.GPS_list.len * 14, 325, 700)
ui = new(user, src, ui_key, "Gps", "Global Positioning System", 470, gps_window_height, master_ui, state) //width, height
ui = new(user, src, "Gps")
ui.open()
ui.set_autoupdate(state = updating)
ui.set_autoupdate(updating)
/datum/component/gps/item/ui_data(mob/user)
var/list/data = list()
+91
View File
@@ -0,0 +1,91 @@
/**
* KILLER QUEEN
*
* Simple contact bomb component
* Blows up the first person to touch it.
*/
/datum/component/killerqueen
can_transfer = TRUE
/// strength of explosion on the touch-er. 0 to disable. usually only used if the normal explosion is disabled (this is the default).
var/ex_strength = EXPLODE_HEAVY
/// callback to invoke with (parent, victim) before standard detonation - useful for losing a reference to this component or implementing custom behavior. return FALSE to prevent explosion.
var/datum/callback/pre_explode
/// callback to invoke with (parent) when deleting without an explosion
var/datum/callback/failure
/// did we explode
var/exploded = FALSE
/// examine message
var/examine_message
/// light explosion radius
var/light = 0
/// heavy explosion radius
var/heavy = 0
/// dev explosion radius
var/dev = 0
/// flame explosion radius
var/flame = 0
/// only triggered by living mobs
var/living_only = TRUE
/datum/component/killerqueen/Initialize(ex_strength = EXPLODE_HEAVY, datum/callback/pre_explode, datum/callback/failure, examine_message, light = 0, heavy = 0, dev = 0, flame = 0, living_only = TRUE)
. = ..()
if(. & COMPONENT_INCOMPATIBLE)
return
if(!isatom(parent))
return COMPONENT_INCOMPATIBLE
src.ex_strength = ex_strength
src.pre_explode = pre_explode
src.failure = failure
src.examine_message = examine_message
src.light = light
src.heavy = heavy
src.dev = dev
src.flame = flame
src.living_only = living_only
/datum/component/killerqueen/Destroy()
if(!exploded)
failure?.Invoke(parent)
return ..()
/datum/component/killerqueen/RegisterWithParent()
. = ..()
RegisterSignal(parent, list(COMSIG_ATOM_ATTACK_HAND, COMSIG_ATOM_ATTACK_PAW, COMSIG_ATOM_ATTACK_ANIMAL), .proc/touch_detonate)
RegisterSignal(parent, COMSIG_MOVABLE_BUMP, .proc/bump_detonate)
RegisterSignal(parent, COMSIG_PARENT_ATTACKBY, .proc/attackby_detonate)
RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/on_examine)
/datum/component/killerqueen/UnregisterFromParent()
. = ..()
UnregisterSignal(parent, list(COMSIG_ATOM_ATTACK_ANIMAL, COMSIG_ATOM_ATTACK_HAND, COMSIG_ATOM_ATTACK_PAW,
COMSIG_MOVABLE_BUMP, COMSIG_PARENT_ATTACKBY, COMSIG_PARENT_EXAMINE))
/datum/component/killerqueen/proc/attackby_detonate(datum/source, obj/item/I, mob/user)
detonate(user)
/datum/component/killerqueen/proc/bump_detonate(datum/source, atom/A)
detonate(A)
/datum/component/killerqueen/proc/touch_detonate(datum/source, mob/user)
detonate(user)
/datum/component/killerqueen/proc/on_examine(datum/source, mob/examiner, list/examine_return)
if(examine_message)
examine_return += examine_message
/datum/component/killerqueen/proc/detonate(atom/victim)
if(!isliving(victim) && living_only)
return
if(pre_explode && !pre_explode.Invoke(parent, victim))
return
if(ex_strength)
victim.ex_act(ex_strength)
if(light || heavy || dev || flame)
explosion(parent, dev, heavy, light, flame_range = flame)
else
var/turf/T = get_turf(parent)
playsound(T, 'sound/effects/explosion2.ogg', 200, 1)
new /obj/effect/temp_visual/explosion(T)
exploded = TRUE
qdel(src)
+20
View File
@@ -307,6 +307,10 @@
/datum/component/mood/proc/HandleNutrition(mob/living/L)
if(isethereal(L))
HandleCharge(L)
if(HAS_TRAIT(L, TRAIT_NOHUNGER))
return FALSE //no mood events for nutrition
switch(L.nutrition)
if(NUTRITION_LEVEL_FULL to INFINITY)
add_event(null, "nutrition", /datum/mood_event/fat)
@@ -321,6 +325,22 @@
if(0 to NUTRITION_LEVEL_STARVING)
add_event(null, "nutrition", /datum/mood_event/starving)
/datum/component/mood/proc/HandleCharge(mob/living/carbon/human/H)
var/datum/species/ethereal/E = H.dna.species
switch(E.get_charge(H))
if(ETHEREAL_CHARGE_NONE to ETHEREAL_CHARGE_LOWPOWER)
add_event(null, "charge", /datum/mood_event/decharged)
if(ETHEREAL_CHARGE_LOWPOWER to ETHEREAL_CHARGE_NORMAL)
add_event(null, "charge", /datum/mood_event/lowpower)
if(ETHEREAL_CHARGE_NORMAL to ETHEREAL_CHARGE_ALMOSTFULL)
clear_event(null, "charge")
if(ETHEREAL_CHARGE_ALMOSTFULL to ETHEREAL_CHARGE_FULL)
add_event(null, "charge", /datum/mood_event/charged)
if(ETHEREAL_CHARGE_FULL to ETHEREAL_CHARGE_OVERLOAD)
add_event(null, "charge", /datum/mood_event/overcharged)
if(ETHEREAL_CHARGE_OVERLOAD to ETHEREAL_CHARGE_DANGEROUS)
add_event(null, "charge", /datum/mood_event/supercharged)
/datum/component/mood/proc/update_beauty(area/A)
if(A.outdoors) //if we're outside, we don't care.
clear_event(null, "area_beauty")
+47 -8
View File
@@ -1,3 +1,8 @@
// the following defines are used for [/datum/component/pellet_cloud/var/list/wound_info_by_part] to store the damage, wound_bonus, and bw_bonus for each bodypart hit
#define CLOUD_POSITION_DAMAGE 1
#define CLOUD_POSITION_W_BONUS 2
#define CLOUD_POSITION_BW_BONUS 3
/*
* 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
@@ -29,7 +34,10 @@
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()]
/// Another associated list for hit bodyparts on carbons so we can track how much wounding potential we have for each bodypart
var/list/wound_info_by_part = 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
@@ -64,6 +72,7 @@
/datum/component/pellet_cloud/Destroy(force, silent)
purple_hearts = null
pellets = null
wound_info_by_part = null
targets_hit = null
bodies = null
return ..()
@@ -187,10 +196,26 @@
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)
/datum/component/pellet_cloud/proc/pellet_hit(obj/item/projectile/P, atom/movable/firer, atom/target, Angle, hit_zone)
pellets -= P
terminated++
hits++
var/obj/item/bodypart/hit_part
if(iscarbon(target) && hit_zone)
var/mob/living/carbon/hit_carbon = target
hit_part = hit_carbon.get_bodypart(hit_zone)
if(hit_part)
target = hit_part
if(P.wound_bonus != CANT_WOUND) // handle wounding
// unfortunately, due to how pellet clouds handle finalizing only after every pellet is accounted for, that also means there might be a short delay in dealing wounds if one pellet goes wide
// while buckshot may reach a target or miss it all in one tick, we also have to account for possible ricochets that may take a bit longer to hit the target
if(isnull(wound_info_by_part[hit_part]))
wound_info_by_part[hit_part] = list(0, 0, 0)
wound_info_by_part[hit_part][CLOUD_POSITION_DAMAGE] += P.damage // these account for decay
wound_info_by_part[hit_part][CLOUD_POSITION_W_BONUS] += P.wound_bonus
wound_info_by_part[hit_part][CLOUD_POSITION_BW_BONUS] += P.bare_wound_bonus
P.wound_bonus = CANT_WOUND // actual wounding will be handled aggregate
targets_hit[target]++
if(targets_hit[target] == 1)
RegisterSignal(target, COMSIG_PARENT_QDELETING, .proc/on_target_qdel, override=TRUE)
@@ -231,13 +256,23 @@
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>")
var/obj/item/bodypart/hit_part
if(isbodypart(target))
hit_part = target
target = hit_part.owner
var/damage_dealt = wound_info_by_part[hit_part][CLOUD_POSITION_DAMAGE]
var/w_bonus = wound_info_by_part[hit_part][CLOUD_POSITION_W_BONUS]
var/bw_bonus = wound_info_by_part[hit_part][CLOUD_POSITION_BW_BONUS]
var/wound_type = (initial(P.damage_type) == BRUTE) ? WOUND_BLUNT : WOUND_BURN // sharpness is handled in the wound rolling
wound_info_by_part[hit_part] = null
hit_part.painless_wound_roll(wound_type, damage_dealt, w_bonus, bw_bonus, initial(P.sharpness))
if(num_hits > 1)
target.visible_message("<span class='danger'>[target] is hit by [num_hits] [proj_name]s[hit_part ? " in the [hit_part.name]" : ""]!</span>", null, null, COMBAT_MESSAGE_RANGE, target)
to_chat(target, "<span class='userdanger'>You're hit by [num_hits] [proj_name]s[hit_part ? " in the [hit_part.name]" : ""]!</span>")
else
target.visible_message("<span class='danger'>[target] is hit by a [proj_name][hit_part ? " in the [hit_part.name]" : ""]!</span>", null, null, COMBAT_MESSAGE_RANGE, target)
to_chat(target, "<span class='userdanger'>You're hit by a [proj_name][hit_part ? " in the [hit_part.name]" : ""]!</span>")
UnregisterSignal(parent, COMSIG_PARENT_PREQDELETED)
if(queued_delete)
qdel(parent)
@@ -281,3 +316,7 @@
targets_hit -= target
bodies -= target
purple_hearts -= target
#undef CLOUD_POSITION_DAMAGE
#undef CLOUD_POSITION_W_BONUS
#undef CLOUD_POSITION_BW_BONUS
+15
View File
@@ -29,10 +29,18 @@
if(strength > RAD_MINIMUM_CONTAMINATION)
SSradiation.warn(src)
//Let's make er glow
//This relies on parent not being a turf or something. IF YOU CHANGE THAT, CHANGE THIS
var/atom/movable/master = parent
master.add_filter("rad_glow", 2, list("type" = "outline", "color" = "#39ff1430", "size" = 2))
addtimer(CALLBACK(src, .proc/glow_loop, master), rand(1,19))//Things should look uneven
START_PROCESSING(SSradiation, src)
/datum/component/radioactive/Destroy()
STOP_PROCESSING(SSradiation, src)
var/atom/movable/master = parent
master.remove_filter("rad_glow")
return ..()
/datum/component/radioactive/process()
@@ -46,6 +54,13 @@
if(strength <= RAD_BACKGROUND_RADIATION)
return PROCESS_KILL
/datum/component/radioactive/proc/glow_loop(atom/movable/master)
var/filter = master.get_filter("rad_glow")
if(filter)
animate(filter, alpha = 110, time = 15, loop = -1)
animate(alpha = 40, time = 25)
/datum/component/radioactive/InheritComponent(datum/component/C, i_am_original, _strength, _source, _half_life, _can_contaminate)
if(!i_am_original)
return
+4 -4
View File
@@ -98,16 +98,16 @@
/datum/component/simple_rotation/proc/HandRot(datum/source, mob/user, rotation = default_rotation_direction)
if(can_be_rotated)
if(!can_be_rotated.Invoke(user, default_rotation_direction))
if(!can_be_rotated.Invoke(user, rotation))
return
else
if(!default_can_be_rotated(user, default_rotation_direction))
if(!default_can_be_rotated(user, rotation))
return
if(can_user_rotate)
if(!can_user_rotate.Invoke(user, default_rotation_direction))
if(!can_user_rotate.Invoke(user, rotation))
return
else
if(!default_can_user_rotate(user, default_rotation_direction))
if(!default_can_user_rotate(user, rotation))
return
BaseRot(user, rotation)
return TRUE
+24 -3
View File
@@ -11,6 +11,13 @@
// This is to stop squeak spam from inhand usage
var/last_use = 0
var/use_delay = 20
// squeak cooldowns
var/last_squeak = 0
var/squeak_delay = 5
/// chance we'll be stopped from squeaking by cooldown when something crossing us squeaks
var/cross_squeak_delay_chance = 33 // about 3 things can squeak at a time
/datum/component/squeak/Initialize(custom_sounds, volume_override, chance_override, step_delay_override, use_delay_override)
if(!isatom(parent))
@@ -19,6 +26,7 @@
if(ismovable(parent))
RegisterSignal(parent, list(COMSIG_MOVABLE_BUMP, COMSIG_MOVABLE_IMPACT), .proc/play_squeak)
RegisterSignal(parent, list(COMSIG_MOVABLE_CROSSED, COMSIG_ITEM_WEARERCROSSED), .proc/play_squeak_crossed)
RegisterSignal(parent, COMSIG_CROSS_SQUEAKED, .proc/delay_squeak)
RegisterSignal(parent, COMSIG_MOVABLE_DISPOSING, .proc/disposing_react)
if(isitem(parent))
RegisterSignal(parent, list(COMSIG_ITEM_ATTACK, COMSIG_ITEM_ATTACK_OBJ, COMSIG_ITEM_HIT_REACT), .proc/play_squeak)
@@ -39,20 +47,28 @@
use_delay = use_delay_override
/datum/component/squeak/proc/play_squeak()
do_play_squeak()
/datum/component/squeak/proc/do_play_squeak(bypass_cooldown = FALSE)
if(!bypass_cooldown && ((last_squeak + squeak_delay) >= world.time))
return FALSE
if(prob(squeak_chance))
if(!override_squeak_sounds)
playsound(parent, pickweight(default_squeak_sounds), volume, 1, -1)
else
playsound(parent, pickweight(override_squeak_sounds), volume, 1, -1)
last_squeak = world.time
return TRUE
return FALSE
/datum/component/squeak/proc/step_squeak()
if(steps > step_delay)
play_squeak()
do_play_squeak(TRUE)
steps = 0
else
steps++
/datum/component/squeak/proc/play_squeak_crossed(atom/movable/AM)
/datum/component/squeak/proc/play_squeak_crossed(datum/source, atom/movable/AM)
if(isitem(AM))
var/obj/item/I = AM
if(I.item_flags & ABSTRACT)
@@ -63,13 +79,18 @@
return
var/atom/current_parent = parent
if(isturf(current_parent.loc))
play_squeak()
if(do_play_squeak())
SEND_SIGNAL(AM, COMSIG_CROSS_SQUEAKED)
/datum/component/squeak/proc/use_squeak()
if(last_use + use_delay < world.time)
last_use = world.time
play_squeak()
/datum/component/squeak/proc/delay_squeak()
if(prob(cross_squeak_delay_chance))
last_squeak = world.time
/datum/component/squeak/proc/on_equip(datum/source, mob/equipper, slot)
RegisterSignal(equipper, COMSIG_MOVABLE_DISPOSING, .proc/disposing_react, TRUE)
+1
View File
@@ -62,6 +62,7 @@
///Store the thrownthing datum for later use
/datum/component/tackler/proc/registerTackle(mob/living/carbon/user, datum/thrownthing/TT)
tackle = TT
tackle.thrower = user
///See if we can tackle or not. If we can, leap!
/datum/component/tackler/proc/checkTackle(mob/living/carbon/user, atom/A, params)
+2
View File
@@ -105,6 +105,8 @@
/// Triggered on attack self of the item containing the component
/datum/component/two_handed/proc/on_attack_self(datum/source, mob/user)
if(!user.is_holding(parent))
return //give no quarter to telekinesis powergaemrs (telekinetic wielding will desync the offhand and result in all sorts of bugs so no until someone codes it properly)
if(wielded)
unwield(user)
else
+25 -10
View File
@@ -102,6 +102,15 @@ GLOBAL_LIST_EMPTY(uplinks)
return //no hitting everyone/everything just to try to slot tcs in!
if(istype(I, /obj/item/stack/telecrystal))
LoadTC(user, I)
if(active)
if(I.GetComponent(/datum/component/uplink))
var/datum/component/uplink/hidden_uplink = I.GetComponent(/datum/component/uplink)
var/amt = hidden_uplink.telecrystals
hidden_uplink.telecrystals -= amt
src.telecrystals += amt
to_chat(user, "<span class='notice'>You connect the [I] to your uplink, siphoning [amt] telecrystals before quickly undoing the connection.")
else
return
for(var/category in uplink_items)
for(var/item in uplink_items[category])
var/datum/uplink_item/UI = uplink_items[category][item]
@@ -134,23 +143,19 @@ GLOBAL_LIST_EMPTY(uplinks)
// an unlocked uplink blocks also opening the PDA or headset menu
return COMPONENT_NO_INTERACT
/datum/component/uplink/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.inventory_state)
/datum/component/uplink/ui_state(mob/user)
return GLOB.inventory_state
/datum/component/uplink/ui_interact(mob/user, datum/tgui/ui)
active = TRUE
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, ui_key, "Uplink", name, 620, 580, master_ui, state)
ui = new(user, src, "Uplink", name)
// This UI is only ever opened by one person,
// and never is updated outside of user input.
ui.set_autoupdate(FALSE)
ui.open()
/datum/component/uplink/ui_host(mob/user)
if(istype(parent, /obj/item/implant)) //implants are like organs, not really located inside mobs codewise.
var/obj/item/implant/I = parent
return I.imp_in
return ..()
/datum/component/uplink/ui_data(mob/user)
if(!user.mind)
return
@@ -178,8 +183,18 @@ GLOBAL_LIST_EMPTY(uplinks)
is_inaccessible = FALSE
if(is_inaccessible)
continue
/*
if(I.restricted_species) //catpeople specfic gloves.
if(ishuman(user))
var/is_inaccessible = TRUE
var/mob/living/carbon/human/H = user
for(var/F in I.restricted_species)
if(F == H.dna.species.id || debug)
is_inaccessible = FALSE
break
if(is_inaccessible)
continue
*/
cat["items"] += list(list(
"name" = I.name,
"cost" = I.cost,