Merge pull request #6183 from Citadel-Station-13/upstream-merge-36548
[MIRROR] Added a new ability to sentient diseases
This commit is contained in:
@@ -71,7 +71,8 @@
|
||||
#define COMSIG_MOVABLE_MOVED "movable_moved" //from base of atom/movable/Moved(): (/atom, dir)
|
||||
#define COMSIG_MOVABLE_CROSSED "movable_crossed" //from base of atom/movable/Crossed(): (/atom/movable)
|
||||
#define COMSIG_MOVABLE_COLLIDE "movable_collide" //from base of atom/movable/Collide(): (/atom)
|
||||
#define COMSIG_MOVABLE_IMPACT "movable_impact" //from base of atom/movable/throw_impact(): (/atom, throwingdatum)
|
||||
#define COMSIG_MOVABLE_IMPACT "movable_impact" //from base of atom/movable/throw_impact(): (/atom/hit_atom, /datum/thrownthing/throwingdatum)
|
||||
#define COMSIG_MOVABLE_IMPACT_ZONE "item_impact_zone" //from base of mob/living/hitby(): (mob/living/target, hit_zone)
|
||||
#define COMSIG_MOVABLE_BUCKLE "buckle" //from base of atom/movable/buckle_mob(): (mob, force)
|
||||
#define COMSIG_MOVABLE_UNBUCKLE "unbuckle" //from base of atom/movable/unbuckle_mob(): (mob, force)
|
||||
|
||||
@@ -80,7 +81,9 @@
|
||||
#define COMSIG_ITEM_ATTACK_SELF "item_attack_self" //from base of obj/item/attack_self(): (/mob)
|
||||
#define COMSIG_ITEM_ATTACK_OBJ "item_attack_obj" //from base of obj/item/attack_obj(): (/obj, /mob)
|
||||
#define COMSIG_ITEM_EQUIPPED "item_equip" //from base of obj/item/equipped(): (/mob/equipper, slot)
|
||||
#define COMSIG_ITEM_DROPPED "item_drop" //from base of obj/item/dropped(): (/mob/dropper)
|
||||
#define COMSIG_ITEM_DROPPED "item_drop"
|
||||
#define COMSIG_ITEM_PICKUP "item_pickup" //from base of obj/item/pickup(): (/mob/taker)
|
||||
#define COMSIG_ITEM_ATTACK_ZONE "item_attack_zone" //from base of mob/living/carbon/attacked_by(): (mob/living/carbon/target, mob/living/user, hit_zone)
|
||||
|
||||
// /obj/item/clothing signals
|
||||
#define COMSIG_SHOES_STEP_ACTION "shoes_step_action" //from base of obj/item/clothing/shoes/proc/step_action(): ()
|
||||
@@ -101,3 +104,6 @@
|
||||
//Wet floors
|
||||
#define COMSIG_TURF_IS_WET "check_turf_wet" //(): Returns bitflags of wet values.
|
||||
#define COMSIG_TURF_MAKE_DRY "make_turf_try" //(max_strength, immediate, duration_decrease = INFINITY): Returns bool.
|
||||
|
||||
//Food
|
||||
#define COMSIG_FOOD_EATEN "food_eaten" //from base of obj/item/reagent_containers/food/snacks/attack(): (mob/living/eater, mob/feeder)
|
||||
|
||||
@@ -398,7 +398,28 @@
|
||||
|
||||
return covered_parts
|
||||
|
||||
/proc/slot2body_zone(slot)
|
||||
switch(slot)
|
||||
if(slot_back, slot_wear_suit, slot_w_uniform, slot_belt, slot_wear_id)
|
||||
return BODY_ZONE_CHEST
|
||||
|
||||
if(slot_gloves, slot_hands, slot_handcuffed)
|
||||
return pick(BODY_ZONE_PRECISE_L_HAND, BODY_ZONE_PRECISE_R_HAND)
|
||||
|
||||
if(slot_head, slot_neck, slot_neck, slot_ears)
|
||||
return BODY_ZONE_HEAD
|
||||
|
||||
if(slot_wear_mask)
|
||||
return BODY_ZONE_PRECISE_MOUTH
|
||||
|
||||
if(slot_glasses)
|
||||
return BODY_ZONE_PRECISE_EYES
|
||||
|
||||
if(slot_shoes)
|
||||
return pick(BODY_ZONE_PRECISE_R_FOOT, BODY_ZONE_PRECISE_L_FOOT)
|
||||
|
||||
if(slot_legcuffed)
|
||||
return pick(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
|
||||
|
||||
//adapted from http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/
|
||||
/proc/heat2colour(temp)
|
||||
|
||||
@@ -1,12 +1,78 @@
|
||||
/datum/component/infective
|
||||
dupe_mode = COMPONENT_DUPE_ALLOWED
|
||||
var/list/datum/disease/diseases //make sure these are the static, non-processing versions!
|
||||
var/expire_time
|
||||
var/min_clean_strength = CLEAN_WEAK
|
||||
|
||||
/datum/component/infective/Initialize(list/datum/disease/_diseases)
|
||||
RegisterSignal(COMSIG_MOVABLE_CROSSED, .proc/Infect)
|
||||
diseases = _diseases
|
||||
/datum/component/infective/Initialize(list/datum/disease/_diseases, expire_in)
|
||||
if(islist(_diseases))
|
||||
diseases = diseases
|
||||
else
|
||||
diseases = list(_diseases)
|
||||
if(expire_in)
|
||||
expire_time = world.time + expire_in
|
||||
QDEL_IN(src, expire_in)
|
||||
RegisterSignal(COMSIG_MOVABLE_BUCKLE, .proc/try_infect_buckle)
|
||||
RegisterSignal(COMSIG_MOVABLE_COLLIDE, .proc/try_infect_collide)
|
||||
RegisterSignal(COMSIG_MOVABLE_CROSSED, .proc/try_infect_crossed)
|
||||
RegisterSignal(COMSIG_ITEM_ATTACK_ZONE, .proc/try_infect_attack_zone)
|
||||
RegisterSignal(COMSIG_ITEM_ATTACK, .proc/try_infect_attack)
|
||||
RegisterSignal(COMSIG_ITEM_EQUIPPED, .proc/try_infect_equipped)
|
||||
RegisterSignal(COMSIG_MOVABLE_IMPACT_ZONE, .proc/try_infect_impact_zone)
|
||||
RegisterSignal(COMSIG_FOOD_EATEN, .proc/try_infect_eat)
|
||||
RegisterSignal(COMSIG_COMPONENT_CLEAN_ACT, .proc/clean)
|
||||
|
||||
/datum/component/infective/proc/Infect(atom/movable/AM)
|
||||
var/mob/living/carbon/victim = AM
|
||||
if(istype(victim))
|
||||
for(var/datum/disease/D in diseases)
|
||||
victim.ContactContractDisease(D, "feet")
|
||||
/datum/component/infective/proc/try_infect_eat(mob/living/eater, mob/living/feeder)
|
||||
for(var/V in diseases)
|
||||
eater.ForceContractDisease(V)
|
||||
try_infect(feeder, BODY_ZONE_L_ARM)
|
||||
|
||||
/datum/component/infective/proc/clean(clean_strength)
|
||||
if(clean_strength >= min_clean_strength)
|
||||
qdel(src)
|
||||
|
||||
/datum/component/infective/proc/try_infect_buckle(mob/M, force)
|
||||
if(isliving(M))
|
||||
try_infect(M)
|
||||
|
||||
/datum/component/infective/proc/try_infect_collide(atom/A)
|
||||
var/atom/movable/P = parent
|
||||
if(P.throwing)
|
||||
//this will be handled by try_infect_impact_zone()
|
||||
return
|
||||
if(isliving(A))
|
||||
try_infect(A)
|
||||
|
||||
/datum/component/infective/proc/try_infect_impact_zone(mob/living/target, hit_zone)
|
||||
try_infect(target, hit_zone)
|
||||
|
||||
/datum/component/infective/proc/try_infect_attack_zone(mob/living/carbon/target, mob/living/user, hit_zone)
|
||||
try_infect(user, BODY_ZONE_L_ARM)
|
||||
try_infect(target, hit_zone)
|
||||
|
||||
/datum/component/infective/proc/try_infect_attack(mob/living/target, mob/living/user)
|
||||
if(!iscarbon(target)) //this case will be handled by try_infect_attack_zone
|
||||
try_infect(target)
|
||||
try_infect(user, BODY_ZONE_L_ARM)
|
||||
|
||||
/datum/component/infective/proc/try_infect_equipped(mob/living/L, slot)
|
||||
var/old_permeability
|
||||
if(isitem(parent))
|
||||
//if you are putting an infective item on, it obviously will not protect you, so set its permeability high enough that it will never block ContactContractDisease()
|
||||
var/obj/item/I = parent
|
||||
old_permeability = I.permeability_coefficient
|
||||
I.permeability_coefficient = 1.01
|
||||
|
||||
try_infect(L, slot2body_zone(slot))
|
||||
|
||||
if(isitem(parent))
|
||||
var/obj/item/I = parent
|
||||
I.permeability_coefficient = old_permeability
|
||||
|
||||
/datum/component/infective/proc/try_infect_crossed(atom/movable/M)
|
||||
if(isliving(M))
|
||||
try_infect(M, BODY_ZONE_PRECISE_L_FOOT)
|
||||
|
||||
/datum/component/infective/proc/try_infect(mob/living/L, target_zone)
|
||||
for(var/V in diseases)
|
||||
L.ContactContractDisease(V, target_zone)
|
||||
|
||||
@@ -46,8 +46,12 @@
|
||||
|
||||
if(satiety>0 && prob(satiety/10)) // positive satiety makes it harder to contract the disease.
|
||||
return
|
||||
|
||||
//Lefts and rights do not matter for arms and legs, they both run the same checks
|
||||
if(!target_zone)
|
||||
target_zone = pick(head_ch;BODY_ZONE_HEAD,body_ch;"body",hands_ch;"hands",feet_ch;"feet")
|
||||
target_zone = pick(head_ch;BODY_ZONE_HEAD,body_ch;BODY_ZONE_CHEST,hands_ch;BODY_ZONE_L_ARM,feet_ch;BODY_ZONE_L_LEG)
|
||||
else
|
||||
target_zone = check_zone(target_zone)
|
||||
|
||||
if(ishuman(src))
|
||||
var/mob/living/carbon/human/H = src
|
||||
@@ -63,14 +67,14 @@
|
||||
if(passed && isobj(H.wear_neck))
|
||||
Cl = H.wear_neck
|
||||
passed = prob((Cl.permeability_coefficient*100) - 1)
|
||||
if("body")
|
||||
if(BODY_ZONE_CHEST)
|
||||
if(isobj(H.wear_suit))
|
||||
Cl = H.wear_suit
|
||||
passed = prob((Cl.permeability_coefficient*100) - 1)
|
||||
if(passed && isobj(slot_w_uniform))
|
||||
Cl = slot_w_uniform
|
||||
passed = prob((Cl.permeability_coefficient*100) - 1)
|
||||
if("hands")
|
||||
if(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM)
|
||||
if(isobj(H.wear_suit) && H.wear_suit.body_parts_covered&HANDS)
|
||||
Cl = H.wear_suit
|
||||
passed = prob((Cl.permeability_coefficient*100) - 1)
|
||||
@@ -78,7 +82,7 @@
|
||||
if(passed && isobj(H.gloves))
|
||||
Cl = H.gloves
|
||||
passed = prob((Cl.permeability_coefficient*100) - 1)
|
||||
if("feet")
|
||||
if(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
|
||||
if(isobj(H.wear_suit) && H.wear_suit.body_parts_covered&FEET)
|
||||
Cl = H.wear_suit
|
||||
passed = prob((Cl.permeability_coefficient*100) - 1)
|
||||
|
||||
@@ -400,7 +400,7 @@
|
||||
SSspacedrift.processing[src] = src
|
||||
return 1
|
||||
|
||||
/atom/movable/proc/throw_impact(atom/hit_atom, throwingdatum)
|
||||
/atom/movable/proc/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
|
||||
set waitfor = 0
|
||||
SendSignal(COMSIG_MOVABLE_IMPACT, hit_atom, throwingdatum)
|
||||
return hit_atom.hitby(src)
|
||||
|
||||
@@ -440,7 +440,6 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
|
||||
var/datum/action/A = X
|
||||
if(item_action_slot_check(slot, user)) //some items only give their actions buttons when in a specific slot.
|
||||
A.Grant(user)
|
||||
SendSignal(COMSIG_ITEM_EQUIPPED,user,slot)
|
||||
item_flags |= IN_INVENTORY
|
||||
|
||||
//sometimes we only want to grant the item's action if it's equipped in a specific slot.
|
||||
@@ -571,8 +570,9 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
|
||||
else
|
||||
return
|
||||
|
||||
/obj/item/throw_impact(atom/A)
|
||||
/obj/item/throw_impact(atom/A, datum/thrownthing/throwingdatum)
|
||||
if(A && !QDELETED(A))
|
||||
SendSignal(COMSIG_MOVABLE_IMPACT, A, throwingdatum)
|
||||
if(is_hot() && isliving(A))
|
||||
var/mob/living/L = A
|
||||
L.IgniteMob()
|
||||
|
||||
@@ -228,6 +228,7 @@
|
||||
return
|
||||
usr.visible_message("<span class='notice'>[usr] grabs \the [src.name].</span>", "<span class='notice'>You grab \the [src.name].</span>")
|
||||
var/C = new item_chair(loc)
|
||||
TransferComponents(C)
|
||||
usr.put_in_hands(C)
|
||||
qdel(src)
|
||||
|
||||
@@ -279,6 +280,7 @@
|
||||
|
||||
user.visible_message("<span class='notice'>[user] rights \the [src.name].</span>", "<span class='notice'>You right \the [name].</span>")
|
||||
var/obj/structure/chair/C = new origin_type(get_turf(loc))
|
||||
TransferComponents(C)
|
||||
C.setDir(dir)
|
||||
qdel(src)
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ is currently following.
|
||||
GLOBAL_LIST_INIT(disease_ability_singletons, list(
|
||||
new /datum/disease_ability/action/cough(),
|
||||
new /datum/disease_ability/action/sneeze(),
|
||||
new /datum/disease_ability/action/infect(),
|
||||
new /datum/disease_ability/symptom/cough(),
|
||||
new /datum/disease_ability/symptom/sneeze(),\
|
||||
new /datum/disease_ability/symptom/hallucigen(),
|
||||
@@ -165,7 +166,6 @@ GLOBAL_LIST_INIT(disease_ability_singletons, list(
|
||||
short_desc = "Force the host you are following to sneeze, spreading your infection to those in front of them."
|
||||
long_desc = "Force the host you are following to sneeze with extra force, spreading your infection to any victims in a 4 meter cone in front of your host.<br>Cooldown: 20 seconds"
|
||||
|
||||
|
||||
/datum/action/cooldown/disease_sneeze
|
||||
name = "Sneeze"
|
||||
icon_icon = 'icons/mob/actions/actions_minor_antag.dmi'
|
||||
@@ -194,6 +194,47 @@ GLOBAL_LIST_INIT(disease_ability_singletons, list(
|
||||
StartCooldown()
|
||||
return TRUE
|
||||
|
||||
|
||||
/datum/disease_ability/action/infect
|
||||
name = "Secrete Infection"
|
||||
actions = list(/datum/action/cooldown/disease_infect)
|
||||
cost = 2
|
||||
required_total_points = 3
|
||||
short_desc = "Cause all objects your host is touching to become infectious for a limited time, spreading your infection to anyone who touches them."
|
||||
long_desc = "Cause the host you are following to excrete an infective substance from their pores, causing all objects touching their skin to transmit your infection to anyone who touches them for the next 30 seconds. This includes the floor, if they are not wearing shoes, and any items they are holding, if they are not wearing gloves.<br>Cooldown: 40 seconds"
|
||||
|
||||
/datum/action/cooldown/disease_infect
|
||||
name = "Secrete Infection"
|
||||
icon_icon = 'icons/mob/actions/actions_minor_antag.dmi'
|
||||
button_icon_state = "infect"
|
||||
desc = "Cause the host you are following to excrete an infective substance from their pores, causing all objects touching their skin to transmit your infection to anyone who touches them for the next 30 seconds.<br>Cooldown: 40 seconds"
|
||||
cooldown_time = 400
|
||||
|
||||
/datum/action/cooldown/disease_infect/Trigger()
|
||||
if(!..())
|
||||
return FALSE
|
||||
var/mob/camera/disease/D = owner
|
||||
var/mob/living/carbon/human/H = D.following_host
|
||||
if(!H)
|
||||
return FALSE
|
||||
for(var/V in H.get_equipped_items(FALSE))
|
||||
var/obj/O = V
|
||||
O.AddComponent(/datum/component/infective, D.disease_template, 300)
|
||||
//no shoes? infect the floor.
|
||||
if(!H.shoes)
|
||||
var/turf/T = get_turf(H)
|
||||
if(T && !isspaceturf(T))
|
||||
T.AddComponent(/datum/component/infective, D.disease_template, 300)
|
||||
//no gloves? infect whatever we are holding.
|
||||
if(!H.gloves)
|
||||
for(var/V in H.held_items)
|
||||
if(!V)
|
||||
continue
|
||||
var/obj/O = V
|
||||
O.AddComponent(/datum/component/infective, D.disease_template, 300)
|
||||
StartCooldown()
|
||||
return TRUE
|
||||
|
||||
//passive symptom abilities
|
||||
|
||||
/datum/disease_ability/symptom/cough
|
||||
|
||||
@@ -37,20 +37,20 @@
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/proc/On_Consume()
|
||||
if(!usr)
|
||||
/obj/item/reagent_containers/food/snacks/proc/On_Consume(mob/living/eater)
|
||||
if(!eater)
|
||||
return
|
||||
if(!reagents.total_volume)
|
||||
var/obj/item/trash_item = generate_trash(usr)
|
||||
var/obj/item/trash_item = generate_trash(eater)
|
||||
qdel(src)
|
||||
usr.put_in_hands(trash_item)
|
||||
eater.put_in_hands(trash_item)
|
||||
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/attack_self(mob/user)
|
||||
return
|
||||
|
||||
|
||||
/obj/item/reagent_containers/food/snacks/attack(mob/living/M, mob/user, def_zone)
|
||||
/obj/item/reagent_containers/food/snacks/attack(mob/living/M, mob/living/user, def_zone)
|
||||
if(user.a_intent == INTENT_HARM)
|
||||
return ..()
|
||||
if(!eatverb)
|
||||
@@ -109,11 +109,12 @@
|
||||
M.satiety -= junkiness
|
||||
playsound(M.loc,'sound/items/eatfood.ogg', rand(10,50), 1)
|
||||
if(reagents.total_volume)
|
||||
SendSignal(COMSIG_FOOD_EATEN, M, user)
|
||||
var/fraction = min(bitesize / reagents.total_volume, 1)
|
||||
reagents.reaction(M, INGEST, fraction)
|
||||
reagents.trans_to(M, bitesize)
|
||||
bitecount++
|
||||
On_Consume()
|
||||
On_Consume(M)
|
||||
checkLiked(fraction, M)
|
||||
return 1
|
||||
|
||||
|
||||
@@ -75,6 +75,7 @@
|
||||
affecting = get_bodypart(ran_zone(user.zone_selected))
|
||||
if(!affecting) //missing limb? we select the first bodypart (you can never have zero, because of chest)
|
||||
affecting = bodyparts[1]
|
||||
I.SendSignal(COMSIG_ITEM_ATTACK_ZONE, src, user, affecting)
|
||||
send_item_attack_message(I, user, affecting.name)
|
||||
if(I.force)
|
||||
//CIT CHANGES START HERE - combatmode and resting checks
|
||||
|
||||
@@ -173,6 +173,8 @@
|
||||
affecting = get_bodypart(ran_zone(user.zone_selected))
|
||||
var/target_area = parse_zone(check_zone(user.zone_selected)) //our intended target
|
||||
|
||||
I.SendSignal(COMSIG_ITEM_ATTACK_ZONE, src, user, affecting)
|
||||
|
||||
SSblackbox.record_feedback("nested tally", "item_used_for_combat", 1, list("[I.force]", "[I.type]"))
|
||||
SSblackbox.record_feedback("tally", "zone_targeted", 1, target_area)
|
||||
|
||||
|
||||
@@ -67,6 +67,7 @@
|
||||
var/zone = ran_zone(BODY_ZONE_CHEST, 65)//Hits a random part of the body, geared towards the chest
|
||||
var/dtype = BRUTE
|
||||
var/volume = I.get_volume_by_throwforce_and_or_w_class()
|
||||
I.SendSignal(COMSIG_MOVABLE_IMPACT_ZONE, src, zone)
|
||||
dtype = I.damtype
|
||||
|
||||
if (I.throwforce > 0) //If the weapon's throwforce is greater than zero...
|
||||
|
||||
Reference in New Issue
Block a user