mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2026-08-24 05:38:15 +01:00
Merge master into loadout-crystals
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
/obj/item/petrifier
|
||||
name = "odd button"
|
||||
desc = "A metal device with a single, purple button on it, and a tiny interface."
|
||||
icon = 'modular_chomp/icons/obj/machines/other.dmi'
|
||||
icon_state = "petrifier"
|
||||
|
||||
var/mob/living/carbon/human/target
|
||||
var/identifier = "statue"
|
||||
var/material = "stone"
|
||||
var/adjective = "hardens"
|
||||
var/tint = "#FFFFFF"
|
||||
var/discard_clothes = TRUE
|
||||
var/able_to_unpetrify = TRUE
|
||||
var/obj/machinery/petrification/linked
|
||||
|
||||
/obj/item/petrifier/Initialize(mapload, var/to_link)
|
||||
. = ..()
|
||||
linked = to_link
|
||||
|
||||
/obj/item/petrifier/attack_self(var/mob/user)
|
||||
. = ..()
|
||||
if (!isturf(user.loc) && user.get_ultimate_mob() != target)
|
||||
to_chat(user, "<span class='warning'>The device beeps but does nothing.</span>")
|
||||
return
|
||||
if (linked?.petrify(src))
|
||||
visible_message("<span class='notice'>A ray of purple light streams out of \the [src], aimed directly at [target]. Everywhere the light touches on them quickly [adjective] into [material].</span>")
|
||||
to_chat(user, "<span class='warning'>The device fizzles and crumbles into dust.</span>")
|
||||
qdel(src)
|
||||
@@ -20,3 +20,84 @@
|
||||
|
||||
/obj/item/capture_crystal/loadout/capture_chance()
|
||||
return 0
|
||||
|
||||
/obj/item/capture_crystal/cheap
|
||||
name = "cheap capture crystal"
|
||||
desc = "A silent, unassuming crystal in what appears to be some kind of steel housing. This one seems to be cheapley made and can only handle a willing mind."
|
||||
icon = 'icons/obj/capture_crystal_vr.dmi'
|
||||
|
||||
|
||||
//The basic capture command does most of the registration work.
|
||||
/obj/item/capture_crystal/cheap/capture(mob/living/M, mob/living/U)
|
||||
if(!M.capture_crystal || M.capture_caught)
|
||||
to_chat(U, "<span class='warning'>This creature is not suitable for capture with this crystal.</span>")
|
||||
playsound(src, 'sound/effects/capture-crystal-negative.ogg', 75, 1, -1)
|
||||
return
|
||||
knowyoursignals(M, U)
|
||||
if(isanimal(M) || !M.client)
|
||||
to_chat(U, "<span class='warning'>This creature is not suitable for capture.</span>")
|
||||
playsound(src, 'sound/effects/capture-crystal-negative.ogg', 75, 1, -1)
|
||||
return
|
||||
owner = U
|
||||
if(!bound_mob)
|
||||
bound_mob = M
|
||||
bound_mob.capture_caught = TRUE
|
||||
persist_storable = FALSE
|
||||
desc = "A silent, unassuming crystal in what appears to be some kind of steel housing. This one seems to be cheapley made and can only handle a willing mind."
|
||||
|
||||
|
||||
/obj/item/capture_crystal/cheap/activate(mob/living/user, target)
|
||||
if(!cooldown_check()) //Are we ready to do things yet?
|
||||
to_chat(thrower, "<span class='notice'>\The [src] clicks unsatisfyingly... It is not ready yet.</span>")
|
||||
playsound(src, 'sound/effects/capture-crystal-negative.ogg', 75, 1, -1)
|
||||
return
|
||||
if(spawn_mob_type && !bound_mob) //We don't already have a mob, but we know what kind of mob we want
|
||||
bound_mob = new spawn_mob_type(src) //Well let's spawn it then!
|
||||
bound_mob.faction = user.faction
|
||||
spawn_mob_type = null
|
||||
capture(bound_mob, user)
|
||||
if(bound_mob) //We have a mob! Let's finish setting up.
|
||||
user.visible_message("\The [src] clicks, and then emits a small chime.", "\The [src] grows warm in your hand, something inside is awake.")
|
||||
active = TRUE
|
||||
if(!owner) //Do we have an owner? It's pretty unlikely that this would ever happen! But it happens, let's claim the crystal.
|
||||
owner = user
|
||||
if(isanimal(bound_mob))
|
||||
var/mob/living/simple_mob/S = bound_mob
|
||||
S.revivedby = user.name
|
||||
determine_action(user, target)
|
||||
return
|
||||
else if(isliving(target)) //So we don't have a mob, let's try to claim one! Is the target a mob?
|
||||
var/mob/living/M = target
|
||||
last_activate = world.time
|
||||
if(M.capture_caught) //Can't capture things that were already caught.
|
||||
playsound(src, 'sound/effects/capture-crystal-negative.ogg', 75, 1, -1)
|
||||
to_chat(user, "<span class='notice'>\The [src] clicks unsatisfyingly... \The [M] is already under someone else's control.</span>")
|
||||
return
|
||||
else if(M.stat == DEAD) //Is it dead? We can't influence dead things.
|
||||
playsound(src, 'sound/effects/capture-crystal-negative.ogg', 75, 1, -1)
|
||||
to_chat(user, "<span class='notice'>\The [src] clicks unsatisfyingly... \The [M] is not in a state to be captured.</span>")
|
||||
return
|
||||
else if(M.client) //Is it player controlled?
|
||||
capture_player(M, user) //We have to do things a little differently if so.
|
||||
return
|
||||
else if(!isanimal(M)) //So it's not player controlled, but it's also not a simplemob?
|
||||
to_chat(user, "<span class='warning'>This creature is not suitable for capture.</span>")
|
||||
playsound(src, 'sound/effects/capture-crystal-negative.ogg', 75, 1, -1)
|
||||
return
|
||||
var/mob/living/simple_mob/S = M
|
||||
if(!S.ai_holder) //We don't really want to capture simplemobs that don't have an AI
|
||||
to_chat(user, "<span class='warning'>This creature is not suitable for capture.</span>")
|
||||
playsound(src, 'sound/effects/capture-crystal-negative.ogg', 75, 1, -1)
|
||||
else //Shoot, it didn't work and now it's mad!!!
|
||||
S.ai_holder.go_wake()
|
||||
S.ai_holder.target = user
|
||||
S.ai_holder.track_target_position()
|
||||
S.ai_holder.set_stance(STANCE_FIGHT)
|
||||
user.visible_message("\The [src] bonks into \the [S], angering it!")
|
||||
playsound(src, 'sound/effects/capture-crystal-negative.ogg', 75, 1, -1)
|
||||
to_chat(user, "<span class='notice'>\The [src] clicks unsatisfyingly.</span>")
|
||||
update_icon()
|
||||
return
|
||||
//The target is not a mob, so let's not do anything.
|
||||
playsound(src, 'sound/effects/capture-crystal-negative.ogg', 75, 1, -1)
|
||||
to_chat(user, "<span class='notice'>\The [src] clicks unsatisfyingly.</span>")
|
||||
|
||||
@@ -17,62 +17,93 @@
|
||||
var/stored_examine
|
||||
var/identifier = "statue"
|
||||
var/material = "stone"
|
||||
var/adjective = "hardens"
|
||||
var/list/tail_lower_dirs = list(SOUTH, EAST, WEST)
|
||||
var/image/tail_image
|
||||
var/tail_alt = TAIL_UPPER_LAYER
|
||||
|
||||
/obj/structure/gargoyle/Initialize(mapload, var/mob/living/carbon/human/H)
|
||||
var/can_revert = TRUE
|
||||
var/was_rayed = FALSE
|
||||
|
||||
/obj/structure/gargoyle/Initialize(mapload, var/mob/living/carbon/human/H, var/ident_ovr, var/mat_ovr, var/adj_ovr, var/tint_ovr, var/revert = TRUE, var/discard_clothes)
|
||||
. = ..()
|
||||
if (isspace(loc) || isopenspace(loc))
|
||||
anchored = FALSE
|
||||
if (!istype(H) || !isturf(H.loc))
|
||||
return
|
||||
var/datum/component/gargoyle/comp = H.GetComponent(/datum/component/gargoyle)
|
||||
var/tint = rgb(255,255,255)
|
||||
var/tint = "#FFFFFF"
|
||||
if (comp)
|
||||
comp.cooldown = world.time + (15 SECONDS)
|
||||
comp.statue = src
|
||||
comp.transformed = TRUE
|
||||
comp.paused = FALSE
|
||||
identifier = comp.identifier
|
||||
material = comp.material
|
||||
tint = comp.tint
|
||||
identifier = length(comp.identifier) > 0 ? comp.identifier : initial(identifier)
|
||||
material = length(comp.material) > 0 ? comp.material : initial(material)
|
||||
tint = length(comp.tint) > 0 ? comp.tint : initial(tint)
|
||||
adjective = length(comp.adjective) > 0 ? comp.adjective : initial(adjective)
|
||||
if (copytext_char(adjective, -1) != "s")
|
||||
adjective += "s"
|
||||
gargoyle = H
|
||||
|
||||
if (H.get_effective_size(TRUE) < 0.5) // "So small! I can step over it!"
|
||||
density = FALSE
|
||||
|
||||
if (ident_ovr)
|
||||
identifier = ident_ovr
|
||||
if (mat_ovr)
|
||||
material = mat_ovr
|
||||
if (adj_ovr)
|
||||
adjective = adj_ovr
|
||||
if (tint_ovr)
|
||||
tint = tint_ovr
|
||||
|
||||
if (H.tail_style?.clip_mask_state)
|
||||
tail_lower_dirs.Cut()
|
||||
else if (H.tail_style)
|
||||
tail_lower_dirs = H.tail_style.lower_layer_dirs.Copy()
|
||||
tail_alt = H.tail_alt ? TAIL_UPPER_LAYER_ALT : TAIL_UPPER_LAYER
|
||||
|
||||
max_integrity = H.getMaxHealth() + 100
|
||||
obj_integrity = H.health + 100
|
||||
original_int = obj_integrity
|
||||
name = "[identifier] of [H.name]"
|
||||
desc = "A very lifelike [identifier]."
|
||||
desc = "A very lifelike [identifier] made of [material]."
|
||||
stored_examine = H.examine()
|
||||
description_fluff = H.get_description_fluff()
|
||||
|
||||
if (H.buckled)
|
||||
H.buckled.unbuckle_mob(H, TRUE)
|
||||
icon = H.icon
|
||||
copy_overlays(H)
|
||||
//icon = H.icon
|
||||
//copy_overlays(H)
|
||||
|
||||
//calculate our tints
|
||||
var/list/RGB = rgb2num(tint)
|
||||
|
||||
var/list/RGB = list( hex2num( "[tint[2]][tint[3]]" ),
|
||||
hex2num( "[tint[4]][tint[5]]" ),
|
||||
hex2num( "[tint[6]][tint[7]]" )
|
||||
)
|
||||
var/colorr = rgb(RGB[1]*0.299, RGB[2]*0.299, RGB[3]*0.299)
|
||||
var/colorg = rgb(RGB[1]*0.587, RGB[2]*0.587, RGB[3]*0.587)
|
||||
var/colorb = rgb(RGB[1]*0.114, RGB[2]*0.114, RGB[3]*0.114)
|
||||
|
||||
var/colora = rgb( RGB[1]*0.299,
|
||||
RGB[2]*0.299,
|
||||
RGB[3]*0.299
|
||||
)
|
||||
|
||||
var/colorb = rgb( RGB[1]*0.587,
|
||||
RGB[2]*0.587,
|
||||
RGB[3]*0.587
|
||||
)
|
||||
|
||||
var/colorc = rgb( RGB[1]*0.114,
|
||||
RGB[2]*0.114,
|
||||
RGB[3]*0.114
|
||||
)
|
||||
|
||||
color = list( colora, colorb , colorc, rgb(0,0,0))
|
||||
var/tint_color = list(colorr, colorg, colorb, "#000000")
|
||||
|
||||
var/list/body_layers = HUMAN_BODY_LAYERS
|
||||
var/list/other_layers = HUMAN_OTHER_LAYERS
|
||||
for (var/i = 1; i <= length(H.overlays_standing); i++)
|
||||
if (i in other_layers)
|
||||
continue
|
||||
if (discard_clothes && !(i in body_layers))
|
||||
continue
|
||||
if (istype(H.overlays_standing[i], /image) && (i in body_layers))
|
||||
var/image/old_image = H.overlays_standing[i]
|
||||
var/image/new_image = image(old_image)
|
||||
if (i == TAIL_LOWER_LAYER || i == TAIL_UPPER_LAYER || i == TAIL_UPPER_LAYER_ALT)
|
||||
tail_image = new_image
|
||||
new_image.color = tint_color
|
||||
new_image.layer = old_image.layer
|
||||
add_overlay(new_image)
|
||||
else
|
||||
if (!isnull(H.overlays_standing[i]))
|
||||
add_overlay(H.overlays_standing[i])
|
||||
|
||||
initial_sleep = H.sleeping
|
||||
initial_blind = H.eye_blind
|
||||
@@ -92,7 +123,7 @@
|
||||
flapping = H.flapping
|
||||
H.toggle_tail(FALSE, FALSE)
|
||||
H.toggle_wing(FALSE, FALSE)
|
||||
H.visible_message("<span class='warning'>[H]'s skin rapidly turns to [material]!</span>", "<span class='warning'>Your skin abruptly [comp.adjective] as you turn to [material]!</span>")
|
||||
H.visible_message("<span class='warning'>[H]'s skin rapidly [adjective] as they turn to [material]!</span>", "<span class='warning'>Your skin abruptly [adjective] as you turn to [material]!</span>")
|
||||
H.forceMove(src)
|
||||
H.SetBlinded(0)
|
||||
H.SetSleeping(0)
|
||||
@@ -100,10 +131,28 @@
|
||||
H.updatehealth()
|
||||
H.canmove = 0
|
||||
|
||||
can_revert = revert
|
||||
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
|
||||
/obj/structure/gargoyle/Destroy()
|
||||
unpetrify()
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
if (!gargoyle)
|
||||
return ..()
|
||||
if (can_revert)
|
||||
unpetrify(deleting = TRUE)
|
||||
else
|
||||
visible_message("<span class='warning'>The [identifier] loses shape and crumbles into a pile of [material]!</span>")
|
||||
qdel(gargoyle)
|
||||
. = ..()
|
||||
|
||||
/obj/structure/gargoyle/process()
|
||||
if (!gargoyle)
|
||||
qdel(src)
|
||||
if (gargoyle.loc != src)
|
||||
can_revert = TRUE //something's gone wrong, they escaped, lets not qdel them
|
||||
unpetrify(FALSE)
|
||||
|
||||
/obj/structure/gargoyle/examine_icon()
|
||||
var/icon/examine_icon = ..()
|
||||
examine_icon.MapColors(rgb(77,77,77), rgb(150,150,150), rgb(28,28,28), rgb(0,0,0))
|
||||
@@ -122,7 +171,7 @@
|
||||
. += stored_examine
|
||||
return
|
||||
|
||||
/obj/structure/gargoyle/proc/unpetrify()
|
||||
/obj/structure/gargoyle/proc/unpetrify(var/deal_damage = TRUE, var/deleting = FALSE)
|
||||
if (!gargoyle)
|
||||
return
|
||||
var/datum/component/gargoyle/comp = gargoyle.GetComponent(/datum/component/gargoyle)
|
||||
@@ -130,16 +179,20 @@
|
||||
comp.cooldown = world.time + (15 SECONDS)
|
||||
comp.statue = null
|
||||
comp.transformed = FALSE
|
||||
gargoyle.forceMove(loc)
|
||||
gargoyle.transform = transform
|
||||
gargoyle.pixel_x = pixel_x
|
||||
gargoyle.pixel_y = pixel_y
|
||||
gargoyle.is_shifted = initial_is_shifted
|
||||
gargoyle.dir = dir
|
||||
gargoyle.lying = initial_lying
|
||||
gargoyle.lying_prev = initial_lying_prev
|
||||
gargoyle.toggle_tail(wagging, FALSE)
|
||||
gargoyle.toggle_wing(flapping, FALSE)
|
||||
else
|
||||
if (was_rayed)
|
||||
gargoyle.verbs -= /mob/living/carbon/human/proc/gargoyle_transformation
|
||||
if (gargoyle.loc == src)
|
||||
gargoyle.forceMove(loc)
|
||||
gargoyle.transform = transform
|
||||
gargoyle.pixel_x = pixel_x
|
||||
gargoyle.pixel_y = pixel_y
|
||||
gargoyle.is_shifted = initial_is_shifted
|
||||
gargoyle.dir = dir
|
||||
gargoyle.lying = initial_lying
|
||||
gargoyle.lying_prev = initial_lying_prev
|
||||
gargoyle.toggle_tail(wagging, FALSE)
|
||||
gargoyle.toggle_wing(flapping, FALSE)
|
||||
gargoyle.sdisabilities &= ~MUTE //why is there no ADD_TRAIT etc here that's actually ussssed
|
||||
gargoyle.status_flags &= ~GODMODE
|
||||
gargoyle.SetBlinded(initial_blind)
|
||||
@@ -148,14 +201,18 @@
|
||||
gargoyle.canmove = 1
|
||||
gargoyle.update_canmove()
|
||||
var/hurtmessage = ""
|
||||
if (obj_integrity < original_int)
|
||||
var/f = (original_int - obj_integrity) / 10
|
||||
for (var/x in 1 to 10)
|
||||
gargoyle.adjustBruteLoss(f)
|
||||
hurtmessage = " <b>You feel your body take the damage that was dealt while being [material]!</b>"
|
||||
if (deal_damage)
|
||||
if (obj_integrity < original_int)
|
||||
var/f = (original_int - obj_integrity) / 10
|
||||
for (var/x in 1 to 10)
|
||||
gargoyle.adjustBruteLoss(f)
|
||||
hurtmessage = " <b>You feel your body take the damage that was dealt while being [material]!</b>"
|
||||
gargoyle.updatehealth()
|
||||
alpha = 0
|
||||
gargoyle.visible_message("<span class='warning'>[gargoyle]'s skin rapidly reverts, returning them to normal!</span>", "<span class='warning'>Your skin reverts, freeing your movement once more![hurtmessage]</span>")
|
||||
gargoyle = null
|
||||
if (!deleting)
|
||||
qdel(src)
|
||||
|
||||
/obj/structure/gargoyle/return_air()
|
||||
return return_air_for_internal_lifeform()
|
||||
@@ -168,6 +225,8 @@
|
||||
return air
|
||||
|
||||
/obj/structure/gargoyle/proc/damage(var/damage)
|
||||
if (was_rayed)
|
||||
return //gargoyle quick regenerates, the others don't, so let's not have them getting too damaged
|
||||
obj_integrity = min(obj_integrity-damage, max_integrity)
|
||||
if(obj_integrity <= 0)
|
||||
qdel(src)
|
||||
@@ -197,4 +256,11 @@
|
||||
playsound(src, W.hitsound, 50, 1)
|
||||
damage(W.force)
|
||||
else
|
||||
return ..()
|
||||
return ..()
|
||||
|
||||
/obj/structure/gargoyle/set_dir(var/new_dir)
|
||||
. = ..()
|
||||
if(. && tail_image)
|
||||
cut_overlay(tail_image)
|
||||
tail_image.layer = BODY_LAYER + ((dir in tail_lower_dirs) ? TAIL_LOWER_LAYER : tail_alt)
|
||||
add_overlay(tail_image)
|
||||
|
||||
Reference in New Issue
Block a user