mirror of
https://github.com/SPLURT-Station/S.P.L.U.R.T-Station-13.git
synced 2025-12-09 16:07:40 +00:00
first port
This commit is contained in:
@@ -176,6 +176,14 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(
|
|||||||
#define EMBED_THROWSPEED_THRESHOLD 4 //The minimum value of an item's throw_speed for it to embed (Unless it has embedded_ignore_throwspeed_threshold set to 1)
|
#define EMBED_THROWSPEED_THRESHOLD 4 //The minimum value of an item's throw_speed for it to embed (Unless it has embedded_ignore_throwspeed_threshold set to 1)
|
||||||
#define EMBEDDED_UNSAFE_REMOVAL_PAIN_MULTIPLIER 8 //Coefficient of multiplication for the damage the item does when removed without a surgery (this*item.w_class)
|
#define EMBEDDED_UNSAFE_REMOVAL_PAIN_MULTIPLIER 8 //Coefficient of multiplication for the damage the item does when removed without a surgery (this*item.w_class)
|
||||||
#define EMBEDDED_UNSAFE_REMOVAL_TIME 150 //A Time in ticks, total removal time = (this/item.w_class)
|
#define EMBEDDED_UNSAFE_REMOVAL_TIME 150 //A Time in ticks, total removal time = (this/item.w_class)
|
||||||
|
#define EMBEDDED_JOSTLE_CHANCE 5 //Chance for embedded objects to cause pain every time they move (jostle)
|
||||||
|
#define EMBEDDED_JOSTLE_PAIN_MULTIPLIER 1 //Coefficient of multiplication for the damage the item does while
|
||||||
|
#define EMBEDDED_PAIN_STAM_PCT 0.0 //This percentage of all pain will be dealt as stam damage rather than brute (0-1)
|
||||||
|
|
||||||
|
#define EMBED_HARMLESS list("pain_mult" = 0, "jostle_pain_mult" = 0, "ignore_throwspeed_threshold" = TRUE)
|
||||||
|
#define EMBED_HARMLESS_SUPERIOR list("pain_mult" = 0, "jostle_pain_mult" = 0, "ignore_throwspeed_threshold" = TRUE, "embed_chance" = 100, "fall_chance" = 0.1)
|
||||||
|
#define EMBED_POINTY list("ignore_throwspeed_threshold" = TRUE)
|
||||||
|
#define EMBED_POINTY_SUPERIOR list("embed_chance" = 100, "ignore_throwspeed_threshold" = TRUE)
|
||||||
|
|
||||||
//Gun weapon weight
|
//Gun weapon weight
|
||||||
#define WEAPON_LIGHT 1
|
#define WEAPON_LIGHT 1
|
||||||
|
|||||||
@@ -26,6 +26,11 @@
|
|||||||
#define COMPONENT_ADD_TRAIT (1<<0)
|
#define COMPONENT_ADD_TRAIT (1<<0)
|
||||||
#define COMPONENT_REMOVE_TRAIT (1<<1)
|
#define COMPONENT_REMOVE_TRAIT (1<<1)
|
||||||
|
|
||||||
|
/// fires on the target datum when an element is attached to it (/datum/element)
|
||||||
|
#define COMSIG_ELEMENT_ATTACH "element_attach"
|
||||||
|
/// fires on the target datum when an element is attached to it (/datum/element)
|
||||||
|
#define COMSIG_ELEMENT_DETACH "element_detach"
|
||||||
|
|
||||||
// /atom signals
|
// /atom signals
|
||||||
#define COMSIG_PARENT_ATTACKBY "atom_attackby" //from base of atom/attackby(): (/obj/item, /mob/living, params)
|
#define COMSIG_PARENT_ATTACKBY "atom_attackby" //from base of atom/attackby(): (/obj/item, /mob/living, params)
|
||||||
#define COMPONENT_NO_AFTERATTACK 1 //Return this in response if you don't want afterattack to be called
|
#define COMPONENT_NO_AFTERATTACK 1 //Return this in response if you don't want afterattack to be called
|
||||||
@@ -314,6 +319,8 @@
|
|||||||
#define COMSIG_HUMAN_MELEE_UNARMED_ATTACK "human_melee_unarmed_attack" //from mob/living/carbon/human/UnarmedAttack(): (atom/target)
|
#define COMSIG_HUMAN_MELEE_UNARMED_ATTACK "human_melee_unarmed_attack" //from mob/living/carbon/human/UnarmedAttack(): (atom/target)
|
||||||
#define COMSIG_HUMAN_MELEE_UNARMED_ATTACKBY "human_melee_unarmed_attackby" //from mob/living/carbon/human/UnarmedAttack(): (mob/living/carbon/human/attacker)
|
#define COMSIG_HUMAN_MELEE_UNARMED_ATTACKBY "human_melee_unarmed_attackby" //from mob/living/carbon/human/UnarmedAttack(): (mob/living/carbon/human/attacker)
|
||||||
#define COMSIG_HUMAN_DISARM_HIT "human_disarm_hit" //Hit by successful disarm attack (mob/living/carbon/human/attacker,zone_targeted)
|
#define COMSIG_HUMAN_DISARM_HIT "human_disarm_hit" //Hit by successful disarm attack (mob/living/carbon/human/attacker,zone_targeted)
|
||||||
|
#define COMSIG_HUMAN_EMBED_RIP "item_embed_removing" // called on human when said human tries to rip out this embedded item (mob/living/carbon/human/target, /obj/item, /obj/item/bodypart/L)
|
||||||
|
#define COMSIG_HUMAN_EMBED_REMOVAL "item_embed_remove_surgery" // called on human from /datum/surgery_step/remove_object/success (mob/living/carbon/human/target, /obj/item, /obj/item/bodypart/L)
|
||||||
#define COMSIG_HUMAN_PREFS_COPIED_TO "human_prefs_copied_to" //from datum/preferences/copy_to(): (datum/preferences, icon_updates, roundstart_checks)
|
#define COMSIG_HUMAN_PREFS_COPIED_TO "human_prefs_copied_to" //from datum/preferences/copy_to(): (datum/preferences, icon_updates, roundstart_checks)
|
||||||
#define COMSIG_HUMAN_HARDSET_DNA "human_hardset_dna" //from mob/living/carbon/human/hardset_dna(): (ui, list/mutation_index, newreal_name, newblood_type, datum/species, newfeatures)
|
#define COMSIG_HUMAN_HARDSET_DNA "human_hardset_dna" //from mob/living/carbon/human/hardset_dna(): (ui, list/mutation_index, newreal_name, newblood_type, datum/species, newfeatures)
|
||||||
#define COMSIG_HUMAN_ON_RANDOMIZE "humman_on_randomize" //from base of proc/randomize_human()
|
#define COMSIG_HUMAN_ON_RANDOMIZE "humman_on_randomize" //from base of proc/randomize_human()
|
||||||
|
|||||||
@@ -295,3 +295,4 @@
|
|||||||
#define CLOWNOP_TRAIT "clown-op"
|
#define CLOWNOP_TRAIT "clown-op"
|
||||||
#define MEGAFAUNA_TRAIT "megafauna"
|
#define MEGAFAUNA_TRAIT "megafauna"
|
||||||
#define DEATHSQUAD_TRAIT "deathsquad"
|
#define DEATHSQUAD_TRAIT "deathsquad"
|
||||||
|
#define STICKY_NODROP "sticky-nodrop" //sticky nodrop sounds like a bad soundcloud rapper's name
|
||||||
|
|||||||
@@ -116,6 +116,7 @@ GLOBAL_LIST_INIT(maintenance_loot, list(
|
|||||||
/obj/item/autosurgeon/testicles = 1,
|
/obj/item/autosurgeon/testicles = 1,
|
||||||
/obj/item/storage/box/marshmallow = 2,
|
/obj/item/storage/box/marshmallow = 2,
|
||||||
/obj/item/clothing/gloves/tackler/offbrand = 1,
|
/obj/item/clothing/gloves/tackler/offbrand = 1,
|
||||||
|
/obj/item/stack/sticky_tape = 1,
|
||||||
"" = 3
|
"" = 3
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|||||||
319
code/datums/components/embedded.dm
Normal file
319
code/datums/components/embedded.dm
Normal file
@@ -0,0 +1,319 @@
|
|||||||
|
/*
|
||||||
|
This component is responsible for handling individual instances of embedded objects. The embeddable element is what allows an item to be embeddable and stores its embedding stats,
|
||||||
|
and when it impacts and meets the requirements to stick into something, it instantiates an embedded component. Once the item falls out, the component is destroyed, while the
|
||||||
|
element survives to embed another day.
|
||||||
|
|
||||||
|
There are 2 different things that can be embedded presently: humans, and closed turfs (see: walls)
|
||||||
|
|
||||||
|
- Human embedding has all the classical embedding behavior, and tracks more events and signals. The main behaviors and hooks to look for are:
|
||||||
|
-- Every process tick, there is a chance to randomly proc pain, controlled by pain_chance. There may also be a chance for the object to fall out randomly, per fall_chance
|
||||||
|
-- Every time the mob moves, there is a chance to proc jostling pain, controlled by jostle_chance (and only 50% as likely if the mob is walking or crawling)
|
||||||
|
-- Various signals hooking into human topic() and the embed removal surgery in order to handle removals
|
||||||
|
|
||||||
|
- Turf embedding is much simpler. All we do here is draw an overlay of the item's inhand on the turf, hide the item, and create an HTML link in the turf's inspect
|
||||||
|
that allows you to rip the item out. There's nothing dynamic about this, so far less checks.
|
||||||
|
|
||||||
|
In addition, there are 2 cases of embedding: embedding, and sticking
|
||||||
|
|
||||||
|
- Embedding involves harmful and dangerous embeds, whether they cause brute damage, stamina damage, or a mix. This is the default behavior for embeddings, for when something is "pointy"
|
||||||
|
|
||||||
|
- Sticking occurs when an item should not cause any harm while embedding (imagine throwing a sticky ball of tape at someone, rather than a shuriken). An item is considered "sticky"
|
||||||
|
when it has 0 for both pain multiplier and jostle pain multiplier. It's a bit arbitrary, but fairly straightforward.
|
||||||
|
|
||||||
|
Stickables differ from embeds in the following ways:
|
||||||
|
-- Text descriptors use phrasing like "X is stuck to Y" rather than "X is embedded in Y"
|
||||||
|
-- There is no slicing sound on impact
|
||||||
|
-- All damage checks and bloodloss are skipped for humans
|
||||||
|
-- Pointy objects create sparks when embedding into a turf
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/datum/component/embedded
|
||||||
|
dupe_mode = COMPONENT_DUPE_ALLOWED
|
||||||
|
var/obj/item/bodypart/L
|
||||||
|
var/obj/item/weapon
|
||||||
|
|
||||||
|
// all of this stuff is explained in _DEFINES/combat.dm
|
||||||
|
var/embed_chance // not like we really need it once we're already stuck in but hey
|
||||||
|
var/fall_chance
|
||||||
|
var/pain_chance
|
||||||
|
var/pain_mult
|
||||||
|
var/impact_pain_mult
|
||||||
|
var/remove_pain_mult
|
||||||
|
var/rip_time
|
||||||
|
var/ignore_throwspeed_threshold
|
||||||
|
var/jostle_chance
|
||||||
|
var/jostle_pain_mult
|
||||||
|
var/pain_stam_pct
|
||||||
|
|
||||||
|
///if both our pain multiplier and jostle pain multiplier are 0, we're harmless and can omit most of the damage related stuff
|
||||||
|
var/harmful
|
||||||
|
var/mutable_appearance/overlay
|
||||||
|
|
||||||
|
/datum/component/embedded/Initialize(obj/item/I,
|
||||||
|
datum/thrownthing/throwingdatum,
|
||||||
|
embed_chance = EMBED_CHANCE,
|
||||||
|
fall_chance = EMBEDDED_ITEM_FALLOUT,
|
||||||
|
pain_chance = EMBEDDED_PAIN_CHANCE,
|
||||||
|
pain_mult = EMBEDDED_PAIN_MULTIPLIER,
|
||||||
|
remove_pain_mult = EMBEDDED_UNSAFE_REMOVAL_PAIN_MULTIPLIER,
|
||||||
|
impact_pain_mult = EMBEDDED_IMPACT_PAIN_MULTIPLIER,
|
||||||
|
rip_time = EMBEDDED_UNSAFE_REMOVAL_TIME,
|
||||||
|
ignore_throwspeed_threshold = FALSE,
|
||||||
|
jostle_chance = EMBEDDED_JOSTLE_CHANCE,
|
||||||
|
jostle_pain_mult = EMBEDDED_JOSTLE_PAIN_MULTIPLIER,
|
||||||
|
pain_stam_pct = EMBEDDED_PAIN_STAM_PCT)
|
||||||
|
|
||||||
|
if((!ishuman(parent) && !isclosedturf(parent)) || !isitem(I))
|
||||||
|
return COMPONENT_INCOMPATIBLE
|
||||||
|
|
||||||
|
src.embed_chance = embed_chance
|
||||||
|
src.fall_chance = fall_chance
|
||||||
|
src.pain_chance = pain_chance
|
||||||
|
src.pain_mult = pain_mult
|
||||||
|
src.remove_pain_mult = remove_pain_mult
|
||||||
|
src.rip_time = rip_time
|
||||||
|
src.impact_pain_mult = impact_pain_mult
|
||||||
|
src.ignore_throwspeed_threshold = ignore_throwspeed_threshold
|
||||||
|
src.jostle_chance = jostle_chance
|
||||||
|
src.jostle_pain_mult = jostle_pain_mult
|
||||||
|
src.pain_stam_pct = pain_stam_pct
|
||||||
|
|
||||||
|
src.weapon = I
|
||||||
|
|
||||||
|
if(src.pain_mult || src.jostle_pain_mult)
|
||||||
|
harmful = TRUE
|
||||||
|
if(ishuman(parent))
|
||||||
|
initHuman()
|
||||||
|
else if(isclosedturf(parent))
|
||||||
|
initTurf(throwingdatum)
|
||||||
|
|
||||||
|
/datum/component/embedded/RegisterWithParent()
|
||||||
|
if(ishuman(parent))
|
||||||
|
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/jostleCheck)
|
||||||
|
RegisterSignal(parent, COMSIG_HUMAN_EMBED_RIP, .proc/ripOutHuman)
|
||||||
|
RegisterSignal(parent, COMSIG_HUMAN_EMBED_REMOVAL, .proc/safeRemoveHuman)
|
||||||
|
else if(isclosedturf(parent))
|
||||||
|
RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/examineTurf)
|
||||||
|
|
||||||
|
/datum/component/embedded/UnregisterFromParent()
|
||||||
|
if(ishuman(parent))
|
||||||
|
UnregisterSignal(parent, list(COMSIG_MOVABLE_MOVED, COMSIG_HUMAN_EMBED_RIP, COMSIG_HUMAN_EMBED_REMOVAL))
|
||||||
|
else if(isclosedturf(parent))
|
||||||
|
UnregisterSignal(parent, COMSIG_PARENT_EXAMINE)
|
||||||
|
|
||||||
|
/datum/component/embedded/process()
|
||||||
|
if(ishuman(parent))
|
||||||
|
processHuman()
|
||||||
|
|
||||||
|
/datum/component/embedded/Destroy()
|
||||||
|
if(overlay)
|
||||||
|
var/atom/A = parent
|
||||||
|
A.cut_overlay(overlay, TRUE)
|
||||||
|
qdel(overlay)
|
||||||
|
|
||||||
|
return ..()
|
||||||
|
|
||||||
|
////////////////////////////////////////
|
||||||
|
/////////////HUMAN PROCS////////////////
|
||||||
|
////////////////////////////////////////
|
||||||
|
|
||||||
|
/// Set up an instance of embedding for a human. This is basically an extension of Initialize() so not much to say
|
||||||
|
/datum/component/embedded/proc/initHuman()
|
||||||
|
START_PROCESSING(SSdcs, src)
|
||||||
|
var/mob/living/carbon/human/victim = parent
|
||||||
|
L = pick(victim.bodyparts)
|
||||||
|
L.embedded_objects |= weapon // on the inside... on the inside...
|
||||||
|
weapon.forceMove(victim)
|
||||||
|
|
||||||
|
if(harmful)
|
||||||
|
victim.visible_message("<span class='danger'>[weapon] embeds itself in [victim]'s [L.name]!</span>","<span class='userdanger'>[weapon] embeds itself in your [L.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
|
||||||
|
L.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage)
|
||||||
|
SEND_SIGNAL(victim, COMSIG_ADD_MOOD_EVENT, "embedded", /datum/mood_event/embedded)
|
||||||
|
else
|
||||||
|
victim.visible_message("<span class='danger'>[weapon] sticks itself to [victim]'s [L.name]!</span>","<span class='userdanger'>[weapon] sticks itself to your [L.name]!</span>")
|
||||||
|
|
||||||
|
|
||||||
|
/// Called every time a human with a harmful embed moves, rolling a chance for the item to cause pain. The chance is halved if the human is crawling or walking.
|
||||||
|
/datum/component/embedded/proc/jostleCheck()
|
||||||
|
var/mob/living/carbon/human/victim = parent
|
||||||
|
|
||||||
|
var/chance = jostle_chance
|
||||||
|
if(victim.m_intent == MOVE_INTENT_WALK || victim.lying)
|
||||||
|
chance *= 0.5
|
||||||
|
|
||||||
|
if(prob(chance))
|
||||||
|
var/damage = weapon.w_class * jostle_pain_mult
|
||||||
|
L.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage)
|
||||||
|
to_chat(victim, "<span class='userdanger'>[weapon] embedded in your [L.name] jostles and stings!</span>")
|
||||||
|
|
||||||
|
|
||||||
|
/// Called when then item randomly falls out of a human. This handles the damage and descriptors, then calls safe_remove()
|
||||||
|
/datum/component/embedded/proc/fallOutHuman()
|
||||||
|
var/mob/living/carbon/human/victim = parent
|
||||||
|
|
||||||
|
if(harmful)
|
||||||
|
var/damage = weapon.w_class * remove_pain_mult
|
||||||
|
L.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage)
|
||||||
|
victim.visible_message("<span class='danger'>[weapon] falls out of [victim.name]'s [L.name]!</span>","<span class='userdanger'>[weapon] falls out of your [L.name]!</span>")
|
||||||
|
else
|
||||||
|
victim.visible_message("<span class='danger'>[weapon] falls off of [victim.name]'s [L.name]!</span>","<span class='userdanger'>[weapon] falls off of your [L.name]!</span>")
|
||||||
|
|
||||||
|
safeRemoveHuman()
|
||||||
|
|
||||||
|
|
||||||
|
/// Called when a human with an object embedded/stuck to them inspects themselves and clicks the appropriate link to begin ripping the item out. This handles the ripping attempt, descriptors, and dealing damage, then calls safe_remove()
|
||||||
|
/datum/component/embedded/proc/ripOutHuman()
|
||||||
|
var/mob/living/carbon/human/victim = parent
|
||||||
|
var/time_taken = rip_time * weapon.w_class
|
||||||
|
|
||||||
|
victim.visible_message("<span class='warning'>[victim] attempts to remove [weapon] from [victim.p_their()] [L.name].</span>","<span class='notice'>You attempt to remove [weapon] from your [L.name]... (It will take [DisplayTimeText(time_taken)].)</span>")
|
||||||
|
if(do_after(victim, time_taken, target = victim))
|
||||||
|
if(!weapon || !L || weapon.loc != victim || !(weapon in L.embedded_objects))
|
||||||
|
qdel(src)
|
||||||
|
|
||||||
|
if(harmful)
|
||||||
|
var/damage = weapon.w_class * remove_pain_mult
|
||||||
|
L.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage) //It hurts to rip it out, get surgery you dingus.
|
||||||
|
victim.emote("scream")
|
||||||
|
victim.visible_message("<span class='notice'>[victim] successfully rips [weapon] out of [victim.p_their()] [L.name]!</span>", "<span class='notice'>You successfully remove [weapon] from your [L.name].</span>")
|
||||||
|
else
|
||||||
|
victim.visible_message("<span class='notice'>[victim] successfully rips [weapon] off of [victim.p_their()] [L.name]!</span>", "<span class='notice'>You successfully remove [weapon] from your [L.name].</span>")
|
||||||
|
|
||||||
|
safeRemoveHuman(TRUE)
|
||||||
|
|
||||||
|
|
||||||
|
/// This proc handles the final step and actual removal of an embedded/stuck item from a human, whether or not it was actually removed safely.
|
||||||
|
/// Pass TRUE for to_hands if we want it to go to the victim's hands when they pull it out
|
||||||
|
/datum/component/embedded/proc/safeRemoveHuman(to_hands)
|
||||||
|
var/mob/living/carbon/human/victim = parent
|
||||||
|
L.embedded_objects -= weapon
|
||||||
|
|
||||||
|
if(!victim)
|
||||||
|
weapon.forceMove(get_turf(weapon))
|
||||||
|
qdel(src)
|
||||||
|
|
||||||
|
if(to_hands)
|
||||||
|
victim.put_in_hands(weapon)
|
||||||
|
else
|
||||||
|
weapon.forceMove(get_turf(victim))
|
||||||
|
|
||||||
|
if(!victim.has_embedded_objects())
|
||||||
|
victim.clear_alert("embeddedobject")
|
||||||
|
SEND_SIGNAL(victim, COMSIG_CLEAR_MOOD_EVENT, "embedded")
|
||||||
|
qdel(src)
|
||||||
|
|
||||||
|
|
||||||
|
/// Items embedded/stuck to humans both check whether they randomly fall out (if applicable), as well as if the target mob and limb still exists.
|
||||||
|
/// Items harmfully embedded in humans have an additional check for random pain (if applicable)
|
||||||
|
/datum/component/embedded/proc/processHuman()
|
||||||
|
var/mob/living/carbon/human/victim = parent
|
||||||
|
|
||||||
|
if(!victim || !L) // in case the victim and/or their limbs exploded (say, due to a sticky bomb)
|
||||||
|
weapon.forceMove(get_turf(weapon))
|
||||||
|
qdel(src)
|
||||||
|
|
||||||
|
if(victim.stat == DEAD)
|
||||||
|
return
|
||||||
|
|
||||||
|
if(harmful && prob(pain_chance))
|
||||||
|
var/damage = weapon.w_class * pain_mult
|
||||||
|
L.receive_damage(brute=(1-pain_stam_pct) * damage, stamina=pain_stam_pct * damage)
|
||||||
|
to_chat(victim, "<span class='userdanger'>[weapon] embedded in your [L.name] hurts!</span>")
|
||||||
|
|
||||||
|
if(prob(fall_chance))
|
||||||
|
fallOutHuman()
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////
|
||||||
|
//////////////TURF PROCS////////////////
|
||||||
|
////////////////////////////////////////
|
||||||
|
|
||||||
|
/// Turfs are much lower maintenance, since we don't care if they're in pain, but since they don't bleed or scream, we draw an overlay to show their status.
|
||||||
|
/// The only difference pointy/sticky items make here is text descriptors and pointy objects making a spark shower on impact.
|
||||||
|
/datum/component/embedded/proc/initTurf(datum/thrownthing/throwingdatum)
|
||||||
|
var/turf/closed/hit = parent
|
||||||
|
|
||||||
|
// we can't store the item IN the turf (cause turfs are just kinda... there), so we fake it by making the item invisible and bailing if it moves due to a blast
|
||||||
|
weapon.forceMove(hit)
|
||||||
|
weapon.invisibility = INVISIBILITY_ABSTRACT
|
||||||
|
RegisterSignal(weapon, COMSIG_MOVABLE_MOVED, .proc/itemMoved)
|
||||||
|
|
||||||
|
var/pixelX = rand(-2, 2)
|
||||||
|
var/pixelY = rand(-1, 3) // bias this upwards since in-hands are usually on the lower end of the sprite
|
||||||
|
|
||||||
|
switch(throwingdatum.init_dir)
|
||||||
|
if(NORTH)
|
||||||
|
pixelY -= 2
|
||||||
|
if(SOUTH)
|
||||||
|
pixelY += 2
|
||||||
|
if(WEST)
|
||||||
|
pixelX += 2
|
||||||
|
if(EAST)
|
||||||
|
pixelX -= 2
|
||||||
|
|
||||||
|
if(throwingdatum.init_dir in list(NORTH, WEST, NORTHWEST, SOUTHWEST))
|
||||||
|
overlay = mutable_appearance(icon=weapon.righthand_file,icon_state=weapon.item_state)
|
||||||
|
else
|
||||||
|
overlay = mutable_appearance(icon=weapon.lefthand_file,icon_state=weapon.item_state)
|
||||||
|
|
||||||
|
var/matrix/M = matrix()
|
||||||
|
M.Translate(pixelX, pixelY)
|
||||||
|
overlay.transform = M
|
||||||
|
hit.add_overlay(overlay, TRUE)
|
||||||
|
|
||||||
|
if(harmful)
|
||||||
|
hit.visible_message("<span class='danger'>[weapon] embeds itself in [hit]!</span>")
|
||||||
|
playsound(hit,'sound/weapons/bladeslice.ogg', 70)
|
||||||
|
|
||||||
|
var/datum/effect_system/spark_spread/sparks = new
|
||||||
|
sparks.set_up(1, 1, parent)
|
||||||
|
sparks.attach(parent)
|
||||||
|
sparks.start()
|
||||||
|
else
|
||||||
|
hit.visible_message("<span class='danger'>[weapon] sticks itself to [hit]!</span>")
|
||||||
|
|
||||||
|
|
||||||
|
/datum/component/embedded/proc/examineTurf(datum/source, mob/user, list/examine_list)
|
||||||
|
if(harmful)
|
||||||
|
examine_list += "\t <a href='?src=[REF(src)];embedded_object=[REF(weapon)]' class='warning'>There is \a [weapon] embedded in [parent]!</a>"
|
||||||
|
else
|
||||||
|
examine_list += "\t <a href='?src=[REF(src)];embedded_object=[REF(weapon)]' class='warning'>There is \a [weapon] stuck to [parent]!</a>"
|
||||||
|
|
||||||
|
|
||||||
|
/// Someone is ripping out the item from the turf by hand
|
||||||
|
/datum/component/embedded/Topic(datum/source, href_list)
|
||||||
|
var/mob/living/us = usr
|
||||||
|
if(in_range(us, parent) && locate(href_list["embedded_object"]) == weapon)
|
||||||
|
if(harmful)
|
||||||
|
us.visible_message("<span class='notice'>[us] begins unwedging [weapon] from [parent].</span>", "<span class='notice'>You begin unwedging [weapon] from [parent]...</span>")
|
||||||
|
else
|
||||||
|
us.visible_message("<span class='notice'>[us] begins unsticking [weapon] from [parent].</span>", "<span class='notice'>You begin unsticking [weapon] from [parent]...</span>")
|
||||||
|
|
||||||
|
if(do_after(us, 30, target = parent))
|
||||||
|
us.put_in_hands(weapon)
|
||||||
|
qdel(src)
|
||||||
|
|
||||||
|
|
||||||
|
/// This proc handles if something knocked the invisible item loose from the turf somehow (probably an explosion). Just make it visible and say it fell loose, then get outta here.
|
||||||
|
/datum/component/embedded/proc/itemMoved()
|
||||||
|
weapon.invisibility = initial(weapon.invisibility)
|
||||||
|
weapon.visible_message("<span class='notice'>[weapon] falls loose from [parent].</span>")
|
||||||
|
qdel(src)
|
||||||
|
SHOULD_CALL_PARENT(1)
|
||||||
|
if(type == /datum/element)
|
||||||
|
return ELEMENT_INCOMPATIBLE
|
||||||
|
SEND_SIGNAL(target, COMSIG_ELEMENT_ATTACH, src)
|
||||||
|
if(element_flags & ELEMENT_DETACH)
|
||||||
|
RegisterSignal(target, COMSIG_PARENT_QDELETING, .proc/Detach, override = TRUE)
|
||||||
|
|
||||||
|
/// Deactivates the functionality defines by the element on the given datum
|
||||||
|
/datum/element/proc/Detach(datum/source, force)
|
||||||
|
SEND_SIGNAL(source, COMSIG_ELEMENT_DETACH, src)
|
||||||
|
SHOULD_CALL_PARENT(1)
|
||||||
|
UnregisterSignal(source, COMSIG_PARENT_QDELETING)
|
||||||
128
code/datums/elements/embed.dm
Normal file
128
code/datums/elements/embed.dm
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
The presence of this element allows an item to embed itself in a human or turf when it is thrown into a target (whether by hand, gun, or explosive wave)
|
||||||
|
with either at least 4 throwspeed (EMBED_THROWSPEED_THRESHOLD) or ignore_throwspeed_threshold set to TRUE.
|
||||||
|
|
||||||
|
This element is granted primarily to any /obj/item that has something in its /embedding var, which should be formatted as a list. If you wish to be able to
|
||||||
|
grant/rescind the ability for an item to embed (say, when activating and deactivating an edagger), you can do so in two ways:
|
||||||
|
|
||||||
|
1. Drop the throw_speed var below EMBED_THROWSPEED_THRESHOLD (object will still be able to otherwise embed if thrown at high speed by something else like a blast)
|
||||||
|
2. Add/Remove the embed element as needed (won't be able to embed at all)
|
||||||
|
|
||||||
|
Otherwise non-embeddable or stickable items can be made embeddable/stickable through wizard events/sticky tape/admin memes.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define STANDARD_WALL_HARDNESS 40
|
||||||
|
|
||||||
|
/datum/element/embed
|
||||||
|
element_flags = ELEMENT_BESPOKE
|
||||||
|
id_arg_index = 2
|
||||||
|
|
||||||
|
// all of this stuff is explained in _DEFINES/combat.dm
|
||||||
|
var/embed_chance
|
||||||
|
var/fall_chance
|
||||||
|
var/pain_chance
|
||||||
|
var/pain_mult
|
||||||
|
var/remove_pain_mult
|
||||||
|
var/impact_pain_mult
|
||||||
|
var/rip_time
|
||||||
|
var/ignore_throwspeed_threshold
|
||||||
|
var/jostle_chance
|
||||||
|
var/jostle_pain_mult
|
||||||
|
var/pain_stam_pct
|
||||||
|
|
||||||
|
/datum/element/embed/Attach(datum/target, list/embedArgs)
|
||||||
|
. = ..()
|
||||||
|
parseArgs(arglist(embedArgs))
|
||||||
|
|
||||||
|
if(!isitem(target))
|
||||||
|
return ELEMENT_INCOMPATIBLE
|
||||||
|
|
||||||
|
RegisterSignal(target, COMSIG_MOVABLE_IMPACT_ZONE, .proc/checkEmbedMob)
|
||||||
|
RegisterSignal(target, COMSIG_MOVABLE_IMPACT, .proc/checkEmbedOther)
|
||||||
|
RegisterSignal(target, COMSIG_ELEMENT_ATTACH, .proc/severancePackage)
|
||||||
|
RegisterSignal(target, COMSIG_PARENT_EXAMINE, .proc/examined)
|
||||||
|
|
||||||
|
/datum/element/embed/Detach(obj/item/target)
|
||||||
|
. = ..()
|
||||||
|
UnregisterSignal(target, list(COMSIG_MOVABLE_IMPACT_ZONE, COMSIG_ELEMENT_ATTACH, COMSIG_MOVABLE_IMPACT, COMSIG_PARENT_EXAMINE))
|
||||||
|
|
||||||
|
/// Checking to see if we're gonna embed into a human
|
||||||
|
/datum/element/embed/proc/checkEmbedMob(obj/item/weapon, mob/living/carbon/human/victim, hit_zone, datum/thrownthing/throwingdatum)
|
||||||
|
if(!istype(victim))
|
||||||
|
return
|
||||||
|
|
||||||
|
if((((throwingdatum ? throwingdatum.speed : weapon.throw_speed) >= EMBED_THROWSPEED_THRESHOLD) || ignore_throwspeed_threshold) && prob(embed_chance) && !HAS_TRAIT(victim, TRAIT_PIERCEIMMUNE))
|
||||||
|
victim.AddComponent(/datum/component/embedded,\
|
||||||
|
weapon,\
|
||||||
|
throwingdatum,\
|
||||||
|
embed_chance = embed_chance,\
|
||||||
|
fall_chance = fall_chance,\
|
||||||
|
pain_chance = pain_chance,\
|
||||||
|
pain_mult = pain_mult,\
|
||||||
|
remove_pain_mult = remove_pain_mult,\
|
||||||
|
rip_time = rip_time,\
|
||||||
|
ignore_throwspeed_threshold = ignore_throwspeed_threshold,\
|
||||||
|
jostle_chance = jostle_chance,\
|
||||||
|
jostle_pain_mult = jostle_pain_mult,\
|
||||||
|
pain_stam_pct = pain_stam_pct)
|
||||||
|
|
||||||
|
/// We need the hit_zone if we're embedding into a human, so this proc only handled if we're embedding into a turf
|
||||||
|
/datum/element/embed/proc/checkEmbedOther(obj/item/weapon, turf/closed/hit, datum/thrownthing/throwingdatum)
|
||||||
|
if(!istype(hit))
|
||||||
|
return
|
||||||
|
|
||||||
|
var/chance = embed_chance
|
||||||
|
if(iswallturf(hit))
|
||||||
|
var/turf/closed/wall/W = hit
|
||||||
|
chance += 2 * (W.hardness - STANDARD_WALL_HARDNESS)
|
||||||
|
|
||||||
|
if((((throwingdatum ? throwingdatum.speed : weapon.throw_speed) >= EMBED_THROWSPEED_THRESHOLD) || ignore_throwspeed_threshold) && prob(chance))
|
||||||
|
hit.AddComponent(/datum/component/embedded,\
|
||||||
|
weapon,\
|
||||||
|
throwingdatum,\
|
||||||
|
embed_chance = embed_chance,\
|
||||||
|
fall_chance = fall_chance,\
|
||||||
|
pain_chance = pain_chance,\
|
||||||
|
pain_mult = pain_mult,\
|
||||||
|
remove_pain_mult = remove_pain_mult,\
|
||||||
|
rip_time = rip_time,\
|
||||||
|
ignore_throwspeed_threshold = ignore_throwspeed_threshold,\
|
||||||
|
jostle_chance = jostle_chance,\
|
||||||
|
jostle_pain_mult = jostle_pain_mult,\
|
||||||
|
pain_stam_pct = pain_stam_pct)
|
||||||
|
|
||||||
|
/datum/element/embed/proc/parseArgs(embed_chance = EMBED_CHANCE,
|
||||||
|
fall_chance = EMBEDDED_ITEM_FALLOUT,
|
||||||
|
pain_chance = EMBEDDED_PAIN_CHANCE,
|
||||||
|
pain_mult = EMBEDDED_PAIN_MULTIPLIER,
|
||||||
|
remove_pain_mult = EMBEDDED_UNSAFE_REMOVAL_PAIN_MULTIPLIER,
|
||||||
|
rip_time = EMBEDDED_UNSAFE_REMOVAL_TIME,
|
||||||
|
impact_pain_mult = EMBEDDED_IMPACT_PAIN_MULTIPLIER,
|
||||||
|
ignore_throwspeed_threshold = FALSE,
|
||||||
|
jostle_chance = EMBEDDED_JOSTLE_CHANCE,
|
||||||
|
jostle_pain_mult = EMBEDDED_JOSTLE_PAIN_MULTIPLIER,
|
||||||
|
pain_stam_pct = EMBEDDED_PAIN_STAM_PCT)
|
||||||
|
|
||||||
|
src.embed_chance = embed_chance
|
||||||
|
src.fall_chance = fall_chance
|
||||||
|
src.pain_chance = pain_chance
|
||||||
|
src.pain_mult = pain_mult
|
||||||
|
src.remove_pain_mult = remove_pain_mult
|
||||||
|
src.impact_pain_mult = impact_pain_mult
|
||||||
|
src.rip_time = rip_time
|
||||||
|
src.ignore_throwspeed_threshold = ignore_throwspeed_threshold
|
||||||
|
src.jostle_chance = jostle_chance
|
||||||
|
src.jostle_pain_mult = jostle_pain_mult
|
||||||
|
src.pain_stam_pct = pain_stam_pct
|
||||||
|
|
||||||
|
///A different embed element has been attached, so we'll detach and let them handle things
|
||||||
|
/datum/element/embed/proc/severancePackage(obj/item/weapon, datum/element/E)
|
||||||
|
if(istype(E, /datum/element/embed))
|
||||||
|
Detach(weapon)
|
||||||
|
|
||||||
|
/datum/element/embed/proc/examined(obj/item/I, mob/user, list/examine_list)
|
||||||
|
if(!pain_mult && !jostle_pain_mult)
|
||||||
|
examine_list += "[I] feels sticky, and could probably get stuck to someone if thrown properly!"
|
||||||
|
else
|
||||||
|
examine_list += "[I] has a fine point, and could probably embed in someone if thrown properly!"
|
||||||
@@ -1,53 +1,73 @@
|
|||||||
#define EMBEDID "embed-[embed_chance]-[embedded_fall_chance]-[embedded_pain_chance]-[embedded_pain_multiplier]-[embedded_fall_pain_multiplier]-[embedded_impact_pain_multiplier]-[embedded_unsafe_removal_pain_multiplier]-[embedded_unsafe_removal_time]"
|
#define EMBEDID "embed-[embed_chance]-[fall_chance]-[pain_chance]-[pain_mult]-[fall_pain_mult]-[impact_pain_mult]-[rip_pain_mult]-[rip_time]-[ignore_throwspeed_threshold]-[jostle_chance]-[jostle_pain_mult]-[pain_stam_pct]"
|
||||||
|
|
||||||
/proc/getEmbeddingBehavior(embed_chance = EMBED_CHANCE,
|
/proc/getEmbeddingBehavior(embed_chance = EMBED_CHANCE,
|
||||||
embedded_fall_chance = EMBEDDED_ITEM_FALLOUT,
|
fall_chance = EMBEDDED_ITEM_FALLOUT,
|
||||||
embedded_pain_chance = EMBEDDED_PAIN_CHANCE,
|
pain_chance = EMBEDDED_PAIN_CHANCE,
|
||||||
embedded_pain_multiplier = EMBEDDED_PAIN_MULTIPLIER,
|
pain_mult = EMBEDDED_PAIN_MULTIPLIER,
|
||||||
embedded_fall_pain_multiplier = EMBEDDED_FALL_PAIN_MULTIPLIER,
|
fall_pain_mult = EMBEDDED_FALL_PAIN_MULTIPLIER,
|
||||||
embedded_impact_pain_multiplier = EMBEDDED_IMPACT_PAIN_MULTIPLIER,
|
impact_pain_mult = EMBEDDED_IMPACT_PAIN_MULTIPLIER,
|
||||||
embedded_unsafe_removal_pain_multiplier = EMBEDDED_UNSAFE_REMOVAL_PAIN_MULTIPLIER,
|
rip_pain_mult = EMBEDDED_UNSAFE_REMOVAL_PAIN_MULTIPLIER,
|
||||||
embedded_unsafe_removal_time = EMBEDDED_UNSAFE_REMOVAL_TIME)
|
rip_time = EMBEDDED_UNSAFE_REMOVAL_TIME,
|
||||||
|
ignore_throwspeed_threshold = FALSE,
|
||||||
|
jostle_chance = EMBEDDED_JOSTLE_CHANCE,
|
||||||
|
jostle_pain_mult = EMBEDDED_JOSTLE_PAIN_MULTIPLIER,
|
||||||
|
pain_stam_pct = EMBEDDED_PAIN_STAM_PCT)
|
||||||
|
|
||||||
. = locate(EMBEDID)
|
. = locate(EMBEDID)
|
||||||
if (!.)
|
if (!.)
|
||||||
. = new /datum/embedding_behavior(embed_chance, embedded_fall_chance, embedded_pain_chance, embedded_pain_multiplier, embedded_fall_pain_multiplier, embedded_impact_pain_multiplier, embedded_unsafe_removal_pain_multiplier, embedded_unsafe_removal_time)
|
. = new /datum/embedding_behavior(embed_chance, fall_chance, pain_chance, pain_mult, fall_pain_mult, impact_pain_mult, rip_pain_mult, rip_time, ignore_throwspeed_threshold, jostle_chance, jostle_pain_mult, pain_stam_pct)
|
||||||
|
|
||||||
/datum/embedding_behavior
|
/datum/embedding_behavior
|
||||||
var/embed_chance
|
var/fall_chance
|
||||||
var/embedded_fall_chance
|
var/pain_chance
|
||||||
var/embedded_pain_chance
|
var/pain_mult //The coefficient of multiplication for the damage this item does while embedded (this*w_class)
|
||||||
var/embedded_pain_multiplier //The coefficient of multiplication for the damage this item does while embedded (this*w_class)
|
var/fall_pain_mult //The coefficient of multiplication for the damage this item does when falling out of a limb (this*w_class)
|
||||||
var/embedded_fall_pain_multiplier //The coefficient of multiplication for the damage this item does when falling out of a limb (this*w_class)
|
var/impact_pain_mult //The coefficient of multiplication for the damage this item does when first embedded (this*w_class)
|
||||||
var/embedded_impact_pain_multiplier //The coefficient of multiplication for the damage this item does when first embedded (this*w_class)
|
var/rip_pain_mult //The coefficient of multiplication for the damage removing this without surgery causes (this*w_class)
|
||||||
var/embedded_unsafe_removal_pain_multiplier //The coefficient of multiplication for the damage removing this without surgery causes (this*w_class)
|
var/rip_time //A time in ticks, multiplied by the w_class.
|
||||||
var/embedded_unsafe_removal_time //A time in ticks, multiplied by the w_class.
|
var/ignore_throwspeed_threshold //if we don't give a damn about EMBED_THROWSPEED_THRESHOLD
|
||||||
|
var/jostle_chance //Chance to cause pain every time the victim moves (1/2 chance if they're walking or crawling)
|
||||||
|
var/jostle_pain_mult //The coefficient of multiplication for the damage when jostle damage is applied (this*w_class)
|
||||||
|
var/pain_stam_pct //Percentage of all pain damage dealt as stamina instead of brute (none by default)
|
||||||
|
|
||||||
/datum/embedding_behavior/New(embed_chance = EMBED_CHANCE,
|
/datum/embedding_behavior/New(embed_chance = EMBED_CHANCE,
|
||||||
embedded_fall_chance = EMBEDDED_ITEM_FALLOUT,
|
fall_chance = EMBEDDED_ITEM_FALLOUT,
|
||||||
embedded_pain_chance = EMBEDDED_PAIN_CHANCE,
|
pain_chance = EMBEDDED_PAIN_CHANCE,
|
||||||
embedded_pain_multiplier = EMBEDDED_PAIN_MULTIPLIER,
|
pain_mult = EMBEDDED_PAIN_MULTIPLIER,
|
||||||
embedded_fall_pain_multiplier = EMBEDDED_FALL_PAIN_MULTIPLIER,
|
fall_pain_mult = EMBEDDED_FALL_PAIN_MULTIPLIER,
|
||||||
embedded_impact_pain_multiplier = EMBEDDED_IMPACT_PAIN_MULTIPLIER,
|
impact_pain_mult = EMBEDDED_IMPACT_PAIN_MULTIPLIER,
|
||||||
embedded_unsafe_removal_pain_multiplier = EMBEDDED_UNSAFE_REMOVAL_PAIN_MULTIPLIER,
|
rip_pain_mult = EMBEDDED_UNSAFE_REMOVAL_PAIN_MULTIPLIER,
|
||||||
embedded_unsafe_removal_time = EMBEDDED_UNSAFE_REMOVAL_TIME)
|
rip_time = EMBEDDED_UNSAFE_REMOVAL_TIME,
|
||||||
|
ignore_throwspeed_threshold = FALSE,
|
||||||
|
jostle_chance = EMBEDDED_JOSTLE_CHANCE,
|
||||||
|
jostle_pain_mult = EMBEDDED_JOSTLE_PAIN_MULTIPLIER,
|
||||||
|
pain_stam_pct = EMBEDDED_PAIN_STAM_PCT)
|
||||||
src.embed_chance = embed_chance
|
src.embed_chance = embed_chance
|
||||||
src.embedded_fall_chance = embedded_fall_chance
|
src.fall_chance = fall_chance
|
||||||
src.embedded_pain_chance = embedded_pain_chance
|
src.pain_chance = pain_chance
|
||||||
src.embedded_pain_multiplier = embedded_pain_multiplier
|
src.pain_mult = pain_mult
|
||||||
src.embedded_fall_pain_multiplier = embedded_fall_pain_multiplier
|
src.fall_pain_mult = fall_pain_mult
|
||||||
src.embedded_impact_pain_multiplier = embedded_impact_pain_multiplier
|
src.impact_pain_mult = impact_pain_mult
|
||||||
src.embedded_unsafe_removal_pain_multiplier = embedded_unsafe_removal_pain_multiplier
|
src.rip_pain_mult = rip_pain_mult
|
||||||
src.embedded_unsafe_removal_time = embedded_unsafe_removal_time
|
src.rip_time = rip_time
|
||||||
|
src.ignore_throwspeed_threshold = ignore_throwspeed_threshold
|
||||||
|
src.jostle_chance = jostle_chance
|
||||||
|
src.jostle_pain_mult = jostle_pain_mult
|
||||||
|
src.pain_stam_pct = pain_stam_pct
|
||||||
tag = EMBEDID
|
tag = EMBEDID
|
||||||
|
|
||||||
/datum/embedding_behavior/proc/setRating(embed_chance, embedded_fall_chance, embedded_pain_chance, embedded_pain_multiplier, embedded_fall_pain_multiplier, embedded_impact_pain_multiplier, embedded_unsafe_removal_pain_multiplier, embedded_unsafe_removal_time)
|
/datum/embedding_behavior/proc/setRating(embed_chance, fall_chance, pain_chance, pain_mult, fall_pain_mult, impact_pain_mult, rip_pain_mult, rip_time, ignore_throwspeed_threshold)
|
||||||
return getEmbeddingBehavior((isnull(embed_chance) ? src.embed_chance : embed_chance),\
|
return getEmbeddingBehavior((isnull(embed_chance) ? src.embed_chance : embed_chance),\
|
||||||
(isnull(embedded_fall_chance) ? src.embedded_fall_chance : embedded_fall_chance),\
|
(isnull(fall_chance) ? src.fall_chance : fall_chance),\
|
||||||
(isnull(embedded_pain_chance) ? src.embedded_pain_chance : embedded_pain_chance),\
|
(isnull(pain_chance) ? src.pain_chance : pain_chance),\
|
||||||
(isnull(embedded_pain_multiplier) ? src.embedded_pain_multiplier : embedded_pain_multiplier),\
|
(isnull(pain_mult) ? src.pain_mult : pain_mult),\
|
||||||
(isnull(embedded_fall_pain_multiplier) ? src.embedded_fall_pain_multiplier : embedded_fall_pain_multiplier),\
|
(isnull(fall_pain_mult) ? src.fall_pain_mult : fall_pain_mult),\
|
||||||
(isnull(embedded_impact_pain_multiplier) ? src.embedded_impact_pain_multiplier : embedded_impact_pain_multiplier),\
|
(isnull(impact_pain_mult) ? src.impact_pain_mult : impact_pain_mult),\
|
||||||
(isnull(embedded_unsafe_removal_pain_multiplier) ? src.embedded_unsafe_removal_pain_multiplier : embedded_unsafe_removal_pain_multiplier),\
|
(isnull(rip_pain_mult) ? src.rip_pain_mult : rip_pain_mult),\
|
||||||
(isnull(embedded_unsafe_removal_time) ? src.embedded_unsafe_removal_time : embedded_unsafe_removal_time))
|
(isnull(rip_time) ? src.rip_time : rip_time),\
|
||||||
|
(isnull(ignore_throwspeed_threshold) ? src.ignore_throwspeed_threshold : ignore_throwspeed_threshold),\
|
||||||
|
(isnull(jostle_chance) ? src.jostle_chance : jostle_chance),\
|
||||||
|
(isnull(jostle_pain_mult) ? src.jostle_pain_mult : jostle_pain_mult),\
|
||||||
|
(isnull(pain_stam_pct) ? src.pain_stam_pct : pain_stam_pct))
|
||||||
|
|
||||||
#undef EMBEDID
|
#undef EMBEDID
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
|
|||||||
// if true, everyone item when created will have its name changed to be
|
// if true, everyone item when created will have its name changed to be
|
||||||
// more... RPG-like.
|
// more... RPG-like.
|
||||||
|
|
||||||
|
GLOBAL_VAR_INIT(stickpocalypse, FALSE) // if true, all non-embeddable items will be able to harmlessly stick to people when thrown
|
||||||
|
GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to embed in people, takes precedence over stickpocalypse
|
||||||
|
|
||||||
/obj/item
|
/obj/item
|
||||||
name = "item"
|
name = "item"
|
||||||
icon = 'icons/obj/items_and_weapons.dmi'
|
icon = 'icons/obj/items_and_weapons.dmi'
|
||||||
@@ -104,7 +107,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
|
|||||||
|
|
||||||
mouse_drag_pointer = MOUSE_ACTIVE_POINTER //the icon to indicate this object is being dragged
|
mouse_drag_pointer = MOUSE_ACTIVE_POINTER //the icon to indicate this object is being dragged
|
||||||
|
|
||||||
var/datum/embedding_behavior/embedding
|
var/list/embedding = NONE
|
||||||
|
|
||||||
var/flags_cover = 0 //for flags such as GLASSESCOVERSEYES
|
var/flags_cover = 0 //for flags such as GLASSESCOVERSEYES
|
||||||
var/heat = 0
|
var/heat = 0
|
||||||
@@ -152,7 +155,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
|
|||||||
|
|
||||||
/obj/item/Initialize()
|
/obj/item/Initialize()
|
||||||
|
|
||||||
if (attack_verb)
|
if(attack_verb)
|
||||||
attack_verb = typelist("attack_verb", attack_verb)
|
attack_verb = typelist("attack_verb", attack_verb)
|
||||||
|
|
||||||
. = ..()
|
. = ..()
|
||||||
@@ -160,9 +163,6 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
|
|||||||
new path(src)
|
new path(src)
|
||||||
actions_types = null
|
actions_types = null
|
||||||
|
|
||||||
if(GLOB.rpg_loot_items)
|
|
||||||
AddComponent(/datum/component/fantasy)
|
|
||||||
|
|
||||||
if(force_string)
|
if(force_string)
|
||||||
item_flags |= FORCE_STRING_OVERRIDE
|
item_flags |= FORCE_STRING_OVERRIDE
|
||||||
|
|
||||||
@@ -172,16 +172,6 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
|
|||||||
if(damtype == "brute")
|
if(damtype == "brute")
|
||||||
hitsound = "swing_hit"
|
hitsound = "swing_hit"
|
||||||
|
|
||||||
if (!embedding)
|
|
||||||
embedding = getEmbeddingBehavior()
|
|
||||||
else if (islist(embedding))
|
|
||||||
embedding = getEmbeddingBehavior(arglist(embedding))
|
|
||||||
else if (!istype(embedding, /datum/embedding_behavior))
|
|
||||||
stack_trace("Invalid type [embedding.type] found in .embedding during /obj/item Initialize()")
|
|
||||||
|
|
||||||
if(sharpness) //give sharp objects butchering functionality, for consistency
|
|
||||||
AddComponent(/datum/component/butchering, 80 * toolspeed)
|
|
||||||
|
|
||||||
/obj/item/Destroy()
|
/obj/item/Destroy()
|
||||||
item_flags &= ~DROPDEL //prevent reqdels
|
item_flags &= ~DROPDEL //prevent reqdels
|
||||||
if(ismob(loc))
|
if(ismob(loc))
|
||||||
@@ -191,6 +181,27 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
|
|||||||
qdel(X)
|
qdel(X)
|
||||||
return ..()
|
return ..()
|
||||||
|
|
||||||
|
/obj/item/ComponentInitialize()
|
||||||
|
. = ..()
|
||||||
|
|
||||||
|
// this proc says it's for initializing components, but we're initializing elements too because it's you and me against the world >:)
|
||||||
|
if(embedding)
|
||||||
|
AddElement(/datum/element/embed, embedding)
|
||||||
|
else if(GLOB.embedpocalypse)
|
||||||
|
embedding = EMBED_POINTY
|
||||||
|
AddElement(/datum/element/embed, embedding)
|
||||||
|
name = "pointy [name]"
|
||||||
|
else if(GLOB.stickpocalypse)
|
||||||
|
embedding = EMBED_HARMLESS
|
||||||
|
AddElement(/datum/element/embed, embedding)
|
||||||
|
name = "sticky [name]"
|
||||||
|
|
||||||
|
if(GLOB.rpg_loot_items)
|
||||||
|
AddComponent(/datum/component/fantasy)
|
||||||
|
|
||||||
|
if(sharpness) //give sharp objects butchering functionality, for consistency
|
||||||
|
AddComponent(/datum/component/butchering, 80 * toolspeed)
|
||||||
|
|
||||||
/obj/item/proc/check_allowed_items(atom/target, not_inside, target_self)
|
/obj/item/proc/check_allowed_items(atom/target, not_inside, target_self)
|
||||||
if(((src in target) && !target_self) || (!isturf(target.loc) && !isturf(target) && not_inside))
|
if(((src in target) && !target_self) || (!isturf(target.loc) && !isturf(target) && not_inside))
|
||||||
return 0
|
return 0
|
||||||
@@ -928,3 +939,11 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
|
|||||||
. = ..()
|
. = ..()
|
||||||
if(var_name == NAMEOF(src, slowdown))
|
if(var_name == NAMEOF(src, slowdown))
|
||||||
set_slowdown(var_value) //don't care if it's a duplicate edit as slowdown'll be set, do it anyways to force normal behavior.
|
set_slowdown(var_value) //don't care if it's a duplicate edit as slowdown'll be set, do it anyways to force normal behavior.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does the current embedding var meet the criteria for being harmless? Namely, does it have a pain multiplier and jostle pain mult of 0? If so, return true.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
/obj/item/proc/is_embed_harmless()
|
||||||
|
if(embedding)
|
||||||
|
return (!embedding["pain_mult"] && !embedding["jostle_pain_mult"])
|
||||||
@@ -45,7 +45,7 @@
|
|||||||
|
|
||||||
/obj/item/grenade/iedcasing/attack_self(mob/user) //
|
/obj/item/grenade/iedcasing/attack_self(mob/user) //
|
||||||
if(!active)
|
if(!active)
|
||||||
if(clown_check(user))
|
if(!botch_check(user))
|
||||||
to_chat(user, "<span class='warning'>You light the [name]!</span>")
|
to_chat(user, "<span class='warning'>You light the [name]!</span>")
|
||||||
cut_overlay("improvised_grenade_filled")
|
cut_overlay("improvised_grenade_filled")
|
||||||
preprime(user, null, FALSE)
|
preprime(user, null, FALSE)
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
var/det_time = 50
|
var/det_time = 50
|
||||||
var/display_timer = 1
|
var/display_timer = 1
|
||||||
var/clumsy_check = GRENADE_CLUMSY_FUMBLE
|
var/clumsy_check = GRENADE_CLUMSY_FUMBLE
|
||||||
|
var/sticky = FALSE
|
||||||
|
|
||||||
/obj/item/grenade/suicide_act(mob/living/carbon/user)
|
/obj/item/grenade/suicide_act(mob/living/carbon/user)
|
||||||
user.visible_message("<span class='suicide'>[user] primes [src], then eats it! It looks like [user.p_theyre()] trying to commit suicide!</span>")
|
user.visible_message("<span class='suicide'>[user] primes [src], then eats it! It looks like [user.p_theyre()] trying to commit suicide!</span>")
|
||||||
@@ -32,19 +33,21 @@
|
|||||||
if(!QDELETED(src))
|
if(!QDELETED(src))
|
||||||
qdel(src)
|
qdel(src)
|
||||||
|
|
||||||
/obj/item/grenade/proc/clown_check(mob/living/carbon/human/user)
|
/obj/item/grenade/proc/botch_check(mob/living/carbon/human/user)
|
||||||
var/clumsy = HAS_TRAIT(user, TRAIT_CLUMSY)
|
var/clumsy = HAS_TRAIT(user, TRAIT_CLUMSY)
|
||||||
if(clumsy)
|
if(clumsy)
|
||||||
if(clumsy_check == GRENADE_CLUMSY_FUMBLE && prob(50))
|
if(clumsy_check == GRENADE_CLUMSY_FUMBLE && prob(50))
|
||||||
to_chat(user, "<span class='warning'>Huh? How does this thing work?</span>")
|
to_chat(user, "<span class='warning'>Huh? How does this thing work?</span>")
|
||||||
preprime(user, 5, FALSE)
|
preprime(user, 5, FALSE)
|
||||||
return FALSE
|
return TRUE
|
||||||
else if(clumsy_check == GRENADE_NONCLUMSY_FUMBLE && !(user.mind && HAS_TRAIT(user.mind, TRAIT_CLOWN_MENTALITY)))
|
else if(clumsy_check == GRENADE_NONCLUMSY_FUMBLE && !(user.mind && HAS_TRAIT(user.mind, TRAIT_CLOWN_MENTALITY)))
|
||||||
to_chat(user, "<span class='warning'>You pull the pin on [src]. Attached to it is a pink ribbon that says, \"<span class='clown'>HONK</span>\"</span>")
|
to_chat(user, "<span class='warning'>You pull the pin on [src]. Attached to it is a pink ribbon that says, \"<span class='clown'>HONK</span>\"</span>")
|
||||||
preprime(user, 5, FALSE)
|
preprime(user, 5, FALSE)
|
||||||
return FALSE
|
return TRUE
|
||||||
return TRUE
|
|
||||||
|
|
||||||
|
else if(sticky && prob(50)) // to add risk to sticky tape grenade cheese, no return cause we still prime as normal after
|
||||||
|
to_chat(user, "<span class='warning'>What the... [src] is stuck to your hand!</span>")
|
||||||
|
ADD_TRAIT(src, TRAIT_NODROP, STICKY_NODROP)
|
||||||
|
|
||||||
/obj/item/grenade/examine(mob/user)
|
/obj/item/grenade/examine(mob/user)
|
||||||
. = ..()
|
. = ..()
|
||||||
@@ -56,8 +59,16 @@
|
|||||||
|
|
||||||
|
|
||||||
/obj/item/grenade/attack_self(mob/user)
|
/obj/item/grenade/attack_self(mob/user)
|
||||||
|
if(HAS_TRAIT(src, TRAIT_NODROP))
|
||||||
|
to_chat(user, "<span class='notice'>You try prying [src] off your hand...</span>")
|
||||||
|
if(do_after(user, 70, target=src))
|
||||||
|
to_chat(user, "<span class='notice'>You manage to remove [src] from your hand.</span>")
|
||||||
|
REMOVE_TRAIT(src, TRAIT_NODROP, STICKY_NODROP)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
if(!active)
|
if(!active)
|
||||||
if(clown_check(user))
|
if(!botch_check(user)) // if they botch the prime, it'll be handled in botch_check
|
||||||
preprime(user)
|
preprime(user)
|
||||||
|
|
||||||
/obj/item/grenade/proc/log_grenade(mob/user, turf/T)
|
/obj/item/grenade/proc/log_grenade(mob/user, turf/T)
|
||||||
|
|||||||
@@ -122,7 +122,9 @@
|
|||||||
var/obj/item/I = AM
|
var/obj/item/I = AM
|
||||||
I.throw_speed = max(1, (I.throw_speed - 3))
|
I.throw_speed = max(1, (I.throw_speed - 3))
|
||||||
I.throw_range = max(1, (I.throw_range - 3))
|
I.throw_range = max(1, (I.throw_range - 3))
|
||||||
I.embedding = I.embedding.setRating(embed_chance = 0)
|
if(I.embedding)
|
||||||
|
I.embedding["embed_chance"] = 0
|
||||||
|
I.AddElement(/datum/element/embed, I.embedding)
|
||||||
|
|
||||||
target.add_overlay(plastic_overlay, TRUE)
|
target.add_overlay(plastic_overlay, TRUE)
|
||||||
if(!nadeassembly)
|
if(!nadeassembly)
|
||||||
|
|||||||
@@ -138,6 +138,7 @@
|
|||||||
icon_state = "buckknife"
|
icon_state = "buckknife"
|
||||||
item_state = "knife"
|
item_state = "knife"
|
||||||
desc = "A military combat utility survival knife."
|
desc = "A military combat utility survival knife."
|
||||||
|
embedding = list("pain_mult" = 4, "embed_chance" = 65, "fall_chance" = 10, "ignore_throwspeed_threshold" = TRUE)
|
||||||
force = 20
|
force = 20
|
||||||
throwforce = 20
|
throwforce = 20
|
||||||
attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "cut")
|
attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "cut")
|
||||||
@@ -148,6 +149,7 @@
|
|||||||
icon_state = "survivalknife"
|
icon_state = "survivalknife"
|
||||||
item_state = "knife"
|
item_state = "knife"
|
||||||
desc = "A hunting grade survival knife."
|
desc = "A hunting grade survival knife."
|
||||||
|
embedding = list("pain_mult" = 4, "embed_chance" = 35, "fall_chance" = 10)
|
||||||
force = 15
|
force = 15
|
||||||
throwforce = 15
|
throwforce = 15
|
||||||
bayonet = TRUE
|
bayonet = TRUE
|
||||||
@@ -159,6 +161,7 @@
|
|||||||
lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi'
|
lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi'
|
||||||
righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi'
|
righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi'
|
||||||
desc = "A sharpened bone. The bare minimum in survival."
|
desc = "A sharpened bone. The bare minimum in survival."
|
||||||
|
embedding = list("pain_mult" = 4, "embed_chance" = 35, "fall_chance" = 10)
|
||||||
force = 15
|
force = 15
|
||||||
throwforce = 15
|
throwforce = 15
|
||||||
custom_materials = null
|
custom_materials = null
|
||||||
|
|||||||
@@ -103,7 +103,7 @@
|
|||||||
throw_speed = 3
|
throw_speed = 3
|
||||||
throw_range = 5
|
throw_range = 5
|
||||||
sharpness = IS_SHARP
|
sharpness = IS_SHARP
|
||||||
embedding = list("embed_chance" = 75, "embedded_impact_pain_multiplier" = 10)
|
embedding = list("embed_chance" = 75, "impact_pain_mult" = 10)
|
||||||
armour_penetration = 35
|
armour_penetration = 35
|
||||||
block_chance = 50
|
block_chance = 50
|
||||||
var/list/possible_colors = list("red" = LIGHT_COLOR_RED, "blue" = LIGHT_COLOR_LIGHT_CYAN, "green" = LIGHT_COLOR_GREEN, "purple" = LIGHT_COLOR_LAVENDER)
|
var/list/possible_colors = list("red" = LIGHT_COLOR_RED, "blue" = LIGHT_COLOR_LIGHT_CYAN, "green" = LIGHT_COLOR_GREEN, "purple" = LIGHT_COLOR_LAVENDER)
|
||||||
|
|||||||
@@ -53,6 +53,8 @@
|
|||||||
throw_speed = 4
|
throw_speed = 4
|
||||||
if(attack_verb_on.len)
|
if(attack_verb_on.len)
|
||||||
attack_verb = attack_verb_on
|
attack_verb = attack_verb_on
|
||||||
|
if(embedding)
|
||||||
|
AddElement(/datum/element/embed, embedding)
|
||||||
icon_state = icon_state_on
|
icon_state = icon_state_on
|
||||||
w_class = w_class_on
|
w_class = w_class_on
|
||||||
else
|
else
|
||||||
@@ -62,6 +64,8 @@
|
|||||||
throw_speed = initial(throw_speed)
|
throw_speed = initial(throw_speed)
|
||||||
if(attack_verb_off.len)
|
if(attack_verb_off.len)
|
||||||
attack_verb = attack_verb_off
|
attack_verb = attack_verb_off
|
||||||
|
if(embedding)
|
||||||
|
RemoveElement(/datum/element/embed, embedding)
|
||||||
icon_state = initial(icon_state)
|
icon_state = initial(icon_state)
|
||||||
w_class = initial(w_class)
|
w_class = initial(w_class)
|
||||||
total_mass = initial(total_mass)
|
total_mass = initial(total_mass)
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ GLOBAL_LIST_INIT(rod_recipes, list ( \
|
|||||||
max_amount = 50
|
max_amount = 50
|
||||||
attack_verb = list("hit", "bludgeoned", "whacked")
|
attack_verb = list("hit", "bludgeoned", "whacked")
|
||||||
hitsound = 'sound/weapons/grenadelaunch.ogg'
|
hitsound = 'sound/weapons/grenadelaunch.ogg'
|
||||||
|
embedding = list()
|
||||||
novariants = TRUE
|
novariants = TRUE
|
||||||
|
|
||||||
/obj/item/stack/rods/suicide_act(mob/living/carbon/user)
|
/obj/item/stack/rods/suicide_act(mob/living/carbon/user)
|
||||||
|
|||||||
@@ -291,6 +291,7 @@ GLOBAL_LIST_INIT(plastitaniumglass_recipes, list(
|
|||||||
max_integrity = 40
|
max_integrity = 40
|
||||||
sharpness = IS_SHARP
|
sharpness = IS_SHARP
|
||||||
var/icon_prefix
|
var/icon_prefix
|
||||||
|
embedding = list("embed_chance" = 65)
|
||||||
|
|
||||||
|
|
||||||
/obj/item/shard/suicide_act(mob/user)
|
/obj/item/shard/suicide_act(mob/user)
|
||||||
|
|||||||
62
code/game/objects/items/stacks/tape.dm
Normal file
62
code/game/objects/items/stacks/tape.dm
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
|
||||||
|
|
||||||
|
/obj/item/stack/sticky_tape
|
||||||
|
name = "sticky tape"
|
||||||
|
singular_name = "sticky tape"
|
||||||
|
desc = "Used for sticking to things for sticking said things to people."
|
||||||
|
icon = 'icons/obj/tapes.dmi'
|
||||||
|
icon_state = "tape_w"
|
||||||
|
var/prefix = "sticky"
|
||||||
|
item_flags = NOBLUDGEON
|
||||||
|
amount = 5
|
||||||
|
max_amount = 5
|
||||||
|
resistance_flags = FLAMMABLE
|
||||||
|
grind_results = list(/datum/reagent/cellulose = 5)
|
||||||
|
|
||||||
|
var/list/conferred_embed = EMBED_HARMLESS
|
||||||
|
var/overwrite_existing = FALSE
|
||||||
|
|
||||||
|
/obj/item/stack/sticky_tape/afterattack(obj/item/I, mob/living/user)
|
||||||
|
if(!istype(I))
|
||||||
|
return
|
||||||
|
|
||||||
|
if(I.embedding && I.embedding == conferred_embed)
|
||||||
|
to_chat(user, "<span class='warning'>[I] is already coated in [src]!</span>")
|
||||||
|
return
|
||||||
|
|
||||||
|
user.visible_message("<span class='notice'>[user] begins wrapping [I] with [src].</span>", "<span class='notice'>You begin wrapping [I] with [src].</span>")
|
||||||
|
|
||||||
|
if(do_after(user, 30, target=I))
|
||||||
|
I.embedding = conferred_embed
|
||||||
|
I.AddElement(/datum/element/embed, I.embedding)
|
||||||
|
to_chat(user, "<span class='notice'>You finish wrapping [I] with [src].</span>")
|
||||||
|
use(1)
|
||||||
|
I.name = "[prefix] [I.name]"
|
||||||
|
|
||||||
|
if(istype(I, /obj/item/grenade))
|
||||||
|
var/obj/item/grenade/sticky_bomb = I
|
||||||
|
sticky_bomb.sticky = TRUE
|
||||||
|
|
||||||
|
/obj/item/stack/sticky_tape/super
|
||||||
|
name = "super sticky tape"
|
||||||
|
singular_name = "super sticky tape"
|
||||||
|
desc = "Quite possibly the most mischevious substance in the galaxy. Use with extreme lack of caution."
|
||||||
|
icon_state = "tape_y"
|
||||||
|
prefix = "super sticky"
|
||||||
|
conferred_embed = EMBED_HARMLESS_SUPERIOR
|
||||||
|
|
||||||
|
/obj/item/stack/sticky_tape/pointy
|
||||||
|
name = "pointy tape"
|
||||||
|
singular_name = "pointy tape"
|
||||||
|
desc = "Used for sticking to things for sticking said things inside people."
|
||||||
|
icon_state = "tape_evil"
|
||||||
|
prefix = "pointy"
|
||||||
|
conferred_embed = EMBED_POINTY
|
||||||
|
|
||||||
|
/obj/item/stack/sticky_tape/pointy/super
|
||||||
|
name = "super pointy tape"
|
||||||
|
singular_name = "super pointy tape"
|
||||||
|
desc = "You didn't know tape could look so sinister. Welcome to Space Station 13."
|
||||||
|
icon_state = "tape_spikes"
|
||||||
|
prefix = "super pointy"
|
||||||
|
conferred_embed = EMBED_POINTY_SUPERIOR
|
||||||
@@ -582,7 +582,7 @@
|
|||||||
force_wielded = 18
|
force_wielded = 18
|
||||||
throwforce = 20
|
throwforce = 20
|
||||||
throw_speed = 4
|
throw_speed = 4
|
||||||
embedding = list("embedded_impact_pain_multiplier" = 1.5, "embed_chance" = 65)
|
embedding = list("impact_pain_mult" = 3)
|
||||||
armour_penetration = 10
|
armour_penetration = 10
|
||||||
custom_materials = list(/datum/material/iron=1150, /datum/material/glass=2075)
|
custom_materials = list(/datum/material/iron=1150, /datum/material/glass=2075)
|
||||||
hitsound = 'sound/weapons/bladeslice.ogg'
|
hitsound = 'sound/weapons/bladeslice.ogg'
|
||||||
|
|||||||
@@ -297,12 +297,26 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301
|
|||||||
force = 2
|
force = 2
|
||||||
throwforce = 20 //This is never used on mobs since this has a 100% embed chance.
|
throwforce = 20 //This is never used on mobs since this has a 100% embed chance.
|
||||||
throw_speed = 4
|
throw_speed = 4
|
||||||
embedding = list("embedded_pain_multiplier" = 4, "embed_chance" = 100, "embedded_fall_chance" = 0)
|
embedding = list("pain_mult" = 4, "embed_chance" = 100, "fall_chance" = 0)
|
||||||
w_class = WEIGHT_CLASS_SMALL
|
w_class = WEIGHT_CLASS_SMALL
|
||||||
sharpness = IS_SHARP
|
sharpness = IS_SHARP
|
||||||
custom_materials = list(/datum/material/iron=500, /datum/material/glass=500)
|
custom_materials = list(/datum/material/iron=500, /datum/material/glass=500)
|
||||||
resistance_flags = FIRE_PROOF
|
resistance_flags = FIRE_PROOF
|
||||||
|
|
||||||
|
/obj/item/throwing_star/stamina
|
||||||
|
name = "shock throwing star"
|
||||||
|
desc = "An aerodynamic disc designed to cause excruciating pain when stuck inside fleeing targets, hopefully without causing fatal harm."
|
||||||
|
throwforce = 5
|
||||||
|
embedding = list("pain_chance" = 5, "embed_chance" = 100, "fall_chance" = 0, "jostle_chance" = 10, "pain_stam_pct" = 0.8, "jostle_pain_mult" = 3)
|
||||||
|
|
||||||
|
/obj/item/throwing_star/toy
|
||||||
|
name = "toy throwing star"
|
||||||
|
desc = "An aerodynamic disc strapped with adhesive for sticking to people, good for playing pranks and getting yourself killed by security."
|
||||||
|
sharpness = IS_BLUNT
|
||||||
|
force = 0
|
||||||
|
throwforce = 0
|
||||||
|
embedding = list("pain_mult" = 0, "jostle_pain_mult" = 0, "embed_chance" = 100, "fall_chance" = 0)
|
||||||
|
|
||||||
/obj/item/switchblade
|
/obj/item/switchblade
|
||||||
name = "switchblade"
|
name = "switchblade"
|
||||||
icon_state = "switchblade"
|
icon_state = "switchblade"
|
||||||
|
|||||||
@@ -12,7 +12,10 @@
|
|||||||
|
|
||||||
baseturfs = /turf/open/floor/plating
|
baseturfs = /turf/open/floor/plating
|
||||||
|
|
||||||
var/hardness = 40 //lower numbers are harder. Used to determine the probability of a hulk smashing through.
|
|
||||||
|
|
||||||
|
///lower numbers are harder. Used to determine the probability of a hulk smashing through. Also, (hardness - 40) is used as a modifier for objects trying to embed in this (hardness of 30 results in a -10% chance)
|
||||||
|
var/hardness = 40
|
||||||
var/slicing_duration = 100 //default time taken to slice the wall
|
var/slicing_duration = 100 //default time taken to slice the wall
|
||||||
var/sheet_type = /obj/item/stack/sheet/metal
|
var/sheet_type = /obj/item/stack/sheet/metal
|
||||||
var/sheet_amount = 2
|
var/sheet_amount = 2
|
||||||
|
|||||||
46
code/modules/events/wizard/embeddies.dm
Normal file
46
code/modules/events/wizard/embeddies.dm
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/datum/round_event_control/wizard/embedpocalypse
|
||||||
|
name = "Make Everything Embeddable"
|
||||||
|
weight = 2
|
||||||
|
typepath = /datum/round_event/wizard/embedpocalypse
|
||||||
|
max_occurrences = 1
|
||||||
|
earliest_start = 0 MINUTES
|
||||||
|
|
||||||
|
/datum/round_event/wizard/embedpocalypse/start()
|
||||||
|
for(var/obj/item/I in world)
|
||||||
|
CHECK_TICK
|
||||||
|
|
||||||
|
if(!(I.flags_1 & INITIALIZED_1))
|
||||||
|
continue
|
||||||
|
|
||||||
|
if(!I.embedding || I.embedding == EMBED_HARMLESS)
|
||||||
|
I.embedding = EMBED_POINTY
|
||||||
|
I.AddElement(/datum/element/embed, I.embedding)
|
||||||
|
I.name = "pointy [I.name]"
|
||||||
|
|
||||||
|
GLOB.embedpocalypse = TRUE
|
||||||
|
GLOB.stickpocalypse = FALSE // embedpocalypse takes precedence over stickpocalypse
|
||||||
|
|
||||||
|
/datum/round_event_control/wizard/embedpocalypse/sticky
|
||||||
|
name = "Make Everything Sticky"
|
||||||
|
weight = 6
|
||||||
|
typepath = /datum/round_event/wizard/embedpocalypse/sticky
|
||||||
|
max_occurrences = 1
|
||||||
|
earliest_start = 0 MINUTES
|
||||||
|
|
||||||
|
/datum/round_event_control/wizard/embedpocalypse/sticky/canSpawnEvent(players_amt, gamemode)
|
||||||
|
if(GLOB.embedpocalypse)
|
||||||
|
return FALSE
|
||||||
|
|
||||||
|
/datum/round_event/wizard/embedpocalypse/sticky/start()
|
||||||
|
for(var/obj/item/I in world)
|
||||||
|
CHECK_TICK
|
||||||
|
|
||||||
|
if(!(I.flags_1 & INITIALIZED_1))
|
||||||
|
continue
|
||||||
|
|
||||||
|
if(!I.embedding)
|
||||||
|
I.embedding = EMBED_HARMLESS
|
||||||
|
I.AddElement(/datum/element/embed, I.embedding)
|
||||||
|
I.name = "sticky [I.name]"
|
||||||
|
|
||||||
|
GLOB.stickpocalypse = TRUE
|
||||||
@@ -94,7 +94,9 @@
|
|||||||
|
|
||||||
//We want an accurate reading of .len
|
//We want an accurate reading of .len
|
||||||
listclearnulls(BP.embedded_objects)
|
listclearnulls(BP.embedded_objects)
|
||||||
temp_bleed += 0.5 * BP.embedded_objects.len
|
for(var/obj/item/embeddies in BP.embedded_objects)
|
||||||
|
if(!embeddies.is_embed_harmless())
|
||||||
|
temp_bleed += 0.5
|
||||||
|
|
||||||
if(brutedamage >= 20)
|
if(brutedamage >= 20)
|
||||||
temp_bleed += (brutedamage * 0.013)
|
temp_bleed += (brutedamage * 0.013)
|
||||||
|
|||||||
@@ -159,7 +159,10 @@
|
|||||||
disabled += BP
|
disabled += BP
|
||||||
missing -= BP.body_zone
|
missing -= BP.body_zone
|
||||||
for(var/obj/item/I in BP.embedded_objects)
|
for(var/obj/item/I in BP.embedded_objects)
|
||||||
msg += "<B>[t_He] [t_has] \a [icon2html(I, user)] [I] embedded in [t_his] [BP.name]!</B>\n"
|
if(I.is_embed_harmless())
|
||||||
|
msg += "<B>[t_He] [t_has] \a [icon2html(I, user)] [I] stuck to [t_his] [BP.name]!</B>\n"
|
||||||
|
else
|
||||||
|
msg += "<B>[t_He] [t_has] \a [icon2html(I, user)] [I] embedded in [t_his] [BP.name]!</B>\n"
|
||||||
|
|
||||||
for(var/X in disabled)
|
for(var/X in disabled)
|
||||||
var/obj/item/bodypart/BP = X
|
var/obj/item/bodypart/BP = X
|
||||||
|
|||||||
@@ -220,22 +220,7 @@
|
|||||||
var/obj/item/I = locate(href_list["embedded_object"]) in L.embedded_objects
|
var/obj/item/I = locate(href_list["embedded_object"]) in L.embedded_objects
|
||||||
if(!I || I.loc != src) //no item, no limb, or item is not in limb or in the person anymore
|
if(!I || I.loc != src) //no item, no limb, or item is not in limb or in the person anymore
|
||||||
return
|
return
|
||||||
var/time_taken = I.embedding.embedded_unsafe_removal_time/I.w_class //Citadel Change from * to /
|
SEND_SIGNAL(src, COMSIG_HUMAN_EMBED_RIP, I, L)
|
||||||
usr.visible_message("<span class='warning'>[usr] attempts to remove [I] from [usr.p_their()] [L.name].</span>","<span class='notice'>You attempt to remove [I] from your [L.name]... (It will take [DisplayTimeText(time_taken)].)</span>")
|
|
||||||
if(do_after(usr, time_taken, needhand = 1, target = src))
|
|
||||||
remove_embedded_unsafe(L, I, usr)
|
|
||||||
/* CITADEL EDIT: remove_embedded_unsafe replaces this code
|
|
||||||
if(!I || !L || I.loc != src || !(I in L.embedded_objects))
|
|
||||||
return
|
|
||||||
L.embedded_objects -= I
|
|
||||||
L.receive_damage(I.embedding.embedded_unsafe_removal_pain_multiplier*I.w_class)//It hurts to rip it out, get surgery you dingus.
|
|
||||||
I.forceMove(get_turf(src))
|
|
||||||
usr.put_in_hands(I)
|
|
||||||
usr.emote("scream")
|
|
||||||
usr.visible_message("[usr] successfully rips [I] out of [usr.p_their()] [L.name]!","<span class='notice'>You successfully remove [I] from your [L.name].</span>")
|
|
||||||
if(!has_embedded_objects())
|
|
||||||
clear_alert("embeddedobject")
|
|
||||||
SEND_SIGNAL(usr, COMSIG_CLEAR_MOOD_EVENT, "embedded") */
|
|
||||||
return
|
return
|
||||||
|
|
||||||
if(href_list["item"])
|
if(href_list["item"])
|
||||||
|
|||||||
@@ -620,7 +620,10 @@
|
|||||||
to_send += "\t <span class='[no_damage ? "notice" : "warning"]'>Your [LB.name] [HAS_TRAIT(src, TRAIT_SELF_AWARE) ? "has" : "is"] [status].</span>\n"
|
to_send += "\t <span class='[no_damage ? "notice" : "warning"]'>Your [LB.name] [HAS_TRAIT(src, TRAIT_SELF_AWARE) ? "has" : "is"] [status].</span>\n"
|
||||||
|
|
||||||
for(var/obj/item/I in LB.embedded_objects)
|
for(var/obj/item/I in LB.embedded_objects)
|
||||||
to_send += "\t <a href='?src=[REF(src)];embedded_object=[REF(I)];embedded_limb=[REF(LB)]' class='warning'>There is \a [I] embedded in your [LB.name]!</a>\n"
|
if(I.is_embed_harmless())
|
||||||
|
to_chat(src, "\t <a href='?src=[REF(src)];embedded_object=[REF(I)];embedded_limb=[REF(LB)]' class='warning'>There is \a [I] stuck to your [LB.name]!</a>")
|
||||||
|
else
|
||||||
|
to_chat(src, "\t <a href='?src=[REF(src)];embedded_object=[REF(I)];embedded_limb=[REF(LB)]' class='warning'>There is \a [I] embedded in your [LB.name]!</a>")
|
||||||
|
|
||||||
for(var/t in missing)
|
for(var/t in missing)
|
||||||
to_send += "<span class='boldannounce'>Your [parse_zone(t)] is missing!</span>\n"
|
to_send += "<span class='boldannounce'>Your [parse_zone(t)] is missing!</span>\n"
|
||||||
|
|||||||
@@ -35,10 +35,6 @@
|
|||||||
//heart attack stuff
|
//heart attack stuff
|
||||||
handle_heart()
|
handle_heart()
|
||||||
|
|
||||||
if(stat != DEAD)
|
|
||||||
//Stuff jammed in your limbs hurts
|
|
||||||
handle_embedded_objects()
|
|
||||||
|
|
||||||
//Update our name based on whether our face is obscured/disfigured
|
//Update our name based on whether our face is obscured/disfigured
|
||||||
name = get_visible_name()
|
name = get_visible_name()
|
||||||
|
|
||||||
@@ -303,25 +299,6 @@
|
|||||||
return TRUE
|
return TRUE
|
||||||
return ..()
|
return ..()
|
||||||
|
|
||||||
|
|
||||||
/mob/living/carbon/human/proc/handle_embedded_objects()
|
|
||||||
for(var/X in bodyparts)
|
|
||||||
var/obj/item/bodypart/BP = X
|
|
||||||
for(var/obj/item/I in BP.embedded_objects)
|
|
||||||
if(prob(I.embedding.embedded_pain_chance))
|
|
||||||
BP.receive_damage(I.w_class*I.embedding.embedded_pain_multiplier)
|
|
||||||
to_chat(src, "<span class='userdanger'>[I] embedded in your [BP.name] hurts!</span>")
|
|
||||||
|
|
||||||
if(prob(I.embedding.embedded_fall_chance))
|
|
||||||
BP.receive_damage(I.w_class*I.embedding.embedded_fall_pain_multiplier)
|
|
||||||
BP.embedded_objects -= I
|
|
||||||
I.forceMove(drop_location())
|
|
||||||
I.unembedded()
|
|
||||||
visible_message("<span class='danger'>[I] falls out of [name]'s [BP.name]!</span>","<span class='userdanger'>[I] falls out of your [BP.name]!</span>")
|
|
||||||
if(!has_embedded_objects())
|
|
||||||
clear_alert("embeddedobject")
|
|
||||||
SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "embedded")
|
|
||||||
|
|
||||||
/mob/living/carbon/human/proc/handle_active_genes()
|
/mob/living/carbon/human/proc/handle_active_genes()
|
||||||
if(HAS_TRAIT(src, TRAIT_MUTATION_STASIS))
|
if(HAS_TRAIT(src, TRAIT_MUTATION_STASIS))
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -124,9 +124,12 @@
|
|||||||
return TRUE
|
return TRUE
|
||||||
var/dtype = BRUTE
|
var/dtype = BRUTE
|
||||||
var/volume = I.get_volume_by_throwforce_and_or_w_class()
|
var/volume = I.get_volume_by_throwforce_and_or_w_class()
|
||||||
SEND_SIGNAL(I, COMSIG_MOVABLE_IMPACT_ZONE, src, impacting_zone)
|
var/nosell_hit = SEND_SIGNAL(I, COMSIG_MOVABLE_IMPACT_ZONE, src, zone, throwingdatum) // TODO: find a better way to handle hitpush and skipcatch for humans
|
||||||
dtype = I.damtype
|
if(nosell_hit)
|
||||||
|
skipcatch = TRUE
|
||||||
|
hitpush = FALSE
|
||||||
|
|
||||||
|
dtype = I.damtype
|
||||||
if (I.throwforce > 0) //If the weapon's throwforce is greater than zero...
|
if (I.throwforce > 0) //If the weapon's throwforce is greater than zero...
|
||||||
if (I.throwhitsound) //...and throwhitsound is defined...
|
if (I.throwhitsound) //...and throwhitsound is defined...
|
||||||
playsound(loc, I.throwhitsound, volume, 1, -1) //...play the weapon's throwhitsound.
|
playsound(loc, I.throwhitsound, volume, 1, -1) //...play the weapon's throwhitsound.
|
||||||
|
|||||||
@@ -15,4 +15,4 @@
|
|||||||
/obj/item/throwing_star/ninja
|
/obj/item/throwing_star/ninja
|
||||||
name = "ninja throwing star"
|
name = "ninja throwing star"
|
||||||
throwforce = 30
|
throwforce = 30
|
||||||
embedding = list("embedded_pain_multiplier" = 6, "embed_chance" = 100, "embedded_fall_chance" = 0)
|
embedding = list("pain_mult" = 6, "embed_chance" = 100, "fall_chance" = 0)
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
var/colour = "black" //what colour the ink is!
|
var/colour = "black" //what colour the ink is!
|
||||||
var/degrees = 0
|
var/degrees = 0
|
||||||
var/font = PEN_FONT
|
var/font = PEN_FONT
|
||||||
|
embedding = list()
|
||||||
|
|
||||||
/obj/item/pen/suicide_act(mob/user)
|
/obj/item/pen/suicide_act(mob/user)
|
||||||
user.visible_message("<span class='suicide'>[user] is scribbling numbers all over [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to commit sudoku...</span>")
|
user.visible_message("<span class='suicide'>[user] is scribbling numbers all over [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to commit sudoku...</span>")
|
||||||
@@ -41,6 +42,7 @@
|
|||||||
desc = "It's a normal red ink pen."
|
desc = "It's a normal red ink pen."
|
||||||
icon_state = "pen_red"
|
icon_state = "pen_red"
|
||||||
colour = "red"
|
colour = "red"
|
||||||
|
throw_speed = 4 // red ones go faster (in this case, fast enough to embed!)
|
||||||
|
|
||||||
/obj/item/pen/invisible
|
/obj/item/pen/invisible
|
||||||
desc = "It's an invisible pen marker."
|
desc = "It's an invisible pen marker."
|
||||||
@@ -56,8 +58,10 @@
|
|||||||
switch(colour)
|
switch(colour)
|
||||||
if("black")
|
if("black")
|
||||||
colour = "red"
|
colour = "red"
|
||||||
|
throw_speed++
|
||||||
if("red")
|
if("red")
|
||||||
colour = "green"
|
colour = "green"
|
||||||
|
throw_speed = initial(throw_speed)
|
||||||
if("green")
|
if("green")
|
||||||
colour = "blue"
|
colour = "blue"
|
||||||
else
|
else
|
||||||
@@ -178,6 +182,7 @@
|
|||||||
attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") //these wont show up if the pen is off
|
attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") //these wont show up if the pen is off
|
||||||
sharpness = IS_SHARP
|
sharpness = IS_SHARP
|
||||||
var/on = FALSE
|
var/on = FALSE
|
||||||
|
var/embedding = list(embed_chance = EMBED_CHANCE)
|
||||||
|
|
||||||
/obj/item/pen/edagger/ComponentInitialize()
|
/obj/item/pen/edagger/ComponentInitialize()
|
||||||
. = ..()
|
. = ..()
|
||||||
@@ -198,6 +203,7 @@
|
|||||||
throwforce = initial(throwforce)
|
throwforce = initial(throwforce)
|
||||||
playsound(user, 'sound/weapons/saberoff.ogg', 5, 1)
|
playsound(user, 'sound/weapons/saberoff.ogg', 5, 1)
|
||||||
to_chat(user, "<span class='warning'>[src] can now be concealed.</span>")
|
to_chat(user, "<span class='warning'>[src] can now be concealed.</span>")
|
||||||
|
RemoveElement(/datum/element/embed, embedding)
|
||||||
else
|
else
|
||||||
on = TRUE
|
on = TRUE
|
||||||
force = 18
|
force = 18
|
||||||
@@ -208,6 +214,7 @@
|
|||||||
throwforce = 35
|
throwforce = 35
|
||||||
playsound(user, 'sound/weapons/saberon.ogg', 5, 1)
|
playsound(user, 'sound/weapons/saberon.ogg', 5, 1)
|
||||||
to_chat(user, "<span class='warning'>[src] is now active.</span>")
|
to_chat(user, "<span class='warning'>[src] is now active.</span>")
|
||||||
|
AddElement(/datum/element/embed, embedding)
|
||||||
update_icon()
|
update_icon()
|
||||||
|
|
||||||
/obj/item/pen/edagger/update_icon_state()
|
/obj/item/pen/edagger/update_icon_state()
|
||||||
|
|||||||
@@ -760,4 +760,35 @@
|
|||||||
materials = list(/datum/material/iron = 1000)
|
materials = list(/datum/material/iron = 1000)
|
||||||
build_path = /obj/item/tank/internals/emergency_oxygen/engi/empty
|
build_path = /obj/item/tank/internals/emergency_oxygen/engi/empty
|
||||||
category = list("Equipment")
|
category = list("Equipment")
|
||||||
departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
|
departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
|
||||||
|
|
||||||
|
/////////////////////////////////////////
|
||||||
|
/////////////////Tape////////////////////
|
||||||
|
/////////////////////////////////////////
|
||||||
|
|
||||||
|
/datum/design/sticky_tape
|
||||||
|
name = "Sticky Tape"
|
||||||
|
id = "sticky_tape"
|
||||||
|
build_type = PROTOLATHE
|
||||||
|
materials = list(/datum/material/plastic = 500)
|
||||||
|
build_path = /obj/item/stack/sticky_tape
|
||||||
|
category = list("Equipment")
|
||||||
|
departmental_flags = DEPARTMENTAL_FLAG_SERVICE
|
||||||
|
|
||||||
|
/datum/design/super_sticky_tape
|
||||||
|
name = "Super Sticky Tape"
|
||||||
|
id = "super_sticky_tape"
|
||||||
|
build_type = PROTOLATHE
|
||||||
|
materials = list(/datum/material/plastic = 3000)
|
||||||
|
build_path = /obj/item/stack/sticky_tape/super
|
||||||
|
category = list("Equipment")
|
||||||
|
departmental_flags = DEPARTMENTAL_FLAG_SERVICE
|
||||||
|
|
||||||
|
/datum/design/pointy_tape
|
||||||
|
name = "Pointy Tape"
|
||||||
|
id = "pointy_tape"
|
||||||
|
build_type = PROTOLATHE
|
||||||
|
materials = list(/datum/material/iron = 1500, /datum/material/plastic = 1000)
|
||||||
|
build_path = /obj/item/stack/sticky_tape/pointy
|
||||||
|
category = list("Equipment")
|
||||||
|
departmental_flags = DEPARTMENTAL_FLAG_SERVICE
|
||||||
|
|||||||
@@ -66,3 +66,28 @@
|
|||||||
design_ids = list("air_horn", "honker_main", "honker_peri", "honker_targ", "honk_chassis", "honk_head", "honk_torso", "honk_left_arm", "honk_right_arm",
|
design_ids = list("air_horn", "honker_main", "honker_peri", "honker_targ", "honk_chassis", "honk_head", "honk_torso", "honk_left_arm", "honk_right_arm",
|
||||||
"honk_left_leg", "honk_right_leg", "mech_banana_mortar", "mech_mousetrap_mortar", "mech_honker", "mech_punching_face", "implant_trombone", "borg_transform_clown")
|
"honk_left_leg", "honk_right_leg", "mech_banana_mortar", "mech_mousetrap_mortar", "mech_honker", "mech_punching_face", "implant_trombone", "borg_transform_clown")
|
||||||
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
|
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
|
||||||
|
|
||||||
|
////////////////////////Tape tech////////////////////////////
|
||||||
|
/datum/techweb_node/sticky_basic
|
||||||
|
id = "sticky_basic"
|
||||||
|
display_name = "Basic Sticky Technology"
|
||||||
|
description = "The only thing left to do after researching this tech is to start printing out a bunch of 'kick me' signs."
|
||||||
|
prereq_ids = list("base")
|
||||||
|
design_ids = list("sticky_tape")
|
||||||
|
|
||||||
|
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
|
||||||
|
export_price = 2500
|
||||||
|
hidden = TRUE
|
||||||
|
experimental = TRUE
|
||||||
|
|
||||||
|
// Can be researched after getting the basic sticky technology from the BEPIS major reward
|
||||||
|
/datum/techweb_node/sticky_advanced
|
||||||
|
id = "sticky_advanced"
|
||||||
|
display_name = "Advanced Sticky Technology"
|
||||||
|
description = "Taking a good joke too far? Nonsense!"
|
||||||
|
prereq_ids = list("sticky_basic")
|
||||||
|
design_ids = list("super_sticky_tape", "pointy_tape")
|
||||||
|
|
||||||
|
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000)
|
||||||
|
export_price = 2500
|
||||||
|
hidden = TRUE
|
||||||
@@ -166,11 +166,13 @@
|
|||||||
clear_alert("embeddedobject")
|
clear_alert("embeddedobject")
|
||||||
SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "embedded")
|
SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "embedded")
|
||||||
|
|
||||||
/mob/living/carbon/proc/has_embedded_objects()
|
/mob/living/carbon/proc/has_embedded_objects(include_harmless=FALSE)
|
||||||
. = 0
|
. = 0
|
||||||
for(var/X in bodyparts)
|
for(var/X in bodyparts)
|
||||||
var/obj/item/bodypart/L = X
|
var/obj/item/bodypart/L = X
|
||||||
for(var/obj/item/I in L.embedded_objects)
|
for(var/obj/item/I in L.embedded_objects)
|
||||||
|
if(!include_harmless && I.is_embed_harmless())
|
||||||
|
continue
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -23,12 +23,7 @@
|
|||||||
var/objects = 0
|
var/objects = 0
|
||||||
for(var/obj/item/I in L.embedded_objects)
|
for(var/obj/item/I in L.embedded_objects)
|
||||||
objects++
|
objects++
|
||||||
I.forceMove(get_turf(H))
|
SEND_SIGNAL(H, COMSIG_HUMAN_EMBED_REMOVAL, I, L)
|
||||||
L.embedded_objects -= I
|
|
||||||
I.unembedded()
|
|
||||||
if(!H.has_embedded_objects())
|
|
||||||
H.clear_alert("embeddedobject")
|
|
||||||
SEND_SIGNAL(H, COMSIG_CLEAR_MOOD_EVENT, "embedded")
|
|
||||||
|
|
||||||
if(objects > 0)
|
if(objects > 0)
|
||||||
display_results(user, target, "<span class='notice'>You successfully remove [objects] objects from [H]'s [L.name].</span>",
|
display_results(user, target, "<span class='notice'>You successfully remove [objects] objects from [H]'s [L.name].</span>",
|
||||||
|
|||||||
BIN
icons/obj/tapes.dmi
Normal file
BIN
icons/obj/tapes.dmi
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 788 B |
Reference in New Issue
Block a user