Merge branch 'master' into clockcultrework_v2
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
#define AB_CHECK_STUN 2
|
||||
#define AB_CHECK_LYING 4
|
||||
#define AB_CHECK_CONSCIOUS 8
|
||||
#define AB_CHECK_ALIVE 16
|
||||
|
||||
/datum/action
|
||||
var/name = "Generic Action"
|
||||
@@ -115,6 +116,9 @@
|
||||
if(check_flags & AB_CHECK_CONSCIOUS)
|
||||
if(owner.stat)
|
||||
return FALSE
|
||||
if(check_flags & AB_CHECK_ALIVE)
|
||||
if(owner.stat == DEAD)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/action/proc/UpdateButtonIcon(status_only = FALSE, force = FALSE)
|
||||
|
||||
@@ -263,4 +263,4 @@
|
||||
popleft(speak_dejavu) //Remove the oldest
|
||||
speak_dejavu += speech_args[SPEECH_MESSAGE]
|
||||
else
|
||||
speak_dejavu += speech_args[SPEECH_MESSAGE]
|
||||
speak_dejavu += speech_args[SPEECH_MESSAGE]
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# Datum Component System (DCS)
|
||||
|
||||
## Concept
|
||||
|
||||
Loosely adapted from /vg/. This is an entity component system for adding behaviours to datums when inheritance doesn't quite cut it. By using signals and events instead of direct inheritance, you can inject behaviours without hacky overloads. It requires a different method of thinking, but is not hard to use correctly. If a behaviour can have application across more than one thing. Make it generic, make it a component. Atom/mob/obj event? Give it a signal, and forward it's arguments with a `SendSignal()` call. Now every component that want's to can also know about this happening.
|
||||
|
||||
See [this thread](https://tgstation13.org/phpBB/viewtopic.php?f=5&t=22674) for an introduction to the system as a whole.
|
||||
|
||||
### See/Define signals and their arguments in [__DEFINES\components.dm](..\..\__DEFINES\components.dm)
|
||||
# Datum Component System (DCS)
|
||||
|
||||
## Concept
|
||||
|
||||
Loosely adapted from /vg/. This is an entity component system for adding behaviours to datums when inheritance doesn't quite cut it. By using signals and events instead of direct inheritance, you can inject behaviours without hacky overloads. It requires a different method of thinking, but is not hard to use correctly. If a behaviour can have application across more than one thing. Make it generic, make it a component. Atom/mob/obj event? Give it a signal, and forward it's arguments with a `SendSignal()` call. Now every component that want's to can also know about this happening.
|
||||
|
||||
See [this thread](https://tgstation13.org/phpBB/viewtopic.php?f=5&t=22674) for an introduction to the system as a whole.
|
||||
|
||||
### See/Define signals and their arguments in [__DEFINES\components.dm](..\..\__DEFINES\components.dm)
|
||||
|
||||
@@ -451,4 +451,4 @@
|
||||
if(istype(I, /obj/item/stack/sheet/glass))
|
||||
if(do_after(user,10, target = src))
|
||||
new next_step(user.loc, 1)
|
||||
qdel(src)
|
||||
qdel(src)
|
||||
|
||||
@@ -95,4 +95,4 @@
|
||||
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."
|
||||
icon = 'icons/obj/glass_ware.dmi'
|
||||
icon_state = "frames_2"
|
||||
icon_state = "frames_2"
|
||||
|
||||
@@ -172,11 +172,11 @@
|
||||
///////////////////
|
||||
|
||||
/datum/crafting_recipe/upgraded_gauze
|
||||
name = "Improved Gauze"
|
||||
name = "Sterilized Gauze"
|
||||
result = /obj/item/stack/medical/gauze/adv/one
|
||||
time = 1
|
||||
reqs = list(/obj/item/stack/medical/gauze = 1,
|
||||
/datum/reagent/space_cleaner/sterilizine = 10)
|
||||
/datum/reagent/space_cleaner/sterilizine = 5)
|
||||
category = CAT_MISC
|
||||
subcategory = CAT_TOOL
|
||||
|
||||
@@ -184,7 +184,7 @@
|
||||
name = "Suture Pack"
|
||||
result = /obj/item/stack/medical/suture/five
|
||||
time = 1
|
||||
reqs = list(/obj/item/stack/medical/gauze = 1,
|
||||
reqs = list(/obj/item/stack/medical/gauze/adv = 1,
|
||||
/datum/reagent/medicine/styptic_powder = 10)
|
||||
category = CAT_MISC
|
||||
subcategory = CAT_TOOL
|
||||
@@ -193,7 +193,7 @@
|
||||
name = "Regenerative Mesh"
|
||||
result = /obj/item/stack/medical/mesh/five
|
||||
time = 1
|
||||
reqs = list(/obj/item/stack/medical/gauze = 1,
|
||||
reqs = list(/obj/item/stack/medical/gauze/adv = 1,
|
||||
/datum/reagent/medicine/silver_sulfadiazine = 10)
|
||||
category = CAT_MISC
|
||||
subcategory = CAT_TOOL
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
/datum/crafting_recipe/floorbot
|
||||
name = "Floorbot"
|
||||
result = /mob/living/simple_animal/bot/floorbot
|
||||
reqs = list(/obj/item/storage/toolbox/mechanical = 1,
|
||||
reqs = list(/obj/item/storage/toolbox = 1,
|
||||
/obj/item/stack/tile/plasteel = 1,
|
||||
/obj/item/assembly/prox_sensor = 1,
|
||||
/obj/item/bodypart/r_arm/robot = 1)
|
||||
@@ -95,4 +95,4 @@
|
||||
reqs = list(/obj/item/aicard = 1,
|
||||
/obj/item/reagent_containers/food/snacks/grown/pumpkin = 1,
|
||||
/obj/item/stack/cable_coil = 5)
|
||||
category = CAT_ROBOT
|
||||
category = CAT_ROBOT
|
||||
|
||||
@@ -72,6 +72,52 @@
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_MELEE
|
||||
|
||||
/datum/crafting_recipe/bokken
|
||||
name = "Training Bokken"
|
||||
result = /obj/item/melee/bokken
|
||||
tools = list(TOOL_SCREWDRIVER)
|
||||
reqs = list(/obj/item/bokken_blade = 1,
|
||||
/obj/item/bokken_hilt = 1,
|
||||
/obj/item/stack/sheet/cloth = 2,
|
||||
/obj/item/stack/sheet/leather = 1)
|
||||
time = 60
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_MELEE
|
||||
|
||||
/datum/crafting_recipe/bokken_steelwood
|
||||
name = "Training Steelwood Bokken"
|
||||
result = /obj/item/melee/bokken/steelwood
|
||||
tools = list(TOOL_SCREWDRIVER)
|
||||
reqs = list(/obj/item/bokken_steelblade = 1,
|
||||
/obj/item/bokken_hilt = 1,
|
||||
/obj/item/stack/sheet/cloth = 2,
|
||||
/obj/item/stack/sheet/leather = 1)
|
||||
time = 60
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_MELEE
|
||||
|
||||
/datum/crafting_recipe/wakibokken
|
||||
name = "Training Wakizashi Bokken"
|
||||
result = /obj/item/melee/bokken/waki
|
||||
tools = list(TOOL_SCREWDRIVER)
|
||||
reqs = list(/obj/item/wakibokken_blade = 1,
|
||||
/obj/item/bokken_hilt = 1,
|
||||
/obj/item/stack/sheet/cloth = 1)
|
||||
time = 40
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_MELEE
|
||||
|
||||
/datum/crafting_recipe/wakibokken_steelwood
|
||||
name = "Training Wakizashi Steelwood Bokken"
|
||||
result = /obj/item/melee/bokken/waki/steelwood
|
||||
tools = list(TOOL_SCREWDRIVER)
|
||||
reqs = list(/obj/item/wakibokken_steelblade = 1,
|
||||
/obj/item/bokken_hilt = 1,
|
||||
/obj/item/stack/sheet/cloth = 1)
|
||||
time = 40
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_MELEE
|
||||
|
||||
/datum/crafting_recipe/bola
|
||||
name = "Bola"
|
||||
result = /obj/item/restraints/legcuffs/bola
|
||||
@@ -248,7 +294,7 @@
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_WEAPON
|
||||
|
||||
/datum/crafting_recipe/ishotgun
|
||||
/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
|
||||
@@ -434,3 +480,51 @@
|
||||
time = 20
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
// BOKKEN CRAFTING
|
||||
|
||||
/datum/crafting_recipe/bokken_blade
|
||||
name = "Training Bokken Blade"
|
||||
result = /obj/item/bokken_blade
|
||||
tools = list(/obj/item/hatchet)
|
||||
reqs = list(/obj/item/stack/sheet/mineral/wood = 5)
|
||||
time = 20
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
/datum/crafting_recipe/wakibokken_blade
|
||||
name = "Training Wakizashi Bokken Blade"
|
||||
result = /obj/item/wakibokken_blade
|
||||
tools = list(/obj/item/hatchet)
|
||||
reqs = list(/obj/item/stack/sheet/mineral/wood = 2)
|
||||
time = 20
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
/datum/crafting_recipe/bokken_steelblade
|
||||
name = "Training Ironwood Bokken Blade"
|
||||
result = /obj/item/bokken_steelblade
|
||||
tools = list(/obj/item/hatchet, TOOL_WELDER)
|
||||
reqs = list(/obj/item/grown/log/steel = 2)
|
||||
time = 20
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
/datum/crafting_recipe/wakibokken_steelblade
|
||||
name = "Training Wakizashi Ironwood Bokken Blade"
|
||||
result = /obj/item/wakibokken_steelblade
|
||||
tools = list(/obj/item/hatchet, TOOL_WELDER)
|
||||
reqs = list(/obj/item/grown/log/steel = 1)
|
||||
time = 20
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
/datum/crafting_recipe/bokken_hilt
|
||||
name = "Training Bokken hilt"
|
||||
result = /obj/item/bokken_hilt
|
||||
tools = list(/obj/item/hatchet)
|
||||
reqs = list(/obj/item/stack/sheet/mineral/wood = 5,
|
||||
/obj/item/stack/sheet/cloth = 2)
|
||||
time = 20
|
||||
category = CAT_WEAPONRY
|
||||
subcategory = CAT_PARTS
|
||||
|
||||
@@ -67,4 +67,4 @@
|
||||
/datum/fantasy_affix/vampiric/apply(datum/component/fantasy/comp, newName)
|
||||
var/obj/item/master = comp.parent
|
||||
comp.appliedComponents += master.AddComponent(/datum/component/lifesteal, comp.quality)
|
||||
return "vampiric [newName]"
|
||||
return "vampiric [newName]"
|
||||
|
||||
@@ -36,4 +36,4 @@
|
||||
if(isliving(target))
|
||||
var/mob/living/L = target
|
||||
L.adjust_fire_stacks(fire_stacks)
|
||||
L.IgniteMob()
|
||||
L.IgniteMob()
|
||||
|
||||
@@ -41,4 +41,4 @@
|
||||
RegisterSignal(H, COMSIG_HUMAN_DISARM_HIT, .proc/Knockoff, TRUE)
|
||||
|
||||
/datum/component/knockoff/proc/OnDropped(datum/source, mob/living/M)
|
||||
UnregisterSignal(M, COMSIG_HUMAN_DISARM_HIT)
|
||||
UnregisterSignal(M, COMSIG_HUMAN_DISARM_HIT)
|
||||
|
||||
@@ -31,4 +31,4 @@
|
||||
UnregisterSignal(thing, COMSIG_MOVABLE_PRE_THROW)
|
||||
|
||||
/datum/component/magnetic_catch/proc/throw_react(datum/source, list/arguments)
|
||||
return COMPONENT_CANCEL_THROW
|
||||
return COMPONENT_CANCEL_THROW
|
||||
|
||||
@@ -17,6 +17,44 @@
|
||||
var/stealth = FALSE //if TRUE, does not appear on HUDs and health scans
|
||||
var/diagnostics = TRUE //if TRUE, displays program list when scanned by nanite scanners
|
||||
|
||||
/// Delete ourselves when we're depleted.
|
||||
var/qdel_self_on_depletion = TRUE
|
||||
/// Allow deletion
|
||||
var/can_be_deleted = TRUE
|
||||
/// Whether or not we can survive no cloud syncing without errors
|
||||
var/requires_cloud_sync = TRUE
|
||||
/// Permanent programs - can never be deleted. does not count towards max_programs.
|
||||
var/list/datum/nanite_program/permanent_programs = list()
|
||||
|
||||
// Vulnerabilities
|
||||
/// EMP flat deletion upper
|
||||
var/emp_flat_deletion_upper = 35
|
||||
/// EMP flat deletion lower
|
||||
var/emp_flat_deletion_lower = 20
|
||||
/// EMP percent deletion upper
|
||||
var/emp_percent_deletion_upper = 0.35
|
||||
/// EMP percent deletion lower
|
||||
var/emp_percent_deletion_lower = 0.30
|
||||
/// EMP severity multiplier, capping to 0 to 100
|
||||
var/emp_severity_mod = 1
|
||||
/// EMP severity div for cloudsync reset chance
|
||||
var/emp_desync_mod = 0.25
|
||||
|
||||
/// Shock flat deletion upper
|
||||
var/shock_flat_deletion_upper = 45
|
||||
/// Shock flat deletion lower
|
||||
var/shock_flat_deletion_lower = 25
|
||||
/// Shock percent deletion upper
|
||||
var/shock_percent_deletion_upper = 0.25
|
||||
/// Shock percent deletion lower
|
||||
var/shock_percent_deletion_lower = 0.20
|
||||
|
||||
|
||||
/// minor shock deletion lower
|
||||
var/minor_shock_deletion_lower = 5
|
||||
/// minor shock deletion upper
|
||||
var/minor_shock_deletion_upper = 15
|
||||
|
||||
/datum/component/nanites/Initialize(amount = 100, cloud = 0)
|
||||
if(!isliving(parent) && !istype(parent, /datum/nanite_cloud_backup))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
@@ -55,6 +93,9 @@
|
||||
RegisterSignal(parent, COMSIG_NANITE_ADD_PROGRAM, .proc/add_program)
|
||||
RegisterSignal(parent, COMSIG_NANITE_SCAN, .proc/nanite_scan)
|
||||
RegisterSignal(parent, COMSIG_NANITE_SYNC, .proc/sync)
|
||||
RegisterSignal(parent, COMSIG_NANITE_CHECK_CONSOLE_LOCK, .proc/check_console_locking)
|
||||
RegisterSignal(parent, COMSIG_NANITE_CHECK_HOST_LOCK, .proc/check_host_lockout)
|
||||
RegisterSignal(parent, COMSIG_NANITE_CHECK_VIRAL_PREVENTION, .proc/check_viral_prevention)
|
||||
|
||||
if(isliving(parent))
|
||||
RegisterSignal(parent, COMSIG_ATOM_EMP_ACT, .proc/on_emp)
|
||||
@@ -118,13 +159,63 @@
|
||||
next_sync = world.time + NANITE_SYNC_DELAY
|
||||
set_nanite_bar()
|
||||
|
||||
/**
|
||||
* Called when nanites are depleted.
|
||||
* Deletes ourselves by default.
|
||||
*/
|
||||
/datum/component/nanites/proc/nanites_depleted()
|
||||
if(qdel_self_on_depletion)
|
||||
delete_nanites()
|
||||
|
||||
/**
|
||||
* Used to rid ourselves
|
||||
*/
|
||||
/datum/component/nanites/proc/delete_nanites()
|
||||
qdel(src)
|
||||
if(can_be_deleted)
|
||||
qdel(src)
|
||||
|
||||
/**
|
||||
* Adds permanent programs
|
||||
*
|
||||
* WARNING: Has no sanity checks. Make sure you know what you are doing! (make sure programs do not conflict)
|
||||
*/
|
||||
/datum/component/nanites/proc/add_permanent_program(list/program, immutable = FALSE)
|
||||
if(!islist(program))
|
||||
program = list(program)
|
||||
for(var/i in program)
|
||||
if(i in permanent_programs)
|
||||
continue
|
||||
var/datum/nanite_program/P = i
|
||||
permanent_programs += P
|
||||
if(immutable)
|
||||
P.immutable = TRUE
|
||||
for(var/e in programs)
|
||||
var/datum/nanite_program/E = e
|
||||
if(E.unique && (E.type == P.type))
|
||||
qdel(e)
|
||||
programs += P
|
||||
|
||||
/**
|
||||
* Checks if we can block out console modification
|
||||
*/
|
||||
/datum/component/nanites/proc/check_console_locking()
|
||||
return SEND_SIGNAL(src, COMSIG_NANITE_INTERNAL_CONSOLE_LOCK_CHECK)
|
||||
|
||||
/**
|
||||
* Checks if we can lock out host internal conscious modification
|
||||
*/
|
||||
/datum/component/nanites/proc/check_host_lockout()
|
||||
return SEND_SIGNAL(src, COMSIG_NANITE_INTERNAL_HOST_LOCK_CHECK)
|
||||
|
||||
/**
|
||||
* Checks if we can block out viral replica
|
||||
*/
|
||||
/datum/component/nanites/proc/check_viral_prevention()
|
||||
return SEND_SIGNAL(src, COMSIG_NANITE_INTERNAL_VIRAL_PREVENTION_CHECK)
|
||||
|
||||
//Syncs the nanite component to another, making it so programs are the same with the same programming (except activation status)
|
||||
/datum/component/nanites/proc/sync(datum/signal_source, datum/component/nanites/source, full_overwrite = TRUE, copy_activation = FALSE)
|
||||
var/list/programs_to_remove = programs.Copy()
|
||||
var/list/programs_to_remove = programs.Copy() - permanent_programs
|
||||
var/list/programs_to_add = source.programs.Copy()
|
||||
for(var/X in programs)
|
||||
var/datum/nanite_program/NP = X
|
||||
@@ -151,7 +242,7 @@
|
||||
sync(null, cloud_copy)
|
||||
return
|
||||
//Without cloud syncing nanites can accumulate errors and/or defects
|
||||
if(prob(8) && programs.len)
|
||||
if(prob(8) && programs.len && requires_cloud_sync)
|
||||
var/datum/nanite_program/NP = pick(programs)
|
||||
NP.software_error()
|
||||
|
||||
@@ -159,8 +250,11 @@
|
||||
for(var/X in programs)
|
||||
var/datum/nanite_program/NP = X
|
||||
if(NP.unique && NP.type == new_program.type)
|
||||
qdel(NP)
|
||||
if(programs.len >= max_programs)
|
||||
if(NP in permanent_programs)
|
||||
return COMPONENT_PROGRAM_NOT_INSTALLED
|
||||
else
|
||||
qdel(NP)
|
||||
if((programs.len - length(permanent_programs)) >= max_programs)
|
||||
return COMPONENT_PROGRAM_NOT_INSTALLED
|
||||
if(source_program)
|
||||
source_program.copy_programming(new_program)
|
||||
@@ -177,7 +271,7 @@
|
||||
/datum/component/nanites/proc/adjust_nanites(datum/source, amount)
|
||||
nanite_volume = clamp(nanite_volume + amount, 0, max_nanites)
|
||||
if(nanite_volume <= 0) //oops we ran out
|
||||
qdel(src)
|
||||
nanites_depleted()
|
||||
|
||||
/datum/component/nanites/proc/set_nanite_bar(remove = FALSE)
|
||||
var/image/holder = host_mob.hud_list[DIAG_NANITE_FULL_HUD]
|
||||
@@ -191,28 +285,28 @@
|
||||
holder.icon_state = "nanites[nanite_percent]"
|
||||
|
||||
/datum/component/nanites/proc/on_emp(datum/source, severity)
|
||||
nanite_volume *= (rand(60, 90) * 0.01) //Lose 10-40% of nanites
|
||||
adjust_nanites(null, -(rand(5, 50))) //Lose 5-50 flat nanite volume
|
||||
if(prob(40/severity))
|
||||
severity *= emp_severity_mod
|
||||
var/loss = (severity / 100) * (rand(emp_percent_deletion_lower, emp_percent_deletion_upper) * nanite_volume) + rand(emp_flat_deletion_lower, emp_flat_deletion_upper)
|
||||
adjust_nanites(null, -loss)
|
||||
if(prob(severity * emp_desync_mod))
|
||||
cloud_id = 0
|
||||
for(var/X in programs)
|
||||
var/datum/nanite_program/NP = X
|
||||
NP.on_emp(severity)
|
||||
|
||||
|
||||
/datum/component/nanites/proc/on_shock(datum/source, shock_damage, siemens_coeff = 1, flags = NONE)
|
||||
if(shock_damage < 1)
|
||||
return
|
||||
|
||||
if(!HAS_TRAIT_NOT_FROM(host_mob, TRAIT_SHOCKIMMUNE, "nanites"))//Another shock protection must protect nanites too, but nanites protect only host
|
||||
nanite_volume *= (rand(45, 80) * 0.01) //Lose 20-55% of nanites
|
||||
adjust_nanites(null, -(rand(5, 50))) //Lose 5-50 flat nanite volume
|
||||
var/loss = (rand(shock_percent_deletion_lower, shock_percent_deletion_upper) * nanite_volume) + rand(shock_flat_deletion_lower, shock_flat_deletion_upper)
|
||||
adjust_nanites(null, -loss)
|
||||
for(var/X in programs)
|
||||
var/datum/nanite_program/NP = X
|
||||
NP.on_shock(shock_damage)
|
||||
|
||||
/datum/component/nanites/proc/on_minor_shock(datum/source)
|
||||
adjust_nanites(null, -(rand(5, 15))) //Lose 5-15 flat nanite volume
|
||||
adjust_nanites(null, -(rand(minor_shock_deletion_lower, minor_shock_deletion_upper))) //Lose 5-15 flat nanite volume
|
||||
for(var/X in programs)
|
||||
var/datum/nanite_program/NP = X
|
||||
NP.on_minor_shock()
|
||||
@@ -237,7 +331,7 @@
|
||||
NP.receive_comm_signal(comm_code, comm_message, comm_source)
|
||||
|
||||
/datum/component/nanites/proc/check_viable_biotype()
|
||||
if(!(host_mob.mob_biotypes & (MOB_ORGANIC|MOB_UNDEAD)))
|
||||
if(!(host_mob.mob_biotypes & (MOB_ORGANIC|MOB_UNDEAD|MOB_NANITES)))
|
||||
qdel(src) //bodytype no longer sustains nanites
|
||||
|
||||
/datum/component/nanites/proc/check_access(datum/source, obj/O)
|
||||
@@ -378,3 +472,10 @@
|
||||
id++
|
||||
mob_programs += list(mob_program)
|
||||
data["mob_programs"] = mob_programs
|
||||
|
||||
/**
|
||||
* Subtype that doesn't erase itself from running out
|
||||
*/
|
||||
/datum/component/nanites/permanent
|
||||
qdel_self_on_depletion = FALSE
|
||||
can_be_deleted = FALSE
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
move_react()
|
||||
|
||||
/datum/component/orbiter/proc/begin_orbit(atom/movable/orbiter, radius, clockwise, rotation_speed, rotation_segments, pre_rotation)
|
||||
SEND_SIGNAL(parent, COMSIG_ATOM_ORBIT_BEGIN, orbiter, radius, clockwise, rotation_speed, rotation_segments, pre_rotation)
|
||||
if(orbiter.orbiting)
|
||||
if(orbiter.orbiting == src)
|
||||
orbiter.orbiting.end_orbit(orbiter, TRUE)
|
||||
@@ -87,6 +88,7 @@
|
||||
/datum/component/orbiter/proc/end_orbit(atom/movable/orbiter, refreshing=FALSE)
|
||||
if(!orbiters[orbiter])
|
||||
return
|
||||
SEND_SIGNAL(parent, COMSIG_ATOM_ORBIT_END, orbiter, refreshing)
|
||||
UnregisterSignal(orbiter, COMSIG_MOVABLE_MOVED)
|
||||
orbiter.SpinAnimation(0, 0)
|
||||
if(istype(orbiters[orbiter],/matrix)) //This is ugly.
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
var/mob/living/shooter
|
||||
|
||||
/datum/component/pellet_cloud/Initialize(projectile_type=/obj/item/shrapnel, magnitude=5)
|
||||
if(!isammocasing(parent) && !isgrenade(parent) && !islandmine(parent))
|
||||
if(!isammocasing(parent) && !isgrenade(parent) && !islandmine(parent) && !issupplypod(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
if(magnitude < 1)
|
||||
@@ -66,7 +66,7 @@
|
||||
|
||||
if(isammocasing(parent))
|
||||
num_pellets = magnitude
|
||||
else if(isgrenade(parent) || islandmine(parent))
|
||||
else if(isgrenade(parent) || islandmine(parent) || issupplypod(parent))
|
||||
radius = magnitude
|
||||
|
||||
/datum/component/pellet_cloud/Destroy(force, silent)
|
||||
@@ -86,9 +86,11 @@
|
||||
RegisterSignal(parent, COMSIG_GRENADE_PRIME, .proc/create_blast_pellets)
|
||||
else if(islandmine(parent))
|
||||
RegisterSignal(parent, COMSIG_MINE_TRIGGERED, .proc/create_blast_pellets)
|
||||
else if(issupplypod(parent))
|
||||
RegisterSignal(parent, COMSIG_SUPPLYPOD_LANDED, .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))
|
||||
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, COMSIG_SUPPLYPOD_LANDED))
|
||||
|
||||
/**
|
||||
* create_casing_pellets() is for directed pellet clouds for ammo casings that have multiple pellets (buckshot and scatter lasers for instance)
|
||||
|
||||
@@ -133,7 +133,7 @@
|
||||
|
||||
//KEYS
|
||||
/datum/component/riding/proc/keycheck(mob/user)
|
||||
return !keytype || user.is_holding_item_of_type(keytype)
|
||||
return !keytype || user?.is_holding_item_of_type(keytype)
|
||||
|
||||
//BUCKLE HOOKS
|
||||
/datum/component/riding/proc/restore_position(mob/living/buckled_mob)
|
||||
@@ -153,7 +153,7 @@
|
||||
|
||||
/datum/component/riding/proc/handle_ride(mob/user, direction)
|
||||
var/atom/movable/AM = parent
|
||||
if(user.incapacitated())
|
||||
if(user && user.incapacitated())
|
||||
Unbuckle(user)
|
||||
return
|
||||
if(world.time < last_vehicle_move + ((last_move_diagonal? 2 : 1) * vehicle_move_delay))
|
||||
|
||||
@@ -39,4 +39,4 @@
|
||||
if(ishuman(L))
|
||||
var/mob/living/carbon/human/H = L
|
||||
H.physiology.damage_resistance += 100
|
||||
..()
|
||||
..()
|
||||
|
||||
@@ -22,4 +22,4 @@
|
||||
grill_marks.Blend(icon('icons/obj/kitchen.dmi', "grillmarks"), ICON_MULTIPLY) //adds grill marks and the remaining white areas become transparent
|
||||
sizzling = new(grill_marks)
|
||||
sizzling.alpha = sizzlealpha
|
||||
food.add_overlay(sizzling)
|
||||
food.add_overlay(sizzling)
|
||||
|
||||
@@ -53,4 +53,4 @@
|
||||
spawned_mobs += L
|
||||
L.nest = src
|
||||
L.faction = src.faction
|
||||
P.visible_message("<span class='danger'>[L] [spawn_text] [P].</span>")
|
||||
P.visible_message("<span class='danger'>[L] [spawn_text] [P].</span>")
|
||||
|
||||
@@ -16,6 +16,32 @@
|
||||
to_chat(M, "<span class='warning'>[parent] only accepts machine parts!</span>")
|
||||
return FALSE
|
||||
|
||||
/datum/component/storage/concrete/rped/quick_empty(mob/M)
|
||||
var/atom/A = parent
|
||||
if(!M.canUseStorage() || !A.Adjacent(M) || M.incapacitated())
|
||||
return
|
||||
if(check_locked(null, M, TRUE))
|
||||
return FALSE
|
||||
A.add_fingerprint(M)
|
||||
var/list/things = contents()
|
||||
var/lowest_rating = INFINITY
|
||||
for(var/obj/item/B in things)
|
||||
if(B.get_part_rating() < lowest_rating)
|
||||
lowest_rating = B.get_part_rating()
|
||||
for(var/obj/item/B in things)
|
||||
if(B.get_part_rating() > lowest_rating)
|
||||
things.Remove(B)
|
||||
if(lowest_rating == INFINITY)
|
||||
to_chat(M, "<span class='notice'>There's no parts to dump out from [parent].</span>")
|
||||
return
|
||||
to_chat(M, "<span class='notice'>You start dumping out tier/cell rating [lowest_rating] parts from [parent].</span>")
|
||||
var/turf/T = get_turf(A)
|
||||
var/datum/progressbar/progress = new(M, length(things), T)
|
||||
while (do_after(M, 10, TRUE, T, FALSE, CALLBACK(src, .proc/mass_remove_from_storage, T, things, progress)))
|
||||
stoplag(1)
|
||||
qdel(progress)
|
||||
A.do_squish(0.8, 1.2)
|
||||
|
||||
/datum/component/storage/concrete/bluespace/rped
|
||||
collection_mode = COLLECT_EVERYTHING
|
||||
allow_quick_gather = TRUE
|
||||
@@ -33,5 +59,29 @@
|
||||
to_chat(M, "<span class='warning'>[parent] only accepts machine parts!</span>")
|
||||
return FALSE
|
||||
|
||||
/datum/component/storage/concrete/cyborg/rped
|
||||
max_items = 150
|
||||
|
||||
/datum/component/storage/concrete/bluespace/rped/quick_empty(mob/M)
|
||||
var/atom/A = parent
|
||||
if(!M.canUseStorage() || !A.Adjacent(M) || M.incapacitated())
|
||||
return
|
||||
if(check_locked(null, M, TRUE))
|
||||
return FALSE
|
||||
A.add_fingerprint(M)
|
||||
var/list/things = contents()
|
||||
var/lowest_rating = INFINITY
|
||||
for(var/obj/item/B in things)
|
||||
if(B.get_part_rating() < lowest_rating)
|
||||
lowest_rating = B.get_part_rating()
|
||||
for(var/obj/item/B in things)
|
||||
if(B.get_part_rating() > lowest_rating)
|
||||
things.Remove(B)
|
||||
if(lowest_rating == INFINITY)
|
||||
to_chat(M, "<span class='notice'>There's no parts to dump out from [parent].</span>")
|
||||
return
|
||||
to_chat(M, "<span class='notice'>You start dumping out tier/cell rating [lowest_rating] parts from [parent].</span>")
|
||||
var/turf/T = get_turf(A)
|
||||
var/datum/progressbar/progress = new(M, length(things), T)
|
||||
while (do_after(M, 10, TRUE, T, FALSE, CALLBACK(src, .proc/mass_remove_from_storage, T, things, progress)))
|
||||
stoplag(1)
|
||||
qdel(progress)
|
||||
A.do_squish(0.8, 1.2)
|
||||
|
||||
@@ -68,4 +68,4 @@
|
||||
spawn_location.visible_message("<span class='danger'>[L] [spawn_text].</span>")
|
||||
|
||||
/datum/component/summoning/proc/on_spawned_death(mob/killed, gibbed)
|
||||
spawned_mobs -= killed
|
||||
spawned_mobs -= killed
|
||||
|
||||
@@ -52,4 +52,4 @@
|
||||
var/atom/movable/owner = parent
|
||||
if(is_swarming)
|
||||
animate(owner, pixel_x = owner.pixel_x - offset_x, pixel_y = owner.pixel_y - offset_y, time = 2)
|
||||
is_swarming = FALSE
|
||||
is_swarming = FALSE
|
||||
|
||||
@@ -89,6 +89,11 @@
|
||||
to_chat(user, "<span class='warning'>You can't tackle while tased!</span>")
|
||||
return
|
||||
|
||||
var/left_paralysis = HAS_TRAIT(user, TRAIT_PARALYSIS_L_ARM)
|
||||
var/right_paralysis = HAS_TRAIT(user, TRAIT_PARALYSIS_R_ARM)
|
||||
if(left_paralysis && right_paralysis)
|
||||
to_chat(user, "<span class='warning'>You can't tackle without the use of your arms!</span>")
|
||||
|
||||
user.face_atom(A)
|
||||
|
||||
var/list/modifiers = params2list(params)
|
||||
@@ -280,6 +285,10 @@
|
||||
attack_mod -= 2
|
||||
if(HAS_TRAIT(sacker, TRAIT_GIANT))
|
||||
attack_mod += 2
|
||||
var/left_paralysis = HAS_TRAIT(sacker, TRAIT_PARALYSIS_L_ARM)
|
||||
var/right_paralysis = HAS_TRAIT(sacker, TRAIT_PARALYSIS_R_ARM)
|
||||
if(left_paralysis || right_paralysis)
|
||||
attack_mod -= 2
|
||||
|
||||
if(ishuman(target))
|
||||
var/mob/living/carbon/human/S = sacker
|
||||
|
||||
@@ -78,4 +78,4 @@
|
||||
|
||||
/datum/component/thermite/proc/attackby_react(datum/source, obj/item/thing, mob/user, params)
|
||||
if(thing.get_temperature())
|
||||
thermite_melt(user)
|
||||
thermite_melt(user)
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
* Observers voting on things through orbiting
|
||||
*/
|
||||
/datum/component/twitch_plays
|
||||
/// Observers
|
||||
var/list/mob/players = list()
|
||||
|
||||
/datum/component/twitch_plays/Initialize(...)
|
||||
. = ..()
|
||||
if(!isatom(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
RegisterSignal(parent, COMSIG_ATOM_ORBIT_BEGIN, .proc/on_start_orbit)
|
||||
RegisterSignal(parent, COMSIG_ATOM_ORBIT_END, .proc/on_end_orbit)
|
||||
|
||||
/datum/component/twitch_plays/Destroy(force, silent)
|
||||
for(var/i in players)
|
||||
DetachPlayer(i)
|
||||
return ..()
|
||||
|
||||
/datum/component/twitch_plays/proc/on_start_orbit(datum/source, atom/movable/orbiter)
|
||||
if(!isobserver(orbiter))
|
||||
return
|
||||
AttachPlayer(orbiter)
|
||||
|
||||
/datum/component/twitch_plays/proc/on_end_orbit(datum/source, atom/movable/orbiter)
|
||||
if(!(orbiter in players))
|
||||
return
|
||||
DetachPlayer(orbiter)
|
||||
|
||||
/datum/component/twitch_plays/proc/AttachPlayer(mob/dead/observer)
|
||||
players |= observer
|
||||
RegisterSignal(observer, COMSIG_PARENT_QDELETING, .proc/on_end_orbit)
|
||||
|
||||
/datum/component/twitch_plays/proc/DetachPlayer(mob/dead/observer)
|
||||
players -= observer
|
||||
UnregisterSignal(observer, COMSIG_PARENT_QDELETING)
|
||||
|
||||
/// Simple movement one
|
||||
/datum/component/twitch_plays/simple_movement
|
||||
/// Movement votes by observer
|
||||
var/list/votes = list()
|
||||
/// Allow diagonals
|
||||
var/allow_diagonal = FALSE
|
||||
|
||||
/datum/component/twitch_plays/simple_movement/Initialize(...)
|
||||
. = ..()
|
||||
if(. & COMPONENT_INCOMPATIBLE)
|
||||
return
|
||||
RegisterSignal(parent, COMSIG_TWITCH_PLAYS_MOVEMENT_DATA, .proc/fetch_data)
|
||||
|
||||
/datum/component/twitch_plays/simple_movement/AttachPlayer(mob/dead/observer)
|
||||
. = ..()
|
||||
RegisterSignal(observer, COMSIG_MOVABLE_PRE_MOVE, .proc/pre_move)
|
||||
|
||||
/datum/component/twitch_plays/simple_movement/DetachPlayer(mob/dead/observer)
|
||||
. = ..()
|
||||
UnregisterSignal(observer, COMSIG_MOVABLE_PRE_MOVE)
|
||||
|
||||
/datum/component/twitch_plays/simple_movement/proc/pre_move(datum/source, turf/newLoc)
|
||||
if(get_dist(newLoc, parent) > 1) // they're trying to escape orbit
|
||||
return
|
||||
. = COMPONENT_MOVABLE_BLOCK_PRE_MOVE
|
||||
var/dir = get_dir(parent, newLoc)
|
||||
if(!dir)
|
||||
return
|
||||
if(allow_diagonal || !((dir - 1) & dir))
|
||||
votes[source] = dir
|
||||
else // pick one or the other
|
||||
votes[source] = prob(50)? (dir & ~(dir - 1)) : (dir & (dir - 1))
|
||||
|
||||
/datum/component/twitch_plays/simple_movement/proc/fetch_data(datum/source, wipe_votes)
|
||||
if(!votes.len)
|
||||
return
|
||||
var/list/total = list(TEXT_NORTH, TEXT_SOUTH, TEXT_EAST, TEXT_WEST)
|
||||
for(var/i in votes)
|
||||
total[num2text(votes[i])] += 1
|
||||
. = text2num(pickweight(total, 0))
|
||||
if(wipe_votes)
|
||||
votes.len = 0
|
||||
|
||||
/datum/component/twitch_plays/simple_movement/auto
|
||||
var/move_delay = 2
|
||||
var/last_move = 0
|
||||
|
||||
/datum/component/twitch_plays/simple_movement/auto/Initialize(...)
|
||||
if(!ismovable(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
. = ..()
|
||||
if(. & COMPONENT_INCOMPATIBLE)
|
||||
return
|
||||
START_PROCESSING(SSfastprocess, src)
|
||||
|
||||
/datum/component/twitch_plays/simple_movement/auto/Destroy(force, silent)
|
||||
STOP_PROCESSING(SSfastprocess, src)
|
||||
return ..()
|
||||
|
||||
/datum/component/twitch_plays/simple_movement/auto/process()
|
||||
var/dir = fetch_data(null, TRUE)
|
||||
if(!dir)
|
||||
return
|
||||
if(world.time < (last_move + move_delay))
|
||||
return
|
||||
last_move = world.time
|
||||
step(parent, dir)
|
||||
@@ -46,4 +46,4 @@
|
||||
holder.update_action_buttons_icon()
|
||||
if(recharge_sound)
|
||||
playsound(dashing_item, recharge_sound, 50, 1)
|
||||
to_chat(holder, "<span class='notice'>[src] now has [current_charges]/[max_charges] charges.</span>")
|
||||
to_chat(holder, "<span class='notice'>[src] now has [current_charges]/[max_charges] charges.</span>")
|
||||
|
||||
@@ -151,4 +151,4 @@
|
||||
flags_1 |= SHOCKED_1
|
||||
|
||||
/mob/living/proc/reset_shocked()
|
||||
flags_1 &= ~ SHOCKED_1
|
||||
flags_1 &= ~ SHOCKED_1
|
||||
|
||||
@@ -39,4 +39,4 @@
|
||||
symptoms += S
|
||||
|
||||
name = "Sample #[rand(1,10000)]"
|
||||
..()
|
||||
..()
|
||||
|
||||
@@ -47,4 +47,4 @@ BONUS
|
||||
if(!.)
|
||||
return
|
||||
if(A.affected_mob)
|
||||
REMOVE_TRAIT(A.affected_mob, TRAIT_DISFIGURED, DISEASE_TRAIT)
|
||||
REMOVE_TRAIT(A.affected_mob, TRAIT_DISFIGURED, DISEASE_TRAIT)
|
||||
|
||||
@@ -52,4 +52,4 @@ Bonus
|
||||
to_chat(M, "<span class='userdanger'>A wave of dizziness washes over you!</span>")
|
||||
M.Dizzy(5)
|
||||
if(power >= 2)
|
||||
M.set_drugginess(5)
|
||||
M.set_drugginess(5)
|
||||
|
||||
@@ -31,9 +31,8 @@ Bonus
|
||||
var/bleed = FALSE
|
||||
var/pain = FALSE
|
||||
threshold_desc = list(
|
||||
"Resistance 9" = "Doubles the intensity of the immolation effect, but reduces the frequency of all of this symptom's effects.",
|
||||
"Stage Speed 8" = "Increases explosion radius and explosion damage to the host when the host is wet.",
|
||||
"Transmission 8" = "Additionally synthesizes chlorine trifluoride and napalm inside the host. More chemicals are synthesized if the resistance 9 threshold has been met."
|
||||
"Resistance 7" = "Erodes the host's skin, causing them to bleed profusely.",
|
||||
"Transmission 8" = "Eat's away at the host's musclemass, causing increased fatigue."
|
||||
)
|
||||
|
||||
/datum/symptom/flesh_eating/Start(datum/disease/advance/A)
|
||||
@@ -134,4 +133,4 @@ Bonus
|
||||
M.reagents.add_reagent_list(list(/datum/reagent/toxin/heparin = 2, /datum/reagent/toxin/lipolicide = 2))
|
||||
if(zombie)
|
||||
M.reagents.add_reagent(/datum/reagent/romerol, 1)
|
||||
return 1
|
||||
return 1
|
||||
|
||||
@@ -59,4 +59,4 @@ BONUS
|
||||
M.adjustStaminaLoss(25)
|
||||
if(power >= 3 && A.stage >= 5)
|
||||
to_chat(M, "<span class='userdanger'>[pick("Your head hurts!", "You feel a burning knife inside your brain!", "A wave of pain fills your head!")]</span>")
|
||||
M.Stun(35)
|
||||
M.Stun(35)
|
||||
|
||||
@@ -263,18 +263,18 @@
|
||||
|
||||
/datum/symptom/heal/coma/CanHeal(datum/disease/advance/A)
|
||||
var/mob/living/M = A.affected_mob
|
||||
if(M.getBruteLoss() + M.getFireLoss() >= 70 && !active_coma)
|
||||
to_chat(M, "<span class='warning'>You feel yourself slip into a regenerative coma...</span>")
|
||||
active_coma = TRUE
|
||||
addtimer(CALLBACK(src, .proc/coma, M), 60)
|
||||
if(HAS_TRAIT(M, TRAIT_DEATHCOMA))
|
||||
return power
|
||||
else if(M.IsUnconscious() || M.stat == UNCONSCIOUS)
|
||||
return power * 0.9
|
||||
else if(M.stat == SOFT_CRIT)
|
||||
return power * 0.5
|
||||
else if(M.IsSleeping())
|
||||
return power * 0.25
|
||||
else if(M.getBruteLoss() + M.getFireLoss() >= 70 && !active_coma)
|
||||
to_chat(M, "<span class='warning'>You feel yourself slip into a regenerative coma...</span>")
|
||||
active_coma = TRUE
|
||||
addtimer(CALLBACK(src, .proc/coma, M), 60)
|
||||
else if(M.IsUnconscious() || M.stat == UNCONSCIOUS)
|
||||
return power * 0.9
|
||||
|
||||
/datum/symptom/heal/coma/proc/coma(mob/living/M)
|
||||
if(deathgasp)
|
||||
|
||||
@@ -53,4 +53,4 @@ BONUS
|
||||
var/can_scratch = scratch && !M.incapacitated() && get_location_accessible(M, picked_bodypart)
|
||||
M.visible_message("[can_scratch ? "<span class='warning'>[M] scratches [M.p_their()] [bodypart.name].</span>" : ""]", "<span class='warning'>Your [bodypart.name] itches. [can_scratch ? " You scratch it." : ""]</span>")
|
||||
if(can_scratch)
|
||||
bodypart.receive_damage(0.5)
|
||||
bodypart.receive_damage(0.5)
|
||||
|
||||
@@ -67,4 +67,4 @@ Bonus
|
||||
if(!..())
|
||||
return
|
||||
if(A.stage >= 4)
|
||||
REMOVE_TRAIT(A.affected_mob, TRAIT_NOBREATH, DISEASE_TRAIT)
|
||||
REMOVE_TRAIT(A.affected_mob, TRAIT_NOBREATH, DISEASE_TRAIT)
|
||||
|
||||
@@ -38,4 +38,4 @@ BONUS
|
||||
M.reagents.add_reagent(color, 5)
|
||||
else
|
||||
if (prob(50)) // spam
|
||||
M.visible_message("<span class='warning'>[M] looks rather vibrant...</span>", "<span class='notice'>The colors, man, the colors...</span>")
|
||||
M.visible_message("<span class='warning'>[M] looks rather vibrant...</span>", "<span class='notice'>The colors, man, the colors...</span>")
|
||||
|
||||
@@ -51,4 +51,4 @@ Bonus
|
||||
else
|
||||
M.emote("sneeze")
|
||||
if(M.CanSpreadAirborneDisease()) //don't spread germs if they covered their mouth
|
||||
A.spread(4 + power)
|
||||
A.spread(4 + power)
|
||||
|
||||
@@ -79,4 +79,4 @@
|
||||
return
|
||||
|
||||
/datum/symptom/proc/OnRemove(datum/disease/advance/A) //But dont forget to remove them too.
|
||||
return
|
||||
return
|
||||
|
||||
@@ -50,4 +50,4 @@ Bonus
|
||||
else
|
||||
to_chat(M, "<span class='warning'><i>[pick("So hungry...", "You'd kill someone for a bite of food...", "Hunger cramps seize you...")]</i></span>")
|
||||
M.overeatduration = max(M.overeatduration - 100, 0)
|
||||
M.adjust_nutrition(-100)
|
||||
M.adjust_nutrition(-100)
|
||||
|
||||
@@ -55,4 +55,4 @@ BONUS
|
||||
if(5)
|
||||
if(H.age > 21)
|
||||
H.age = 21
|
||||
to_chat(H, "<span class='notice'>You feel like you can take on the world!</span>")
|
||||
to_chat(H, "<span class='notice'>You feel like you can take on the world!</span>")
|
||||
|
||||
@@ -38,4 +38,4 @@
|
||||
"<span class='userdanger'>You cough up butterflies!</span>")
|
||||
new /mob/living/simple_animal/butterfly(affected_mob.loc)
|
||||
new /mob/living/simple_animal/butterfly(affected_mob.loc)
|
||||
return
|
||||
return
|
||||
|
||||
@@ -36,4 +36,4 @@
|
||||
affected_mob.visible_message("<span class='danger'>[affected_mob] coughs up a swarm of bees!</span>", \
|
||||
"<span class='userdanger'>You cough up a swarm of bees!</span>")
|
||||
new /mob/living/simple_animal/hostile/poison/bees(affected_mob.loc)
|
||||
return
|
||||
return
|
||||
|
||||
@@ -50,4 +50,4 @@
|
||||
if(!affected_mob.disease_resistances.Find(/datum/disease/flu))
|
||||
var/datum/disease/Flu = new /datum/disease/flu()
|
||||
affected_mob.ForceContractDisease(Flu, FALSE, TRUE)
|
||||
cure()
|
||||
cure()
|
||||
|
||||
@@ -36,4 +36,4 @@
|
||||
if(prob(1))
|
||||
to_chat(affected_mob, "<span class='danger'>Your throat feels sore.</span>")
|
||||
if(prob(10))
|
||||
to_chat(affected_mob, "<span class='danger'>You feel stiff.</span>")
|
||||
to_chat(affected_mob, "<span class='danger'>You feel stiff.</span>")
|
||||
|
||||
@@ -62,4 +62,4 @@
|
||||
cure()
|
||||
|
||||
else
|
||||
cure()
|
||||
cure()
|
||||
|
||||
@@ -65,4 +65,4 @@
|
||||
var/iter = rand(1,3)
|
||||
for(i=0,i<iter,i++)
|
||||
step_towards(S,affected_mob)
|
||||
return
|
||||
return
|
||||
|
||||
@@ -52,4 +52,4 @@
|
||||
|
||||
/datum/disease/pierrot_throat/remove_disease()
|
||||
UnregisterSignal(affected_mob, COMSIG_MOB_SAY)
|
||||
return ..()
|
||||
return ..()
|
||||
|
||||
@@ -81,4 +81,4 @@
|
||||
if(prob(50))
|
||||
scramble_dna(affected_mob, 1, 0, rand(50,75))
|
||||
else
|
||||
scramble_dna(affected_mob, 0, 1, rand(50,75))
|
||||
scramble_dna(affected_mob, 0, 1, rand(50,75))
|
||||
|
||||
+12
-3
@@ -660,27 +660,34 @@
|
||||
return
|
||||
if(dna.stability > 0)
|
||||
return
|
||||
var/instability = -dna.stability
|
||||
var/instability = - dna.stability
|
||||
dna.remove_all_mutations()
|
||||
dna.stability = 100
|
||||
if(prob(max(70-instability,0)))
|
||||
if(prob(max(70 - instability,0)))
|
||||
switch(rand(0,3)) //not complete and utter death
|
||||
if(0)
|
||||
monkeyize()
|
||||
if(1)
|
||||
gain_trauma(/datum/brain_trauma/severe/paralysis)
|
||||
if(2)
|
||||
unequip_everything()
|
||||
drop_all_held_items()
|
||||
corgize()
|
||||
if(3)
|
||||
to_chat(src, "<span class='notice'>Oh, we actually feel quite alright!</span>")
|
||||
else
|
||||
switch(rand(0,3))
|
||||
if(0)
|
||||
unequip_everything()
|
||||
drop_all_held_items()
|
||||
gib()
|
||||
if(1)
|
||||
unequip_everything()
|
||||
drop_all_held_items()
|
||||
dust()
|
||||
|
||||
if(2)
|
||||
unequip_everything()
|
||||
drop_all_held_items()
|
||||
death()
|
||||
petrify(INFINITY)
|
||||
if(3)
|
||||
@@ -689,6 +696,8 @@
|
||||
if(BP)
|
||||
BP.dismember()
|
||||
else
|
||||
unequip_everything()
|
||||
drop_all_held_items()
|
||||
gib()
|
||||
else
|
||||
set_species(/datum/species/dullahan)
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/// Tucking element, for things that can be tucked into bed.
|
||||
/datum/element/bed_tuckable
|
||||
element_flags = ELEMENT_BESPOKE|ELEMENT_DETACH
|
||||
id_arg_index = 2
|
||||
/// our pixel_x offset - how much the item moves x when in bed (+x is closer to the pillow)
|
||||
var/x_offset = 0
|
||||
/// our pixel_y offset - how much the item move y when in bed (-y is closer to the middle)
|
||||
var/y_offset = 0
|
||||
/// our rotation degree - how much the item turns when in bed (+degrees turns it more parallel)
|
||||
var/rotation_degree = 0
|
||||
|
||||
/datum/element/bed_tuckable/Attach(obj/target, x = 0, y = 0, rotation = 0)
|
||||
. = ..()
|
||||
if(!isitem(target))
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
|
||||
x_offset = x
|
||||
y_offset = y
|
||||
rotation_degree = rotation
|
||||
RegisterSignal(target, COMSIG_ITEM_ATTACK_OBJ, .proc/tuck_into_bed)
|
||||
|
||||
/datum/element/bed_tuckable/Detach(obj/target)
|
||||
. = ..()
|
||||
UnregisterSignal(target, list(COMSIG_ITEM_ATTACK_OBJ, COMSIG_ITEM_PICKUP))
|
||||
|
||||
/**
|
||||
* Tuck our object into bed.
|
||||
*
|
||||
* tucked - the object being tucked
|
||||
* target_bed - the bed we're tucking them into
|
||||
* tucker - the guy doing the tucking
|
||||
*/
|
||||
/datum/element/bed_tuckable/proc/tuck_into_bed(obj/item/tucked, obj/structure/bed/target_bed, mob/living/tucker)
|
||||
|
||||
|
||||
if(!istype(target_bed))
|
||||
return
|
||||
|
||||
if(!tucker.transferItemToLoc(tucked, target_bed.drop_location()))
|
||||
return
|
||||
|
||||
to_chat(tucker, "<span class='notice'>You lay [tucked] out on [target_bed].</span>")
|
||||
tucked.pixel_x = x_offset
|
||||
tucked.pixel_y = y_offset
|
||||
if(rotation_degree)
|
||||
tucked.transform = turn(tucked.transform, rotation_degree)
|
||||
RegisterSignal(tucked, COMSIG_ITEM_PICKUP, .proc/untuck)
|
||||
|
||||
return COMPONENT_NO_AFTERATTACK
|
||||
|
||||
/**
|
||||
* If we rotate our object, then we need to un-rotate it when it's picked up
|
||||
*
|
||||
* tucked - the object that is tucked
|
||||
*/
|
||||
/datum/element/bed_tuckable/proc/untuck(obj/item/tucked)
|
||||
|
||||
|
||||
tucked.transform = turn(tucked.transform, -rotation_degree)
|
||||
UnregisterSignal(tucked, COMSIG_ITEM_PICKUP)
|
||||
@@ -13,6 +13,8 @@ GLOBAL_LIST_EMPTY(mobs_with_editable_flavor_text) //et tu, hacky code
|
||||
var/save_key
|
||||
/// Do not attempt to render a preview on examine. If this is on, it will display as \[flavor_name\]
|
||||
var/examine_no_preview = FALSE
|
||||
/// Examine FULLY views. Overrides examine_no_preview
|
||||
var/examine_full_view = FALSE
|
||||
|
||||
/datum/element/flavor_text/Attach(datum/target, text = "", _name = "Flavor Text", _addendum, _max_len = MAX_FLAVOR_LEN, _always_show = FALSE, _edit = TRUE, _save_key, _examine_no_preview = FALSE)
|
||||
. = ..()
|
||||
@@ -37,7 +39,7 @@ GLOBAL_LIST_EMPTY(mobs_with_editable_flavor_text) //et tu, hacky code
|
||||
if(can_edit && ismob(target)) //but only mobs receive the proc/verb for the time being
|
||||
var/mob/M = target
|
||||
LAZYOR(GLOB.mobs_with_editable_flavor_text[M], src)
|
||||
M.verbs |= /mob/proc/manage_flavor_tests
|
||||
add_verb(M, /mob/proc/manage_flavor_tests)
|
||||
|
||||
if(save_key && ishuman(target))
|
||||
RegisterSignal(target, COMSIG_HUMAN_PREFS_COPIED_TO, .proc/update_prefs_flavor_text)
|
||||
@@ -71,6 +73,9 @@ GLOBAL_LIST_EMPTY(mobs_with_editable_flavor_text) //et tu, hacky code
|
||||
examine_list += "<span class='notice'><a href='?src=[REF(src)];show_flavor=[REF(target)]'>\[[flavor_name]\]</a></span>"
|
||||
return
|
||||
var/msg = replacetext(text, "\n", " ")
|
||||
if(examine_full_view)
|
||||
examine_list += "[msg]"
|
||||
return
|
||||
if(length_char(msg) <= 40)
|
||||
examine_list += "<span class='notice'>[msg]</span>"
|
||||
else
|
||||
@@ -113,6 +118,21 @@ GLOBAL_LIST_EMPTY(mobs_with_editable_flavor_text) //et tu, hacky code
|
||||
var/datum/element/flavor_text/F = choices[chosen]
|
||||
F.set_flavor(src)
|
||||
|
||||
/mob/proc/set_pose()
|
||||
set name = "Set Pose"
|
||||
set desc = "Sets your temporary flavor text"
|
||||
set category = "IC"
|
||||
|
||||
var/list/L = GLOB.mobs_with_editable_flavor_text[src]
|
||||
var/datum/element/flavor_text/carbon/temporary/T
|
||||
for(var/i in L)
|
||||
if(istype(i, /datum/element/flavor_text/carbon/temporary))
|
||||
T = i
|
||||
if(!T)
|
||||
to_chat(src, "<span class='warning'>Your mob type does not support temporary flavor text.</span>")
|
||||
return
|
||||
T.set_flavor(src)
|
||||
|
||||
/datum/element/flavor_text/proc/set_flavor(mob/user)
|
||||
if(!(user in texts_by_atom))
|
||||
return FALSE
|
||||
@@ -135,7 +155,7 @@ GLOBAL_LIST_EMPTY(mobs_with_editable_flavor_text) //et tu, hacky code
|
||||
var/static/list/i_dont_even_know_who_you_are = typecacheof(list(/datum/antagonist/abductor, /datum/antagonist/ert,
|
||||
/datum/antagonist/nukeop, /datum/antagonist/wizard))
|
||||
|
||||
/datum/element/flavor_text/carbon/Attach(datum/target, text = "", _name = "Flavor Text", _addendum, _max_len = MAX_FLAVOR_LEN, _always_show = FALSE, _edit = TRUE, _save_key = "flavor_text", _examine_no_preview = FALSE)
|
||||
/datum/element/flavor_text/carbon/Attach(datum/target, text = "", _name = "Flavor Text", _addendum, _max_len = MAX_FLAVOR_LEN, _always_show = FALSE, _edit = TRUE, _save_key, _examine_no_preview = FALSE)
|
||||
if(!iscarbon(target))
|
||||
return ELEMENT_INCOMPATIBLE
|
||||
. = ..()
|
||||
@@ -167,3 +187,19 @@ GLOBAL_LIST_EMPTY(mobs_with_editable_flavor_text) //et tu, hacky code
|
||||
texts_by_atom[user] = ""
|
||||
if(user.dna)
|
||||
user.dna.features[save_key] = ""
|
||||
|
||||
/datum/element/flavor_text/carbon/temporary
|
||||
examine_full_view = TRUE
|
||||
max_len = 1024
|
||||
|
||||
/datum/element/flavor_text/carbon/temporary/Attach(datum/target, text, _name, _addendum, _max_len, _always_show, _edit, _save_key, _examine_no_preview)
|
||||
. = ..()
|
||||
if(. & ELEMENT_INCOMPATIBLE)
|
||||
return
|
||||
if(ismob(target))
|
||||
add_verb(target, /mob/proc/set_pose)
|
||||
|
||||
/datum/element/flavor_Text/carbon/temporary/Detach(datum/source, force)
|
||||
. = ..()
|
||||
if(ismob(source))
|
||||
remove_verb(source, /mob/proc/set_pose)
|
||||
|
||||
@@ -165,12 +165,21 @@
|
||||
/datum/element/polychromic/proc/on_examine(atom/source, mob/user, list/examine_list)
|
||||
examine_list += "<span class='notice'>Alt-click to recolor it.</span>"
|
||||
|
||||
/datum/element/polychromic/proc/connect_helmet(atom/I, var/applycolor)
|
||||
if(isitem(I))
|
||||
if(istype(I,/obj/item/clothing/suit/hooded))
|
||||
var/obj/item/clothing/suit/hooded/Isuit = I
|
||||
colors_by_atom[Isuit.hood] = applycolor
|
||||
else if(istype(I,/obj/item/clothing/suit/space/hardsuit))
|
||||
var/obj/item/clothing/suit/space/hardsuit/Isuit = I
|
||||
colors_by_atom[Isuit.helmet] = applycolor
|
||||
|
||||
/datum/element/polychromic/proc/register_helmet(atom/source, obj/item/clothing/head/H)
|
||||
if(!isitem(H)) //backup in case if it messes up somehow
|
||||
if(istype(source,/obj/item/clothing/suit/hooded)) //so how come it be like this, where toggleable headslots are named separately (helmet/hood) anyways?
|
||||
var/obj/item/clothing/suit/hooded/sourcesuit = source
|
||||
H = sourcesuit.hood
|
||||
else if(istype(source,/obj/item/clothing/suit/space/hardsuit))
|
||||
else if(istype(source,/obj/item/clothing/suit/space/hardsuit))
|
||||
var/obj/item/clothing/suit/space/hardsuit/sourcesuit = source
|
||||
H = sourcesuit.helmet
|
||||
else
|
||||
|
||||
@@ -7,4 +7,4 @@
|
||||
RegisterSignal(target, COMSIG_ATOM_UPDATE_ICON, .proc/block_update_icon)
|
||||
|
||||
/datum/element/update_icon_blocker/proc/block_update_icon()
|
||||
return COMSIG_ATOM_NO_UPDATE_ICON_STATE | COMSIG_ATOM_NO_UPDATE_OVERLAYS
|
||||
return COMSIG_ATOM_NO_UPDATE_ICON_STATE | COMSIG_ATOM_NO_UPDATE_OVERLAYS
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
return
|
||||
|
||||
user.log_message(msg, LOG_EMOTE)
|
||||
msg = "<b>[user]</b> " + msg
|
||||
msg = "<span class='emote'><b>[user]</b> [msg]</span>"
|
||||
|
||||
for(var/mob/M in GLOB.dead_mob_list)
|
||||
if(!M.client || isnewplayer(M))
|
||||
@@ -144,7 +144,7 @@
|
||||
var/sound //Sound to play when emote is called
|
||||
var/vary = FALSE //used for the honk borg emote
|
||||
var/volume = 50
|
||||
mob_type_allowed_typecache = list(/mob/living/brain, /mob/living/silicon)
|
||||
mob_type_allowed_typecache = list(/mob/living/brain, /mob/living/silicon, /mob/camera/aiEye)
|
||||
|
||||
/datum/emote/sound/run_emote(mob/user, params)
|
||||
. = ..()
|
||||
|
||||
@@ -85,6 +85,15 @@
|
||||
var/mob/M = teleatom
|
||||
M.cancel_camera()
|
||||
|
||||
var/static/list/bread_cache = typecacheof(/obj/item/reagent_containers/food/snacks/store/bread)
|
||||
var/list/breadlist = typecache_filter_list(teleatom.GetAllContents(), bread_cache)
|
||||
if(breadlist.len && (channel == TELEPORT_CHANNEL_BLUESPACE || channel == TELEPORT_CHANNEL_QUANTUM))
|
||||
for(var/obj/item/reagent_containers/food/snacks/store/bread/bread in breadlist)
|
||||
bread.bread_teleport()
|
||||
else if(istype(teleatom, /obj/item/reagent_containers/food/snacks/store/bread))
|
||||
var/obj/item/reagent_containers/food/snacks/store/bread/bread = teleatom
|
||||
bread.bread_teleport()
|
||||
|
||||
return TRUE
|
||||
|
||||
/proc/tele_play_specials(atom/movable/teleatom, atom/location, datum/effect_system/effect, sound)
|
||||
|
||||
@@ -59,4 +59,4 @@ datum/looping_sound/generator/clockwork
|
||||
mid_sounds = list('sound/machines/fryer/deep_fryer_1.ogg' = 1, 'sound/machines/fryer/deep_fryer_2.ogg' = 1)
|
||||
volume = 10
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -66,4 +66,4 @@
|
||||
|
||||
if(atk_verb)
|
||||
log_combat(A, D, "[atk_verb] (Psychotic Brawling)")
|
||||
return TRUE
|
||||
return TRUE
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
id = MARTIALART_SLEEPINGCARP
|
||||
allow_temp_override = FALSE
|
||||
help_verb = /mob/living/carbon/human/proc/sleeping_carp_help
|
||||
block_parry_data = /datum/block_parry_data/sleeping_carp
|
||||
pugilist = TRUE
|
||||
|
||||
/datum/martial_art/the_sleeping_carp/proc/check_streak(mob/living/carbon/human/A, mob/living/carbon/human/D)
|
||||
@@ -134,6 +135,28 @@
|
||||
return BULLET_ACT_FORCE_PIERCE
|
||||
return BULLET_ACT_HIT
|
||||
|
||||
/datum/block_parry_data/sleeping_carp
|
||||
parry_time_windup = 0
|
||||
parry_time_active = 25
|
||||
parry_time_spindown = 0
|
||||
// we want to signal to players the most dangerous phase, the time when automatic counterattack is a thing.
|
||||
parry_time_windup_visual_override = 1
|
||||
parry_time_active_visual_override = 3
|
||||
parry_time_spindown_visual_override = 12
|
||||
parry_flags = PARRY_DEFAULT_HANDLE_FEEDBACK //can attack while
|
||||
parry_time_perfect = 2.5 // first ds isn't perfect
|
||||
parry_time_perfect_leeway = 1.5
|
||||
parry_imperfect_falloff_percent = 5
|
||||
parry_efficiency_to_counterattack = 100
|
||||
parry_efficiency_considered_successful = 65 // VERY generous
|
||||
parry_efficiency_perfect = 100
|
||||
parry_failed_stagger_duration = 4 SECONDS
|
||||
parry_cooldown = 0.5 SECONDS
|
||||
|
||||
/mob/living/carbon/human/UseStaminaBuffer(amount, warn = FALSE, considered_action = TRUE)
|
||||
amount *= physiology? physiology.stamina_buffer_mod : 1
|
||||
return ..()
|
||||
|
||||
/datum/martial_art/the_sleeping_carp/teach(mob/living/carbon/human/H, make_temporary = FALSE)
|
||||
. = ..()
|
||||
if(!.)
|
||||
@@ -144,12 +167,12 @@
|
||||
ADD_TRAIT(H, TRAIT_TASED_RESISTANCE, SLEEPING_CARP_TRAIT)
|
||||
H.physiology.brute_mod *= 0.4 //brute is really not gonna cut it
|
||||
H.physiology.burn_mod *= 0.7 //burn is distinctly more useful against them than brute but they're still resistant
|
||||
H.physiology.stamina_mod *= 0.5 //You take less stamina damage overall, but you do not reduce the damage from stun batons
|
||||
H.physiology.stamina_mod *= 0.4 //You take less stamina damage overall, but you do not reduce the damage from stun batons as much
|
||||
H.physiology.stun_mod *= 0.3 //for those rare stuns
|
||||
H.physiology.pressure_mod *= 0.3 //go hang out with carp
|
||||
H.physiology.cold_mod *= 0.3 //cold mods are different to burn mods, they do stack however
|
||||
H.physiology.heat_mod *= 2 //this is mostly so sleeping carp has a viable weakness. Cooking them alive. Setting them on fire and heating them will be their biggest weakness. The reason for this is....filet jokes.
|
||||
|
||||
H.physiology.stamina_buffer_mod *= 0.75 //to help with some stamina
|
||||
H.faction |= "carp" //:D
|
||||
|
||||
/datum/martial_art/the_sleeping_carp/on_remove(mob/living/carbon/human/H)
|
||||
@@ -165,7 +188,7 @@
|
||||
H.physiology.pressure_mod = initial(H.physiology.pressure_mod) //no more carpies
|
||||
H.physiology.cold_mod = initial(H.physiology.cold_mod)
|
||||
H.physiology.heat_mod = initial(H.physiology.heat_mod)
|
||||
|
||||
H.physiology.stamina_buffer_mod = initial(H.physiology.stamina_buffer_mod)
|
||||
H.faction -= "carp" //:(
|
||||
|
||||
/mob/living/carbon/human/proc/sleeping_carp_help()
|
||||
|
||||
@@ -163,7 +163,7 @@
|
||||
timeout = 3 MINUTES
|
||||
|
||||
/datum/mood_event/gates_of_mansus
|
||||
description = "<span class='boldwarning'>LIVING IN A PERFORMANCE IS WORSE THAN DEATH</span>\n"
|
||||
description = "<span class='boldwarning'>I HAD A GLIMPSE OF THE HORROR BEYOND THIS WORLD. REALITY UNCOILED BEFORE MY EYES!</span>\n"
|
||||
mood_change = -25
|
||||
timeout = 4 MINUTES
|
||||
|
||||
|
||||
@@ -16,4 +16,4 @@
|
||||
visual_indicators[type] = list(mutable_appearance('icons/effects/genetics.dmi', "radiation", -MUTATIONS_LAYER))
|
||||
|
||||
/datum/mutation/human/radioactive/get_visual_indicator()
|
||||
return visual_indicators[type][1]
|
||||
return visual_indicators[type][1]
|
||||
|
||||
@@ -64,4 +64,4 @@
|
||||
qdel(bar)
|
||||
. = ..()
|
||||
|
||||
#undef PROGRESSBAR_HEIGHT
|
||||
#undef PROGRESSBAR_HEIGHT
|
||||
|
||||
@@ -438,12 +438,19 @@
|
||||
return
|
||||
else
|
||||
linked_alert.icon_state = "fleshmend"
|
||||
owner.adjustBruteLoss(-10, FALSE)
|
||||
owner.adjustFireLoss(-5, FALSE)
|
||||
owner.adjustOxyLoss(-10)
|
||||
if(!iscarbon(owner))
|
||||
owner.adjustBruteLoss(-10, FALSE)
|
||||
owner.adjustFireLoss(-5, FALSE)
|
||||
return
|
||||
var/mob/living/carbon/C = owner
|
||||
var/list/damaged_parts = C.get_damaged_bodyparts(TRUE,TRUE, status = list(BODYPART_ORGANIC, BODYPART_HYBRID, BODYPART_NANITES))
|
||||
if(damaged_parts.len)
|
||||
for(var/obj/item/bodypart/part in damaged_parts)
|
||||
part.heal_damage(10/damaged_parts.len, 5/damaged_parts.len, only_organic = FALSE, updating_health = FALSE)
|
||||
C.updatehealth()
|
||||
C.update_damage_overlays()
|
||||
|
||||
QDEL_LIST(C.all_scars)
|
||||
|
||||
/obj/screen/alert/status_effect/fleshmend
|
||||
@@ -566,13 +573,17 @@
|
||||
duration = 1 MINUTES
|
||||
status_type = STATUS_EFFECT_REPLACE
|
||||
alert_type = /obj/screen/alert/status_effect/regenerative_core
|
||||
var/heal_amount = 25
|
||||
|
||||
/datum/status_effect/regenerative_core/on_apply()
|
||||
. = ..()
|
||||
ADD_TRAIT(owner, TRAIT_IGNOREDAMAGESLOWDOWN, "regenerative_core")
|
||||
owner.adjustBruteLoss(-25)
|
||||
|
||||
if(HAS_TRAIT(owner, TRAIT_ROBOTIC_ORGANISM)) //Robots can heal from cores, but only get 1/5th of the healing. They can use this to get past the damage threshhold however, and then regularely heal from there.
|
||||
heal_amount *= 0.2
|
||||
owner.adjustBruteLoss(-heal_amount, only_organic = FALSE)
|
||||
if(!AmBloodsucker(owner)) //use your coffin you lazy bastard
|
||||
owner.adjustFireLoss(-25)
|
||||
owner.adjustFireLoss(-heal_amount, only_organic = FALSE)
|
||||
owner.remove_CC()
|
||||
owner.bodytemperature = BODYTEMP_NORMAL
|
||||
return TRUE
|
||||
@@ -599,7 +610,7 @@
|
||||
|
||||
//Heal brain damage and toxyloss, alongside trauma
|
||||
owner.adjustOrganLoss(ORGAN_SLOT_BRAIN, -8)
|
||||
owner.adjustToxLoss(-6, forced = TRUE)
|
||||
owner.adjustToxLoss(-6, forced = TRUE, toxins_type = TOX_OMNI)
|
||||
M.cure_trauma_type(resilience = TRAUMA_RESILIENCE_BASIC)
|
||||
//Purges 50 rads per tick
|
||||
if(owner.radiation > 0)
|
||||
@@ -640,3 +651,120 @@
|
||||
if(D.severity == DISEASE_SEVERITY_POSITIVE)
|
||||
continue
|
||||
D.cure()
|
||||
|
||||
/datum/status_effect/mantra // available to wizards and admins alone, currently
|
||||
id = "Mantra"
|
||||
examine_text = "<span class='notice'>Their aura is filled with yellow energy!</span>"
|
||||
alert_type = null
|
||||
var/damageboost = 10
|
||||
var/woundboost = 5
|
||||
var/prev_hair_color
|
||||
var/powerup
|
||||
var/powerdown
|
||||
|
||||
/datum/status_effect/mantra/on_apply()
|
||||
. = ..()
|
||||
if(iscarbon(owner))
|
||||
var/mob/living/carbon/human/H = owner
|
||||
playsound(H, 'sound/magic/powerup.ogg', 50, 1)
|
||||
H.add_filter("mantra_glow", 2, list("type" = "outline", "color" = "#edfa347a", "size" = 2))
|
||||
prev_hair_color = H.hair_color
|
||||
H.hair_color = "ffe11e"
|
||||
H.update_hair()
|
||||
ADD_TRAIT(H, TRAIT_PUGILIST, "Mantra")
|
||||
ADD_TRAIT(H, TRAIT_NOSOFTCRIT, "Mantra")
|
||||
ADD_TRAIT(H, TRAIT_STUNIMMUNE, "Mantra")
|
||||
ADD_TRAIT(H, TRAIT_PUSHIMMUNE, "Mantra")
|
||||
ADD_TRAIT(H, TRAIT_NOGUNS, "Mantra")
|
||||
H.dna.species.punchdamagehigh += damageboost
|
||||
H.dna.species.punchdamagelow += damageboost
|
||||
H.dna.species.punchwoundbonus += woundboost
|
||||
H.physiology.brute_mod *= 0.9 // slightly resilient against lethal damage, but...
|
||||
H.physiology.burn_mod *= 0.9
|
||||
H.physiology.stamina_mod *= 0.5 // very resistant to non-lethal damage, because they're already draining stamina every second
|
||||
to_chat(H, "<span class='notice'>Your inner mantra coalesces around you, granting you incredible strength and durability - but at what cost?</span>")
|
||||
|
||||
/datum/status_effect/mantra/tick()
|
||||
. = ..()
|
||||
if(owner.health < HEALTH_THRESHOLD_FULLCRIT)
|
||||
owner.remove_status_effect(STATUS_EFFECT_MANTRA)
|
||||
return
|
||||
if(owner.combat_flags & COMBAT_FLAG_HARD_STAMCRIT)
|
||||
owner.remove_status_effect(STATUS_EFFECT_MANTRA)
|
||||
return
|
||||
if(iscarbon(owner))
|
||||
var/mob/living/carbon/human/C = owner
|
||||
C.adjustBruteLoss(-1) // slightly resilient against lethal damage
|
||||
C.adjustFireLoss(-1)
|
||||
C.adjustStaminaLoss(3) // in testing i personally found that 2/sec was too minimal and 4/sec was too much
|
||||
/*if(SEND_SIGNAL(owner, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_ACTIVE)) // turning on combat mode flares up your aura
|
||||
|
||||
else*/
|
||||
|
||||
/datum/status_effect/mantra/on_remove()
|
||||
. = ..()
|
||||
if(iscarbon(owner))
|
||||
var/mob/living/carbon/human/M = owner
|
||||
playsound(M, 'sound/magic/powerdown.ogg', 50, 1)
|
||||
M.remove_filter("mantra_glow")
|
||||
M.hair_color = prev_hair_color
|
||||
M.update_hair()
|
||||
REMOVE_TRAIT(M, TRAIT_PUGILIST, "Mantra")
|
||||
REMOVE_TRAIT(M, TRAIT_NOSOFTCRIT, "Mantra")
|
||||
REMOVE_TRAIT(M, TRAIT_STUNIMMUNE, "Mantra")
|
||||
REMOVE_TRAIT(M, TRAIT_PUSHIMMUNE, "Mantra")
|
||||
REMOVE_TRAIT(M, TRAIT_NOGUNS, "Mantra")
|
||||
M.dna.species.punchdamagehigh -= damageboost
|
||||
M.dna.species.punchdamagelow -= damageboost
|
||||
M.dna.species.punchwoundbonus -= woundboost
|
||||
M.physiology.brute_mod /= 0.9
|
||||
M.physiology.burn_mod /= 0.9
|
||||
M.physiology.stamina_mod /= 0.5
|
||||
to_chat(M, "<span class='notice'>Your inner mantra collapses, for now.</span>")
|
||||
|
||||
/datum/status_effect/asura // mfw miner gear
|
||||
id = "Asura"
|
||||
examine_text = "<span class='notice'>Their aura is filled with red-hot rage!</span>"
|
||||
alert_type = null
|
||||
var/damageboost = 10
|
||||
var/woundboost = 5
|
||||
|
||||
/datum/status_effect/asura/on_apply()
|
||||
. = ..()
|
||||
if(iscarbon(owner))
|
||||
var/mob/living/carbon/human/H = owner
|
||||
playsound(H, 'sound/magic/powerup.ogg', 50, 1)
|
||||
H.add_filter("asura_glow", 2, list("type" = "outline", "color" = "#fc21217a", "size" = 2))
|
||||
ADD_TRAIT(H, TRAIT_PUGILIST, "Asura")
|
||||
H.dna.species.punchdamagehigh += damageboost
|
||||
H.dna.species.punchdamagelow += damageboost
|
||||
H.dna.species.punchwoundbonus += woundboost
|
||||
to_chat(H, "<span class='notice'>Your anger unleashes in a crimson blaze around you and corrosive power fills your muscles.</span>")
|
||||
|
||||
/datum/status_effect/asura/tick()
|
||||
. = ..()
|
||||
if(owner.health < HEALTH_THRESHOLD_CRIT)
|
||||
owner.remove_status_effect(STATUS_EFFECT_ASURA)
|
||||
return
|
||||
if(owner.combat_flags & COMBAT_FLAG_HARD_STAMCRIT)
|
||||
owner.remove_status_effect(STATUS_EFFECT_ASURA)
|
||||
return
|
||||
if(iscarbon(owner))
|
||||
var/mob/living/carbon/human/C = owner
|
||||
C.adjustBruteLoss(1) // drains 1 hp per second. You're gonna need some Senzu Cores.
|
||||
C.adjustStaminaLoss(-2) // angry man punch a lot
|
||||
/*if(SEND_SIGNAL(owner, COMSIG_COMBAT_MODE_CHECK, COMBAT_MODE_ACTIVE)) // turning on combat mode flares up your aura
|
||||
|
||||
else*/
|
||||
|
||||
/datum/status_effect/asura/on_remove()
|
||||
. = ..()
|
||||
if(iscarbon(owner))
|
||||
var/mob/living/carbon/human/M = owner
|
||||
playsound(M, 'sound/magic/powerdown.ogg', 50, 1)
|
||||
M.remove_filter("asura_glow")
|
||||
REMOVE_TRAIT(M, TRAIT_PUGILIST, "Asura")
|
||||
M.dna.species.punchdamagehigh -= damageboost
|
||||
M.dna.species.punchdamagelow -= damageboost
|
||||
M.dna.species.punchwoundbonus -= woundboost
|
||||
to_chat(M, "<span class='notice'>You calm yourself, and your unnatural strength dissipates.</span>")
|
||||
|
||||
@@ -586,7 +586,7 @@
|
||||
|
||||
var/list/mob/living/targets = list()
|
||||
for(var/mob/living/potential_target in oview(owner, 1))
|
||||
if(IS_HERETIC(potential_target) || potential_target.mind?.has_antag_datum(/datum/antagonist/heretic_monster))
|
||||
if(IS_HERETIC(potential_target) || IS_HERETIC_MONSTER(potential_target))
|
||||
continue
|
||||
targets += potential_target
|
||||
if(LAZYLEN(targets))
|
||||
|
||||
@@ -74,13 +74,19 @@
|
||||
|
||||
/datum/status_effect/proc/on_remove() //Called whenever the buff expires or is removed; do note that at the point this is called, it is out of the owner's status_effects but owner is not yet null
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
REMOVE_TRAIT(owner, TRAIT_COMBAT_MODE_LOCKED, src)
|
||||
REMOVE_TRAIT(owner, TRAIT_SPRINT_LOCKED, src)
|
||||
if(blocks_combatmode)
|
||||
REMOVE_TRAIT(owner, TRAIT_COMBAT_MODE_LOCKED, src)
|
||||
if(blocks_sprint)
|
||||
REMOVE_TRAIT(owner, TRAIT_SPRINT_LOCKED, src)
|
||||
return TRUE
|
||||
|
||||
/datum/status_effect/proc/be_replaced() //Called instead of on_remove when a status effect is replaced by itself or when a status effect with on_remove_on_mob_delete = FALSE has its mob deleted
|
||||
owner.clear_alert(id)
|
||||
LAZYREMOVE(owner.status_effects, src)
|
||||
if(blocks_combatmode)
|
||||
REMOVE_TRAIT(owner, TRAIT_COMBAT_MODE_LOCKED, src)
|
||||
if(blocks_sprint)
|
||||
REMOVE_TRAIT(owner, TRAIT_SPRINT_LOCKED, src)
|
||||
owner = null
|
||||
qdel(src)
|
||||
|
||||
|
||||
@@ -137,12 +137,18 @@ GLOBAL_LIST_EMPTY(family_heirlooms)
|
||||
var/lums = T.get_lumcount()
|
||||
if(lums <= 0.2)
|
||||
if(quirk_holder.m_intent == MOVE_INTENT_RUN)
|
||||
to_chat(quirk_holder, "<span class='warning'>Easy, easy, take it slow... you're in the dark...</span>")
|
||||
quirk_holder.toggle_move_intent()
|
||||
addtimer(CALLBACK(src, .proc/recheck),2) //0.2 seconds of being in the dark
|
||||
SEND_SIGNAL(quirk_holder, COMSIG_ADD_MOOD_EVENT, "nyctophobia", /datum/mood_event/nyctophobia)
|
||||
else
|
||||
SEND_SIGNAL(quirk_holder, COMSIG_CLEAR_MOOD_EVENT, "nyctophobia")
|
||||
|
||||
/datum/quirk/nyctophobia/proc/recheck()
|
||||
var/turf/T = get_turf(quirk_holder)
|
||||
var/lums = T.get_lumcount()
|
||||
if(lums <= 0.2) //check again, did they remain in the dark for 0.2 seconds?
|
||||
to_chat(quirk_holder, "<span class='warning'>Easy, easy, take it slow... you're in the dark...</span>")
|
||||
quirk_holder.toggle_move_intent()
|
||||
|
||||
/datum/quirk/lightless
|
||||
name = "Light Sensitivity"
|
||||
desc = "Bright lights irritate you. Your eyes start to water, your skin feels itchy against the photon radiation, and your hair gets dry and frizzy. Maybe it's a medical condition. If only Nanotrasen was more considerate of your needs..."
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
name = "Alcohol Intolerance"
|
||||
desc = "You take toxin damage from alcohol rather than getting drunk."
|
||||
value = 0
|
||||
mob_trait = TRAIT_NO_ALCOHOL
|
||||
mob_trait = TRAIT_TOXIC_ALCOHOL
|
||||
medical_record_text = "Patient's body does not react properly to ethyl alcohol."
|
||||
|
||||
/datum/quirk/alcohol_intolerance/add()
|
||||
|
||||
@@ -72,4 +72,4 @@
|
||||
var/area/AA = get_base_area(A)
|
||||
if(AA.atmosalert(2, holder))
|
||||
A.post_alert(2)
|
||||
A.update_icon()
|
||||
A.update_icon()
|
||||
|
||||
@@ -55,4 +55,4 @@
|
||||
if(mend)
|
||||
A.aidisabled = FALSE
|
||||
else
|
||||
A.aidisabled = TRUE
|
||||
A.aidisabled = TRUE
|
||||
|
||||
@@ -79,4 +79,4 @@
|
||||
|
||||
/datum/wires/explosive/gibtonite/explode()
|
||||
var/obj/item/gibtonite/P = holder
|
||||
P.GibtoniteReaction(null, 2)
|
||||
P.GibtoniteReaction(null, 2)
|
||||
|
||||
@@ -29,4 +29,4 @@
|
||||
if(WIRE_MOTOR1, WIRE_MOTOR2)
|
||||
holder.visible_message("<span class='notice'>[icon2html(M, viewers(holder))] The drive motor whines briefly.</span>")
|
||||
else
|
||||
holder.visible_message("<span class='notice'>[icon2html(M, viewers(holder))] You hear a radio crackle.</span>")
|
||||
holder.visible_message("<span class='notice'>[icon2html(M, viewers(holder))] You hear a radio crackle.</span>")
|
||||
|
||||
@@ -47,4 +47,4 @@
|
||||
C.remove_strength()
|
||||
|
||||
/datum/wires/particle_accelerator/control_box/emp_pulse() // to prevent singulo from pulsing wires
|
||||
return
|
||||
return
|
||||
|
||||
@@ -57,4 +57,4 @@
|
||||
if(WIRE_IDSCAN)
|
||||
V.scan_id = mend
|
||||
if(WIRE_SPEAKER)
|
||||
V.shut_up = mend
|
||||
V.shut_up = mend
|
||||
|
||||
@@ -164,7 +164,7 @@
|
||||
. = list()
|
||||
.["version"] = GLOB.game_version
|
||||
.["mode"] = "hidden" //CIT CHANGE - hides the gamemode in topic() calls to prevent meta'ing the gamemode
|
||||
.["respawn"] = config ? !CONFIG_GET(flag/norespawn) : FALSE
|
||||
.["respawn"] = config ? CONFIG_GET(flag/respawns_enabled) : FALSE
|
||||
.["enter"] = GLOB.enter_allowed
|
||||
.["vote"] = CONFIG_GET(flag/allow_vote_mode)
|
||||
.["ai"] = CONFIG_GET(flag/allow_ai)
|
||||
|
||||
@@ -149,4 +149,4 @@
|
||||
/// Used to format a scar to safe in preferences for persistent scars
|
||||
/datum/scar/proc/format_amputated(body_zone)
|
||||
description = pick(list("is several skintone shades paler than the rest of the body", "is a gruesome patchwork of artificial flesh", "has a large series of attachment scars at the articulation points"))
|
||||
return "[SCAR_CURRENT_VERSION]|[body_zone]|[description]|amputated|[WOUND_SEVERITY_LOSS]"
|
||||
return "[SCAR_CURRENT_VERSION]|[body_zone]|[description]|amputated|[WOUND_SEVERITY_LOSS]"
|
||||
|
||||
@@ -91,8 +91,6 @@
|
||||
var/wound_flags = (FLESH_WOUND | BONE_WOUND | ACCEPTS_GAUZE)
|
||||
|
||||
/datum/wound/Destroy()
|
||||
if(attached_surgery)
|
||||
QDEL_NULL(attached_surgery)
|
||||
if(limb?.wounds && (src in limb.wounds)) // destroy can call remove_wound() and remove_wound() calls qdel, so we check to make sure there's anything to remove first
|
||||
remove_wound()
|
||||
limb = null
|
||||
|
||||
Reference in New Issue
Block a user