Breaks up mining loot into multiple files, refactors the hierophant club (#89751)

Splits up tendril_loot.dm and megafauna_loot.dm (both over a thousand
lines long) into group/item specific files, and megafauna-specific files
respectively. Also pulls a few loot items scattered around the codebase
into those files as well.

Additionally while doing so I've cleaned up the code for some of them,
and rewrote the hierophant club's code because it was abominable and a
potential source of harddels.

Its absolutely unnavigateable.

🆑
code: Split and cleaned up mining loot's code
refactor: Refactored the hierophant club.
fix: Hierophant club's beacon no longer can go missing (until you try
using it)
/🆑
This commit is contained in:
SmArtKar
2025-03-12 17:03:37 -04:00
committed by Roxy
parent 4d0e12a240
commit 4e4f5f248c
25 changed files with 3234 additions and 3158 deletions
@@ -218,127 +218,6 @@
. = ..()
AddComponent(/datum/component/armor_plate, upgrade_item = /obj/item/clothing/accessory/talisman)
/obj/item/clothing/suit/hooded/cloak/drake
name = "drake armour"
icon_state = "dragon"
desc = "A suit of armour fashioned from the remains of an ash drake."
armor_type = /datum/armor/cloak_drake
hoodtype = /obj/item/clothing/head/hooded/cloakhood/drake
body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT
heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
resistance_flags = FIRE_PROOF | ACID_PROOF
transparent_protection = HIDEGLOVES|HIDESUITSTORAGE|HIDEJUMPSUIT|HIDESHOES
/datum/armor/cloak_drake
melee = 65
bullet = 15
laser = 40
energy = 40
bomb = 70
bio = 60
fire = 100
acid = 100
wound = 10
/obj/item/clothing/suit/hooded/cloak/drake/Initialize(mapload)
. = ..()
allowed = GLOB.mining_suit_allowed
/obj/item/clothing/head/hooded/cloakhood/drake
name = "drake helm"
icon = 'icons/obj/clothing/head/helmet.dmi'
worn_icon = 'icons/mob/clothing/head/helmet.dmi'
icon_state = "dragon"
desc = "The skull of a dragon."
armor_type = /datum/armor/cloak_drake
clothing_flags = SNUG_FIT
cold_protection = HEAD
min_cold_protection_temperature = FIRE_HELM_MIN_TEMP_PROTECT
heat_protection = HEAD
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
resistance_flags = FIRE_PROOF | ACID_PROOF
/obj/item/clothing/suit/hooded/cloak/godslayer
name = "godslayer armour"
icon_state = "godslayer"
desc = "A suit of armour fashioned from the remnants of a knight's armor, and parts of a wendigo."
armor_type = /datum/armor/cloak_godslayer
clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL
hoodtype = /obj/item/clothing/head/hooded/cloakhood/godslayer
cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT
heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
resistance_flags = FIRE_PROOF | ACID_PROOF | FREEZE_PROOF
transparent_protection = HIDEGLOVES|HIDESUITSTORAGE|HIDEJUMPSUIT|HIDESHOES
/// Amount to heal when the effect is triggered
var/heal_amount = 500
/// Time until the effect can take place again
var/effect_cooldown_time = 10 MINUTES
/// Current cooldown for the effect
COOLDOWN_DECLARE(effect_cooldown)
var/static/list/damage_heal_order = list(BRUTE, BURN, OXY)
/datum/armor/cloak_godslayer
melee = 50
bullet = 25
laser = 25
energy = 25
bomb = 50
bio = 50
fire = 100
acid = 100
wound = 10
/obj/item/clothing/suit/hooded/cloak/godslayer/Initialize(mapload)
. = ..()
allowed = GLOB.mining_suit_allowed
AddComponent(/datum/component/item_equipped_movement_rustle, SFX_PLATE_ARMOR_RUSTLE, 8)
/obj/item/clothing/head/hooded/cloakhood/godslayer
name = "godslayer helm"
icon = 'icons/obj/clothing/head/helmet.dmi'
worn_icon = 'icons/mob/clothing/head/helmet.dmi'
icon_state = "godslayer"
desc = "The horns and skull of a wendigo, held together by the remaining icy energy of a demonic miner."
armor_type = /datum/armor/cloak_godslayer
clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL | SNUG_FIT
cold_protection = HEAD
min_cold_protection_temperature = FIRE_HELM_MIN_TEMP_PROTECT
heat_protection = HEAD
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
flash_protect = FLASH_PROTECTION_WELDER
flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH | PEPPERPROOF
resistance_flags = FIRE_PROOF | ACID_PROOF | FREEZE_PROOF
/obj/item/clothing/suit/hooded/cloak/godslayer/examine(mob/user)
. = ..()
if(loc == user && !COOLDOWN_FINISHED(src, effect_cooldown))
. += "You feel like the revival effect will be able to occur again in [COOLDOWN_TIMELEFT(src, effect_cooldown) / 10] seconds."
/obj/item/clothing/suit/hooded/cloak/godslayer/equipped(mob/user, slot)
. = ..()
if(slot & ITEM_SLOT_OCLOTHING)
RegisterSignal(user, COMSIG_MOB_STATCHANGE, PROC_REF(resurrect))
return
UnregisterSignal(user, COMSIG_MOB_STATCHANGE)
/obj/item/clothing/suit/hooded/cloak/godslayer/dropped(mob/user)
..()
UnregisterSignal(user, COMSIG_MOB_STATCHANGE)
/obj/item/clothing/suit/hooded/cloak/godslayer/proc/resurrect(mob/living/carbon/user, new_stat)
SIGNAL_HANDLER
if(new_stat > CONSCIOUS && new_stat < DEAD && COOLDOWN_FINISHED(src, effect_cooldown))
COOLDOWN_START(src, effect_cooldown, effect_cooldown_time) //This needs to happen first, otherwise there's an infinite loop
user.heal_ordered_damage(heal_amount, damage_heal_order)
user.visible_message(span_notice("[user] suddenly revives, as their armor swirls with demonic energy!"), span_notice("You suddenly feel invigorated!"))
playsound(user.loc, 'sound/effects/magic/clockwork/ratvar_attack.ogg', 50)
/obj/item/clothing/suit/hooded/explorer/syndicate
name = "syndicate explorer suit"
desc = "An armoured suit for exploring harsh environments, dyed in the sinister red and black of the Syndicate. This one seems better armored than the ones Nanotrasen gives out."
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,151 @@
#define MAX_BERSERK_CHARGE 100
#define PROJECTILE_HIT_MULTIPLIER 1.5
#define DAMAGE_TO_CHARGE_SCALE 0.75
#define CHARGE_DRAINED_PER_SECOND 5
#define BERSERK_ATTACK_SPEED_MODIFIER 0.25
/obj/item/clothing/suit/hooded/berserker
name = "berserker armor"
desc = "This hulking armor seems to possess some kind of dark force within; howling in rage, hungry for carnage. \
The self-sealing stem bolts that allowed this suit to be spaceworthy have long since corroded. However, the entity \
sealed within the suit seems to hunger for the fleeting lifeforce found in the remains left in the remains of drakes. \
Feeding it drake remains seems to empower a suit piece, though turns the remains back to lifeless ash."
icon_state = "berserker"
icon = 'icons/obj/clothing/suits/armor.dmi'
worn_icon = 'icons/mob/clothing/suits/armor.dmi'
worn_icon_digi = 'modular_skyrat/master_files/icons/mob/clothing/suit_digi.dmi' // SKYRAT EDIT - DIGIS
hoodtype = /obj/item/clothing/head/hooded/berserker
armor_type = /datum/armor/hooded_berserker
cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT
heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
resistance_flags = FIRE_PROOF | ACID_PROOF
clothing_flags = THICKMATERIAL|HEADINTERNALS
/datum/armor/hooded_berserker
melee = 30
bullet = 30
laser = 10
energy = 20
bomb = 50
bio = 60
fire = 100
acid = 100
wound = 10
/datum/armor/drake_empowerment
melee = 35
laser = 30
energy = 20
bomb = 20
/obj/item/clothing/suit/hooded/berserker/Initialize(mapload)
. = ..()
AddComponent(/datum/component/anti_magic, ALL, inventory_flags = ITEM_SLOT_OCLOTHING)
AddComponent(/datum/component/armor_plate, maxamount = 1, upgrade_item = /obj/item/drake_remains, armor_mod = /datum/armor/drake_empowerment, upgrade_prefix = "empowered")
allowed = GLOB.mining_suit_allowed
/obj/item/clothing/head/hooded/berserker
name = "berserker helmet"
desc = "This burdensome helmet seems to possess some kind of dark force within; howling in rage, hungry for carnage. \
The self-sealing stem bolts that allowed this helmet to be spaceworthy have long since corroded. However, the entity \
sealed within the suit seems to hunger for the fleeting lifeforce found in the remains left in the remains of drakes. \
Feeding it drake remains seems to empower a suit piece, though turns the remains back to lifeless ash."
icon_state = "berserker"
icon = 'icons/obj/clothing/head/helmet.dmi'
worn_icon = 'icons/mob/clothing/head/helmet.dmi'
armor_type = /datum/armor/hooded_berserker
actions_types = list(/datum/action/item_action/berserk_mode)
cold_protection = HEAD
min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT
heat_protection = HEAD
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
flags_inv = HIDEHAIR|HIDEFACE|HIDEEARS|HIDESNOUT
resistance_flags = FIRE_PROOF | ACID_PROOF
clothing_flags = SNUG_FIT|THICKMATERIAL
/// Current charge of berserk, goes from 0 to 100
var/berserk_charge = 0
/// Status of berserk
var/berserk_active = FALSE
/obj/item/clothing/head/hooded/berserker/Initialize(mapload)
. = ..()
ADD_TRAIT(src, TRAIT_NODROP, LOCKED_HELMET_TRAIT)
AddComponent(/datum/component/armor_plate, maxamount = 1, upgrade_item = /obj/item/drake_remains, armor_mod = /datum/armor/drake_empowerment, upgrade_prefix = "empowered")
AddComponent(/datum/component/item_equipped_movement_rustle, SFX_PLATE_ARMOR_RUSTLE, 8)
/obj/item/clothing/head/hooded/berserker/examine()
. = ..()
. += span_notice("Berserk mode is [berserk_charge]% charged.")
/obj/item/clothing/head/hooded/berserker/process(seconds_per_tick)
if(berserk_active)
berserk_charge = clamp(berserk_charge - CHARGE_DRAINED_PER_SECOND * seconds_per_tick, 0, MAX_BERSERK_CHARGE)
if(!berserk_charge)
if(ishuman(loc))
end_berserk(loc)
/obj/item/clothing/head/hooded/berserker/dropped(mob/user)
. = ..()
end_berserk(user)
/obj/item/clothing/head/hooded/berserker/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK, damage_type = BRUTE)
if(berserk_active)
return
var/berserk_value = damage * DAMAGE_TO_CHARGE_SCALE
if(attack_type == PROJECTILE_ATTACK)
berserk_value *= PROJECTILE_HIT_MULTIPLIER
berserk_charge = clamp(round(berserk_charge + berserk_value), 0, MAX_BERSERK_CHARGE)
if(berserk_charge >= MAX_BERSERK_CHARGE)
var/datum/action/item_action/berserk_mode/ragemode = locate() in actions
to_chat(owner, span_cult_large("Berserk mode is fully charged."))
balloon_alert(owner, "berserk charged")
ragemode?.build_all_button_icons(UPDATE_BUTTON_STATUS)
/obj/item/clothing/head/hooded/berserker/IsReflect()
return berserk_active
/// Starts berserk, reducing incoming brute by 50%, doubled attacking speed, NOGUNS trait, adding a color and giving them the berserk movespeed modifier
/obj/item/clothing/head/hooded/berserker/proc/berserk_mode(mob/living/carbon/human/user)
var/datum/action/item_action/berserk_mode/ragemode = locate() in actions
to_chat(user, span_cult("You enter berserk mode."))
playsound(user, 'sound/effects/magic/staff_healing.ogg', 50)
user.add_movespeed_modifier(/datum/movespeed_modifier/berserk)
user.physiology.brute_mod *= 0.5
user.next_move_modifier *= BERSERK_ATTACK_SPEED_MODIFIER
user.add_atom_colour(COLOR_BUBBLEGUM_RED, TEMPORARY_COLOUR_PRIORITY)
user.add_traits(list(TRAIT_NOGUNS, TRAIT_TOSS_GUN_HARD), BERSERK_TRAIT)
ADD_TRAIT(src, TRAIT_NODROP, BERSERK_TRAIT)
berserk_active = TRUE
START_PROCESSING(SSobj, src)
ragemode?.build_all_button_icons(UPDATE_BUTTON_STATUS)
/// Ends berserk, reverting the changes from the proc [berserk_mode]
/obj/item/clothing/head/hooded/berserker/proc/end_berserk(mob/living/carbon/human/user)
if(!berserk_active)
return
berserk_active = FALSE
if(QDELETED(user))
return
var/datum/action/item_action/berserk_mode/ragemode = locate() in actions
ragemode?.build_all_button_icons(UPDATE_BUTTON_STATUS)
to_chat(user, span_cult("You exit berserk mode."))
playsound(user, 'sound/effects/magic/summonitems_generic.ogg', 50)
user.remove_movespeed_modifier(/datum/movespeed_modifier/berserk)
user.physiology.brute_mod *= 2
user.next_move_modifier /= BERSERK_ATTACK_SPEED_MODIFIER
user.remove_atom_colour(TEMPORARY_COLOUR_PRIORITY, COLOR_BUBBLEGUM_RED)
user.remove_traits(list(TRAIT_NOGUNS, TRAIT_TOSS_GUN_HARD), BERSERK_TRAIT)
REMOVE_TRAIT(src, TRAIT_NODROP, BERSERK_TRAIT)
STOP_PROCESSING(SSobj, src)
#undef MAX_BERSERK_CHARGE
#undef PROJECTILE_HIT_MULTIPLIER
#undef DAMAGE_TO_CHARGE_SCALE
#undef CHARGE_DRAINED_PER_SECOND
#undef BERSERK_ATTACK_SPEED_MODIFIER
@@ -0,0 +1,141 @@
// Memento Mori
/obj/item/clothing/neck/necklace/memento_mori
name = "Memento Mori"
desc = "A mysterious pendant. An inscription on it says: \"Certain death tomorrow means certain life today.\""
icon = 'icons/obj/mining_zones/artefacts.dmi'
icon_state = "memento_mori"
worn_icon_state = "memento"
actions_types = list(/datum/action/item_action/hands_free/memento_mori)
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
var/mob/living/carbon/human/active_owner
/obj/item/clothing/neck/necklace/memento_mori/item_action_slot_check(slot)
return (slot & ITEM_SLOT_NECK)
/obj/item/clothing/neck/necklace/memento_mori/dropped(mob/user)
. = ..()
if(active_owner)
mori()
// Just in case
/obj/item/clothing/neck/necklace/memento_mori/Destroy()
if(active_owner)
mori()
return ..()
/obj/item/clothing/neck/necklace/memento_mori/proc/memento(mob/living/carbon/human/user)
to_chat(user, span_warning("You feel your life being drained by the pendant..."))
if (!do_after(user, 4 SECONDS, target = user))
return
to_chat(user, span_notice("Your lifeforce is now linked to the pendant! You feel like removing it would kill you, and yet you instinctively know that until then, you won't die."))
user.add_traits(list(TRAIT_NODEATH, TRAIT_NOHARDCRIT, TRAIT_NOCRITDAMAGE), CLOTHING_TRAIT)
RegisterSignal(user, COMSIG_LIVING_HEALTH_UPDATE, PROC_REF(check_health))
icon_state = "memento_mori_active"
active_owner = user
/obj/item/clothing/neck/necklace/memento_mori/proc/mori()
icon_state = "memento_mori"
if (!active_owner)
return
UnregisterSignal(active_owner, COMSIG_LIVING_HEALTH_UPDATE)
var/mob/living/carbon/human/stored_owner = active_owner //to avoid infinite looping when dust unequips the pendant
active_owner = null
to_chat(stored_owner, span_userdanger("You feel your life rapidly slipping away from you!"))
stored_owner.dust(TRUE, TRUE)
/obj/item/clothing/neck/necklace/memento_mori/proc/check_health(mob/living/source)
SIGNAL_HANDLER
var/list/guardians = source.get_all_linked_holoparasites()
if (!length(guardians))
return
if (source.health <= HEALTH_THRESHOLD_DEAD)
for (var/mob/guardian in guardians)
if(guardian.loc == src)
continue
consume_guardian(guardian)
else if (source.health > HEALTH_THRESHOLD_CRIT)
for (var/mob/guardian in guardians)
if(guardian.loc != src)
continue
regurgitate_guardian(guardian)
/obj/item/clothing/neck/necklace/memento_mori/proc/consume_guardian(mob/living/basic/guardian/guardian)
new /obj/effect/temp_visual/guardian/phase/out(get_turf(guardian))
guardian.locked = TRUE
guardian.forceMove(src)
to_chat(guardian, span_userdanger("You have been locked away in your summoner's pendant!"))
guardian.playsound_local(get_turf(guardian), 'sound/effects/magic/summonitems_generic.ogg', 50, TRUE)
/obj/item/clothing/neck/necklace/memento_mori/proc/regurgitate_guardian(mob/living/basic/guardian/guardian)
guardian.locked = FALSE
guardian.recall(forced = TRUE)
to_chat(guardian, span_notice("You have been returned back from your summoner's pendant!"))
guardian.playsound_local(get_turf(guardian), 'sound/effects/magic/repulse.ogg', 50, TRUE)
/datum/action/item_action/hands_free/memento_mori
check_flags = NONE
name = "Memento Mori"
desc = "Bind your life to the pendant."
/datum/action/item_action/hands_free/memento_mori/do_effect(trigger_flags)
var/obj/item/clothing/neck/necklace/memento_mori/memento = target
if(memento.active_owner || !ishuman(owner))
return FALSE
memento.memento(owner)
Remove(memento.active_owner) //Remove the action button, since there's no real use in having it now.
return TRUE
// Concussive Gauntlets
/obj/item/clothing/gloves/gauntlets
name = "concussive gauntlets"
desc = "Pickaxes... for your hands!"
icon_state = "concussive_gauntlets"
inhand_icon_state = null
toolspeed = 0.1
strip_delay = 40
equip_delay_other = 20
cold_protection = HANDS
min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT
heat_protection = HANDS
max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT
body_parts_covered = HANDS|ARMS
resistance_flags = LAVA_PROOF | FIRE_PROOF //they are from lavaland after all
armor_type = /datum/armor/gloves_gauntlets
/datum/armor/gloves_gauntlets
melee = 15
bullet = 25
laser = 15
energy = 15
bomb = 100
fire = 100
acid = 30
/obj/item/clothing/gloves/gauntlets/equipped(mob/user, slot)
. = ..()
if(slot & ITEM_SLOT_GLOVES)
tool_behaviour = TOOL_MINING
RegisterSignal(user, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(rocksmash))
RegisterSignal(user, COMSIG_MOVABLE_BUMP, PROC_REF(rocksmash))
else
stopmining(user)
/obj/item/clothing/gloves/gauntlets/dropped(mob/user)
. = ..()
stopmining(user)
/obj/item/clothing/gloves/gauntlets/proc/stopmining(mob/user)
tool_behaviour = initial(tool_behaviour)
UnregisterSignal(user, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_MOVABLE_BUMP))
/obj/item/clothing/gloves/gauntlets/proc/rocksmash(mob/living/carbon/human/user, atom/rocks, proximity)
SIGNAL_HANDLER
if(!proximity)
return NONE
if(!ismineralturf(rocks) && !isasteroidturf(rocks))
return NONE
rocks.attackby(src, user)
return COMPONENT_CANCEL_ATTACK_CHAIN
@@ -0,0 +1,244 @@
// KA modkit design discs
/obj/item/disk/design_disk/modkit_disc
name = "KA Mod Disk"
desc = "A design disc containing the design for a unique kinetic accelerator modkit. It's compatible with a research console."
icon_state = "datadisk1"
var/modkit_design = /datum/design/unique_modkit
/obj/item/disk/design_disk/modkit_disc/Initialize(mapload)
. = ..()
blueprints += new modkit_design
/obj/item/disk/design_disk/modkit_disc/mob_and_turf_aoe
name = "Offensive Mining Explosion Mod Disk"
modkit_design = /datum/design/unique_modkit/offensive_turf_aoe
/obj/item/disk/design_disk/modkit_disc/rapid_repeater
name = "Rapid Repeater Mod Disk"
modkit_design = /datum/design/unique_modkit/rapid_repeater
/obj/item/disk/design_disk/modkit_disc/resonator_blast
name = "Resonator Blast Mod Disk"
modkit_design = /datum/design/unique_modkit/resonator_blast
/obj/item/disk/design_disk/modkit_disc/bounty
name = "Death Syphon Mod Disk"
modkit_design = /datum/design/unique_modkit/bounty
// Wisp Lantern
/obj/item/wisp_lantern
name = "spooky lantern"
desc = "This lantern gives off no light, but is home to a friendly wisp."
icon = 'icons/obj/lighting.dmi'
icon_state = "lantern-blue-on"
inhand_icon_state = "lantern-blue-on"
lefthand_file = 'icons/mob/inhands/equipment/mining_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/mining_righthand.dmi'
var/obj/effect/wisp/wisp
/obj/item/wisp_lantern/attack_self(mob/user)
. = ..()
if(!wisp)
to_chat(user, span_warning("The wisp has gone missing!"))
icon_state = "lantern-blue"
inhand_icon_state = "lantern-blue"
return
if(wisp.loc == src)
to_chat(user, span_notice("You release the wisp. It begins to bob around your head."))
icon_state = "lantern-blue"
inhand_icon_state = "lantern-blue"
wisp.orbit(user, 20)
SSblackbox.record_feedback("tally", "wisp_lantern", 1, "Freed")
return
to_chat(user, span_notice("You return the wisp to the lantern."))
icon_state = "lantern-blue-on"
inhand_icon_state = "lantern-blue-on"
wisp.forceMove(src)
SSblackbox.record_feedback("tally", "wisp_lantern", 1, "Returned")
/obj/item/wisp_lantern/Initialize(mapload)
. = ..()
wisp = new(src)
/obj/item/wisp_lantern/Destroy()
if(wisp)
if(wisp.loc == src)
qdel(wisp)
else
wisp.visible_message(span_notice("[wisp] has a sad feeling for a moment, then it passes."))
return ..()
/obj/effect/wisp
name = "friendly wisp"
desc = "Happy to light your way."
icon = 'icons/obj/lighting.dmi'
icon_state = "orb"
light_system = OVERLAY_LIGHT
light_range = 6
light_power = 1.2
light_color = "#79f1ff"
light_flags = LIGHT_ATTACHED
layer = ABOVE_ALL_MOB_LAYER
plane = ABOVE_GAME_PLANE
var/static/list/color_cutoffs = list(10, 25, 25)
/obj/effect/wisp/orbit(atom/thing, radius, clockwise, rotation_speed, rotation_segments, pre_rotation, lockinorbit)
. = ..()
if(!ismob(thing))
return
var/mob/being = thing
RegisterSignal(being, COMSIG_MOB_UPDATE_SIGHT, PROC_REF(update_user_sight))
to_chat(being, span_notice("The wisp enhances your vision."))
ADD_TRAIT(being, TRAIT_THERMAL_VISION, REF(src))
being.update_sight()
/obj/effect/wisp/stop_orbit(datum/component/orbiter/orbits)
if(!ismob(orbit_target))
return ..()
var/mob/being = orbit_target
UnregisterSignal(being, COMSIG_MOB_UPDATE_SIGHT)
to_chat(being, span_notice("Your vision returns to normal."))
REMOVE_TRAIT(being, TRAIT_THERMAL_VISION, REF(src))
being.update_sight()
return ..()
/obj/effect/wisp/proc/update_user_sight(mob/user)
SIGNAL_HANDLER
if(!isnull(color_cutoffs))
user.lighting_color_cutoffs = blend_cutoff_colors(user.lighting_color_cutoffs, color_cutoffs)
// Jacob's ladder
/obj/item/jacobs_ladder
name = "jacob's ladder"
desc = "A celestial ladder that violates the laws of physics."
icon = 'icons/obj/structures.dmi'
icon_state = "ladder00"
/obj/item/jacobs_ladder/attack_self(mob/user)
var/turf/our_loc = get_turf(src)
var/ladder_x = our_loc.x
var/ladder_y = our_loc.y
to_chat(user, span_notice("You unfold the ladder. It extends much farther than you were expecting."))
var/last_ladder = null
for(var/i in 1 to world.maxz)
if(is_centcom_level(i) || is_reserved_level(i) || is_away_level(i))
continue
var/turf/new_loc = locate(ladder_x, ladder_y, i)
last_ladder = new /obj/structure/ladder/unbreakable/jacob(new_loc, null, last_ladder)
qdel(src)
// Inherit from unbreakable but don't set ID, to suppress the default Z linkage
/obj/structure/ladder/unbreakable/jacob
name = "jacob's ladder"
desc = "An indestructible celestial ladder that violates the laws of physics."
// Book of Babel
/obj/item/book_of_babel
name = "Book of Babel"
desc = "An ancient tome written in countless tongues."
icon = 'icons/obj/service/library.dmi'
icon_state = "book1"
w_class = WEIGHT_CLASS_SMALL
/obj/item/book_of_babel/attack_self(mob/user)
if(user.is_blind())
to_chat(user, span_warning("You are blind and can't read anything!"))
return FALSE
if(!user.can_read(src))
return FALSE
to_chat(user, span_notice("You flip through the pages of the book, quickly and conveniently learning every language in existence. Somewhat less conveniently, the aging book crumbles to dust in the process. Whoops."))
cure_curse_of_babel(user) // removes tower of babel if we have it
user.grant_all_languages(source = LANGUAGE_BABEL)
user.remove_blocked_language(GLOB.all_languages, source = LANGUAGE_ALL)
if(user.mind)
ADD_TRAIT(user.mind, TRAIT_TOWER_OF_BABEL, MAGIC_TRAIT) // this makes you immune to babel effects
new /obj/effect/decal/cleanable/ash(get_turf(user))
qdel(src)
// Potion of Flight
/obj/item/reagent_containers/cup/bottle/potion
icon = 'icons/obj/mining_zones/artefacts.dmi'
icon_state = "potionflask"
fill_icon = 'icons/obj/mining_zones/artefacts.dmi'
fill_icon_state = "potion_fill"
fill_icon_thresholds = list(0, 1)
/obj/item/reagent_containers/cup/bottle/potion/update_overlays()
. = ..()
if(reagents?.total_volume)
. += "potionflask_cap"
/obj/item/reagent_containers/cup/bottle/potion/flight
name = "strange elixir"
desc = "A flask with an almost-holy aura emitting from it. The label on the bottle says: 'erqo'hyy tvi'rf lbh jv'atf'."
list_reagents = list(/datum/reagent/flightpotion = 5)
/datum/reagent/flightpotion
name = "Flight Potion"
description = "Strange mutagenic compound of unknown origins."
color = "#976230"
/datum/reagent/flightpotion/expose_mob(mob/living/exposed_mob, methods=TOUCH, reac_volume, show_message = TRUE)
. = ..()
if(!ishuman(exposed_mob) || exposed_mob.stat == DEAD)
return
if(!(methods & (INGEST | TOUCH)))
return
var/mob/living/carbon/human/exposed_human = exposed_mob
var/obj/item/bodypart/chest/chest = exposed_human.get_bodypart(BODY_ZONE_CHEST)
if(!chest.wing_types || reac_volume < 5 || !exposed_human.dna)
if((methods & INGEST) && show_message)
to_chat(exposed_human, span_notice("<i>You feel nothing but a terrible aftertaste.</i>"))
return
var/had_wings = exposed_human.get_organ_slot(ORGAN_SLOT_EXTERNAL_WINGS)
var/wing_type = get_wing_choice(exposed_human, chest)
if(!wing_type)
return
var/obj/item/organ/wings/functional/wings = new wing_type()
wings.Insert(exposed_human)
exposed_human.dna.species.handle_mutant_bodyparts(exposed_human) // BUBBER EDIT OR BEGIN
if(had_wings)
to_chat(exposed_human, span_userdanger("A terrible pain travels down your back as your wings change shape!"))
else
to_chat(exposed_human, span_userdanger("A terrible pain travels down your back as wings burst out!"))
playsound(exposed_human.loc, 'sound/items/poster/poster_ripped.ogg', 50, TRUE, -1)
exposed_human.apply_damage(20, def_zone = BODY_ZONE_CHEST, forced = TRUE, wound_bonus = CANT_WOUND)
exposed_human.emote("scream")
/datum/reagent/flightpotion/proc/get_wing_choice(mob/living/carbon/human/needs_wings, obj/item/bodypart/chest/chest)
var/list/wing_types = chest.wing_types.Copy()
if (wing_types.len == 1 || !needs_wings.client)
return wing_types[1]
var/list/radial_wings = list()
var/list/name2type = list()
for(var/obj/item/organ/wings/functional/possible_type as anything in wing_types)
var/datum/sprite_accessory/accessory = initial(possible_type.sprite_accessory_override) //get the type
accessory = SSaccessories.sprite_accessories[initial(accessory.key)][initial(accessory.name)] //SKYRAT EDIT CHANGE - ORIGINAL: accessory = SSaccessories.wings_list[initial(accessory.name)] //get the singleton instance
var/image/img = image(icon = accessory.icon, icon_state = "m_wingsopen_[accessory.icon_state]_BEHIND") //Process the HUD elements
img.transform *= 0.5
img.pixel_x = -32
if(radial_wings[accessory.name])
stack_trace("Different wing types with repeated names. Please fix as this may cause issues.")
else
radial_wings[accessory.name] = img
name2type[accessory.name] = possible_type
var/wing_name = show_radial_menu(needs_wings, needs_wings, radial_wings, tooltips = TRUE)
var/wing_type = name2type[wing_name]
// If our chest gets replaced in the meanwile this can end up breaking, so we need to re-fetch it just to make sure
var/obj/item/bodypart/chest/new_chest = needs_wings.get_bodypart(BODY_ZONE_CHEST)
if(new_chest != chest)
chest = new_chest
wing_type = null
if(!wing_type)
if(!length(chest.wing_types))
return
wing_type = pick(chest.wing_types)
return wing_type
@@ -0,0 +1,238 @@
#define ATTACK_STRIKE "Hilt Strike"
#define ATTACK_SLICE "Wide Slice"
#define ATTACK_DASH "Dash Attack"
#define ATTACK_CUT "Tendon Cut"
#define ATTACK_CLOAK "Dark Cloak"
#define ATTACK_SHATTER "Shatter"
/obj/item/organ/cyberimp/arm/shard
name = "dark spoon shard"
desc = "An eerie metal shard surrounded by dark energies...of soup drinking. You probably don't think you should have been able to find this."
icon = 'icons/obj/mining_zones/artefacts.dmi'
icon_state = "cursed_katana_organ"
organ_flags = ORGAN_ORGANIC | ORGAN_FROZEN | ORGAN_UNREMOVABLE
items_to_create = list(/obj/item/kitchen/spoon)
extend_sound = 'sound/items/unsheath.ogg'
retract_sound = 'sound/items/sheath.ogg'
/obj/item/organ/cyberimp/arm/shard/attack_self(mob/user, modifiers)
. = ..()
to_chat(user, span_userdanger("The mass goes up your arm and goes inside it!"))
playsound(user, 'sound/effects/magic/demon_consume.ogg', 50, TRUE)
var/index = user.get_held_index_of_item(src)
zone = (index == LEFT_HANDS ? BODY_ZONE_L_ARM : BODY_ZONE_R_ARM)
SetSlotFromZone()
user.temporarilyRemoveItemFromInventory(src, TRUE)
Insert(user)
/obj/item/organ/cyberimp/arm/shard/screwdriver_act(mob/living/user, obj/item/screwtool)
return
/obj/item/organ/cyberimp/arm/shard/katana
name = "dark shard"
desc = "An eerie metal shard surrounded by dark energies."
items_to_create = list(/obj/item/cursed_katana)
/obj/item/organ/cyberimp/arm/shard/katana/Retract()
var/obj/item/cursed_katana/katana = active_item
if(!katana || katana.shattered)
return FALSE
if(!katana.drew_blood)
to_chat(owner, span_userdanger("[katana] lashes out at you in hunger!"))
playsound(owner, 'sound/effects/magic/demon_attack1.ogg', 50, TRUE)
owner.apply_damage(25, BRUTE, hand, wound_bonus = 10, sharpness = SHARP_EDGED)
katana.drew_blood = FALSE
katana.wash(CLEAN_TYPE_BLOOD)
return ..()
/obj/item/cursed_katana
name = "cursed katana"
desc = "A katana used to seal something vile away long ago. \
Even with the weapon destroyed, all the pieces containing the creature have coagulated back together to find a new host."
icon = 'icons/obj/mining_zones/artefacts.dmi'
icon_state = "cursed_katana"
icon_angle = -45
lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi'
force = 15
armour_penetration = 30
block_chance = 30
block_sound = 'sound/items/weapons/parry.ogg'
sharpness = SHARP_EDGED
w_class = WEIGHT_CLASS_HUGE
attack_verb_continuous = list("attacks", "slashes", "slices", "tears", "lacerates", "rips", "dices", "cuts")
attack_verb_simple = list("attack", "slash", "slice", "tear", "lacerate", "rip", "dice", "cut")
hitsound = 'sound/items/weapons/bladeslice.ogg'
resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | FREEZE_PROOF
var/shattered = FALSE
var/drew_blood = FALSE
var/static/list/combo_list = list(
ATTACK_STRIKE = list(COMBO_STEPS = list(LEFT_ATTACK, LEFT_ATTACK, RIGHT_ATTACK), COMBO_PROC = PROC_REF(strike)),
ATTACK_SLICE = list(COMBO_STEPS = list(RIGHT_ATTACK, LEFT_ATTACK, LEFT_ATTACK), COMBO_PROC = PROC_REF(slice)),
ATTACK_DASH = list(COMBO_STEPS = list(LEFT_ATTACK, RIGHT_ATTACK, RIGHT_ATTACK), COMBO_PROC = PROC_REF(dash)),
ATTACK_CUT = list(COMBO_STEPS = list(RIGHT_ATTACK, RIGHT_ATTACK, LEFT_ATTACK), COMBO_PROC = PROC_REF(cut)),
ATTACK_CLOAK = list(COMBO_STEPS = list(LEFT_ATTACK, RIGHT_ATTACK, LEFT_ATTACK, RIGHT_ATTACK), COMBO_PROC = PROC_REF(cloak)),
ATTACK_SHATTER = list(COMBO_STEPS = list(RIGHT_ATTACK, LEFT_ATTACK, RIGHT_ATTACK, LEFT_ATTACK), COMBO_PROC = PROC_REF(shatter)),
)
var/list/alt_continuous = list("stabs", "pierces", "impales")
var/list/alt_simple = list("stab", "pierce", "impale")
/obj/item/cursed_katana/Initialize(mapload)
. = ..()
alt_continuous = string_list(alt_continuous)
alt_simple = string_list(alt_simple)
AddComponent(/datum/component/alternative_sharpness, SHARP_POINTY, alt_continuous, alt_simple)
AddComponent( \
/datum/component/combo_attacks, \
combos = combo_list, \
max_combo_length = 4, \
examine_message = span_notice("<i>There seem to be inscriptions on it... you could examine them closer?</i>"), \
reset_message = "you return to neutral stance", \
can_attack_callback = CALLBACK(src, PROC_REF(can_combo_attack)) \
)
/obj/item/cursed_katana/examine(mob/user)
. = ..()
. += drew_blood ? span_nicegreen("It's sated... for now.") : span_danger("It will not be sated until it tastes blood.")
/obj/item/cursed_katana/dropped(mob/user)
. = ..()
if(isturf(loc))
qdel(src)
/obj/item/cursed_katana/attack(mob/living/target, mob/user, click_parameters)
if(target.stat < DEAD && target != user)
drew_blood = TRUE
if(ismining(target))
user.changeNext_move(CLICK_CD_RAPID)
return ..()
/obj/item/cursed_katana/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK, damage_type = BRUTE)
if(attack_type == PROJECTILE_ATTACK || attack_type == LEAP_ATTACK)
final_block_chance = 0 //Don't bring a sword to a gunfight, and also you aren't going to really block someone full body tackling you with a sword
return ..()
/obj/item/cursed_katana/proc/can_combo_attack(mob/user, mob/living/target)
return target.stat != DEAD && target != user
/obj/item/cursed_katana/proc/strike(mob/living/target, mob/user)
user.visible_message(span_warning("[user] strikes [target] with [src]'s hilt!"),
span_notice("You hilt strike [target]!"))
to_chat(target, span_userdanger("You've been struck by [user]!"))
playsound(src, 'sound/items/weapons/genhit3.ogg', 50, TRUE)
RegisterSignal(target, COMSIG_MOVABLE_IMPACT, PROC_REF(strike_throw_impact))
var/atom/throw_target = get_edge_target_turf(target, user.dir)
target.throw_at(throw_target, 5, 3, user, FALSE, gentle = TRUE)
target.apply_damage(damage = 17, bare_wound_bonus = 10)
to_chat(target, span_userdanger("You've been struck by [user]!"))
user.do_attack_animation(target, ATTACK_EFFECT_PUNCH)
/obj/item/cursed_katana/proc/strike_throw_impact(mob/living/source, atom/hit_atom, datum/thrownthing/thrownthing)
SIGNAL_HANDLER
UnregisterSignal(source, COMSIG_MOVABLE_IMPACT)
if(isclosedturf(hit_atom))
source.apply_damage(damage = 5)
if(ishostile(source))
var/mob/living/simple_animal/hostile/target = source
target.ranged_cooldown += 5 SECONDS
else if(iscarbon(source))
var/mob/living/carbon/target = source
target.set_confusion_if_lower(8 SECONDS)
return NONE
/obj/item/cursed_katana/proc/slice(mob/living/target, mob/user)
user.visible_message(span_warning("[user] does a wide slice!"),
span_notice("You do a wide slice!"))
playsound(src, 'sound/items/weapons/bladeslice.ogg', 50, TRUE)
user.do_item_attack_animation(target, used_item = src, animation_type = ATTACK_ANIMATION_SLASH)
var/turf/user_turf = get_turf(user)
var/dir_to_target = get_dir(user_turf, get_turf(target))
var/static/list/cursed_katana_slice_angles = list(0, -45, 45, -90, 90) //so that the animation animates towards the target clicked and not towards a side target
for(var/iteration in cursed_katana_slice_angles)
var/turf/turf = get_step(user_turf, turn(dir_to_target, iteration))
user.do_attack_animation(turf, ATTACK_EFFECT_SLASH)
for(var/mob/living/additional_target in turf)
if(user.Adjacent(additional_target) && additional_target.density)
additional_target.apply_damage(damage = 15, sharpness = SHARP_EDGED, bare_wound_bonus = 10)
to_chat(additional_target, span_userdanger("You've been sliced by [user]!"))
target.apply_damage(damage = 5, sharpness = SHARP_EDGED, wound_bonus = 10)
/obj/item/cursed_katana/proc/cloak(mob/living/target, mob/user)
user.alpha = 150
user.SetInvisibility(INVISIBILITY_OBSERVER, id=type) // so hostile mobs cant see us or target us
user.add_sight(SEE_SELF) // so we can see us
user.visible_message(span_warning("[user] vanishes into thin air!"),
span_notice("You enter the dark cloak."))
new /obj/effect/temp_visual/mook_dust(get_turf(src))
playsound(src, 'sound/effects/magic/smoke.ogg', 50, TRUE)
if(ishostile(target))
var/mob/living/simple_animal/hostile/hostile_target = target
if(hostile_target.target == user)
hostile_target.LoseTarget()
addtimer(CALLBACK(src, PROC_REF(uncloak), user), 5 SECONDS, TIMER_UNIQUE)
/obj/item/cursed_katana/proc/uncloak(mob/user)
user.alpha = 255
user.RemoveInvisibility(type)
user.clear_sight(SEE_SELF)
user.visible_message(span_warning("[user] appears from thin air!"),
span_notice("You exit the dark cloak."))
playsound(src, 'sound/effects/magic/summonitems_generic.ogg', 50, TRUE)
new /obj/effect/temp_visual/mook_dust(get_turf(src))
/obj/item/cursed_katana/proc/cut(mob/living/target, mob/user)
user.visible_message(span_warning("[user] cuts [target]'s tendons!"),
span_notice("You tendon cut [target]!"))
to_chat(target, span_userdanger("Your tendons have been cut by [user]!"))
user.do_item_attack_animation(target, used_item = src, animation_type = ATTACK_ANIMATION_SLASH)
target.apply_damage(damage = 15, sharpness = SHARP_EDGED, wound_bonus = 15)
user.do_attack_animation(target, ATTACK_EFFECT_DISARM)
playsound(src, 'sound/items/weapons/rapierhit.ogg', 50, TRUE)
var/datum/status_effect/stacking/saw_bleed/bloodletting/status = target.has_status_effect(/datum/status_effect/stacking/saw_bleed/bloodletting)
if(!status)
target.apply_status_effect(/datum/status_effect/stacking/saw_bleed/bloodletting, 6)
else
status.add_stacks(6)
/obj/item/cursed_katana/proc/dash(mob/living/target, mob/user)
user.visible_message(span_warning("[user] dashes through [target]!"),
span_notice("You dash through [target]!"))
to_chat(target, span_userdanger("[user] dashes through you!"))
playsound(src, 'sound/effects/magic/blink.ogg', 50, TRUE)
target.apply_damage(damage = 17, sharpness = SHARP_POINTY, bare_wound_bonus = 10)
var/turf/dash_target = get_turf(target)
for(var/distance in 0 to 8)
var/turf/current_dash_target = dash_target
current_dash_target = get_step(current_dash_target, user.dir)
if(!current_dash_target.is_blocked_turf(TRUE))
dash_target = current_dash_target
else
break
new /obj/effect/temp_visual/guardian/phase/out(get_turf(user))
new /obj/effect/temp_visual/guardian/phase(dash_target)
do_teleport(user, dash_target, channel = TELEPORT_CHANNEL_MAGIC)
/obj/item/cursed_katana/proc/shatter(mob/living/target, mob/user)
user.visible_message(span_warning("[user] shatters [src] over [target]!"),
span_notice("You shatter [src] over [target]!"))
to_chat(target, span_userdanger("[user] shatters [src] over you!"))
target.apply_damage(damage = ishostile(target) ? 75 : 35, wound_bonus = 20)
user.do_attack_animation(target, ATTACK_EFFECT_SMASH)
playsound(src, 'sound/effects/glass/glassbr3.ogg', 100, TRUE)
shattered = TRUE
moveToNullspace()
balloon_alert(user, "katana shattered")
addtimer(CALLBACK(src, PROC_REF(coagulate), user), 45 SECONDS)
/obj/item/cursed_katana/proc/coagulate(mob/user)
balloon_alert(user, "katana coagulated")
shattered = FALSE
playsound(src, 'sound/effects/magic/demon_consume.ogg', 50, TRUE)
#undef ATTACK_STRIKE
#undef ATTACK_SLICE
#undef ATTACK_DASH
#undef ATTACK_CUT
#undef ATTACK_CLOAK
#undef ATTACK_SHATTER
@@ -0,0 +1,251 @@
// Rod of Asclepius
/obj/item/rod_of_asclepius
name = "\improper Rod of Asclepius"
desc = "A wooden rod about the size of your forearm with a snake carved around it, winding its way up the sides of the rod. Something about it seems to inspire in you the responsibilty and duty to help others."
icon = 'icons/obj/mining_zones/artefacts.dmi'
lefthand_file = 'icons/mob/inhands/weapons/staves_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi'
icon_state = "asclepius_dormant"
inhand_icon_state = "asclepius_dormant"
icon_angle = -45
var/activated = FALSE
var/static/list/oath_lines = list(
"I swear to fulfill, to the best of my ability and judgment, this covenant:",
"I will apply, for the benefit of the sick, all measures that are required, avoiding those twin traps of overtreatment and therapeutic nihilism.",
"I will remember that I remain a member of society, with special obligations to all my fellow human beings, those sound of mind and body as well as the infirm.",
"If I do not violate this oath, may I enjoy life and art, respected while I live and remembered with affection thereafter. May I always act so as to preserve the finest traditions of my calling and may I long experience the joy of healing those who seek my help.",
)
/obj/item/rod_of_asclepius/Initialize(mapload)
. = ..()
AddElement(/datum/element/update_icon_updates_onmob)
/obj/item/rod_of_asclepius/update_desc(updates)
. = ..()
desc = activated ? "A short wooden rod with a mystical snake inseparably gripping itself and the rod to your forearm. It flows with a healing energy that disperses amongst yourself and those around you." : initial(desc)
/obj/item/rod_of_asclepius/update_icon_state()
. = ..()
icon_state = inhand_icon_state = "asclepius_[activated ? "active" : "dormant"]"
/obj/item/rod_of_asclepius/vv_edit_var(vname, vval)
. = ..()
if(vname == NAMEOF(src, activated) && activated)
activated()
/obj/item/rod_of_asclepius/attack_self(mob/user)
if(activated)
return
if(!iscarbon(user))
to_chat(user, span_warning("The snake carving seems to come alive, if only for a moment, before returning to its dormant state, almost as if it finds you incapable of holding its oath."))
return
var/mob/living/carbon/itemUser = user
var/usedHand = itemUser.get_held_index_of_item(src)
if(itemUser.has_status_effect(/datum/status_effect/hippocratic_oath))
to_chat(user, span_warning("You can't possibly handle the responsibility of more than one rod!"))
return
var/static/failText = span_warning("The snake seems unsatisfied with your incomplete oath and returns to its previous place on the rod, returning to its dormant, wooden state. You must stand still while completing your oath!")
to_chat(itemUser, span_notice("The wooden snake that was carved into the rod seems to suddenly come alive and begins to slither down your arm! The compulsion to help others grows abnormally strong..."))
for(var/oath_line in oath_lines)
if(do_after(itemUser, 3 SECONDS, target = itemUser))
itemUser.say(oath_line, forced = "hippocratic oath")
continue
balloon_alert(itemUser, "interrupted!")
to_chat(itemUser, failText)
return
to_chat(itemUser, span_notice("The snake, satisfied with your oath, attaches itself and the rod to your forearm with an inseparable grip. Your thoughts seem to only revolve around the core idea of helping others, and harm is nothing more than a distant, wicked memory..."))
var/datum/status_effect/hippocratic_oath/effect = itemUser.apply_status_effect(/datum/status_effect/hippocratic_oath)
effect.hand = usedHand
activated()
/obj/item/rod_of_asclepius/proc/activated()
item_flags = DROPDEL
ADD_TRAIT(src, TRAIT_NODROP, CURSED_ITEM_TRAIT(type))
activated = TRUE
update_appearance()
// Red/Blue Cubes
/obj/item/warp_cube
name = "blue cube"
desc = "A mysterious blue cube."
icon = 'icons/obj/mining_zones/artefacts.dmi'
icon_state = "blue_cube"
var/teleport_color = "#3FBAFD"
var/obj/item/warp_cube/linked
var/teleporting = FALSE
/obj/item/warp_cube/Destroy()
if(!QDELETED(linked))
qdel(linked)
linked = null
return ..()
/obj/item/warp_cube/attack_self(mob/user)
var/turf/current_location = get_turf(user)
if(!linked || isnull(get_turf(linked)) || !check_teleport_valid(src, current_location))
to_chat(user, span_warning("[src] fizzles uselessly."))
return
if(teleporting)
return
teleporting = TRUE
linked.teleporting = TRUE
var/turf/T = get_turf(src)
new /obj/effect/temp_visual/warp_cube(T, user, teleport_color, TRUE)
SSblackbox.record_feedback("tally", "warp_cube", 1, type)
new /obj/effect/temp_visual/warp_cube(get_turf(linked), user, linked.teleport_color, FALSE)
var/obj/effect/warp_cube/link_holder = new /obj/effect/warp_cube(T)
user.forceMove(link_holder) //mess around with loc so the user can't wander around
sleep(0.25 SECONDS)
if(QDELETED(user))
qdel(link_holder)
return
if(QDELETED(linked) || isnull(get_turf(linked)))
user.forceMove(get_turf(link_holder))
qdel(link_holder)
return
link_holder.forceMove(get_turf(linked))
sleep(0.25 SECONDS)
if(QDELETED(user))
qdel(link_holder)
return
teleporting = FALSE
if(!QDELETED(linked))
linked.teleporting = FALSE
user.forceMove(get_turf(link_holder))
qdel(link_holder)
/obj/item/warp_cube/red
name = "red cube"
desc = "A mysterious red cube."
icon_state = "red_cube"
teleport_color = "#FD3F48"
/obj/item/warp_cube/red/Initialize(mapload)
. = ..()
if(!linked)
var/obj/item/warp_cube/blue = new(src.loc)
linked = blue
blue.linked = src
/obj/effect/warp_cube
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
anchored = TRUE
// Immortality Talisman
/obj/item/immortality_talisman
name = "\improper Immortality Talisman"
desc = "A dread talisman that can render you completely invulnerable."
icon = 'icons/obj/mining_zones/artefacts.dmi'
icon_state = "talisman"
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
actions_types = list(/datum/action/item_action/immortality)
var/cooldown = 0
/obj/item/immortality_talisman/Initialize(mapload)
. = ..()
AddComponent(/datum/component/anti_magic, ALL)
/datum/action/item_action/immortality
name = "Immortality"
/obj/item/immortality_talisman/attack_self(mob/user)
if(cooldown < world.time)
SSblackbox.record_feedback("amount", "immortality_talisman_uses", 1)
cooldown = world.time + 600
new /obj/effect/immortality_talisman(get_turf(user), user)
else
to_chat(user, span_warning("[src] is not ready yet!"))
/obj/effect/immortality_talisman
name = "hole in reality"
desc = "It's shaped an awful lot like a person."
icon_state = "blank"
icon = 'icons/effects/effects.dmi'
var/vanish_description = "vanishes from reality"
// Weakref to the user who we're "acting" on
var/datum/weakref/user_ref
/obj/effect/immortality_talisman/Initialize(mapload, mob/new_user)
. = ..()
if(new_user)
vanish(new_user)
/obj/effect/immortality_talisman/Destroy()
// If we have a mob, we need to free it before cleanup
// This is a safety to prevent nuking a human, not so much a good pattern in general
unvanish()
return ..()
/obj/effect/immortality_talisman/proc/unvanish()
var/mob/user = user_ref?.resolve()
user_ref = null
if(!user)
return
user.remove_traits(list(TRAIT_GODMODE, TRAIT_NO_TRANSFORM), REF(src))
user.forceMove(get_turf(src))
user.visible_message(span_danger("[user] pops back into reality!"))
/obj/effect/immortality_talisman/proc/vanish(mob/user)
user.visible_message(span_danger("[user] [vanish_description], leaving a hole in [user.p_their()] place!"))
desc = "It's shaped an awful lot like [user.name]."
setDir(user.dir)
user.forceMove(src)
user.add_traits(list(TRAIT_GODMODE, TRAIT_NO_TRANSFORM), REF(src))
user_ref = WEAKREF(user)
addtimer(CALLBACK(src, PROC_REF(dissipate)), 10 SECONDS)
/obj/effect/immortality_talisman/proc/dissipate()
qdel(src)
/obj/effect/immortality_talisman/attackby()
return
/obj/effect/immortality_talisman/relaymove(mob/living/user, direction)
// Won't really come into play since our mob has TRAIT_NO_TRANSFORM and cannot move,
// but regardless block all relayed moves, because no, you cannot move in the void.
return
/obj/effect/immortality_talisman/singularity_pull(atom/singularity, current_size)
return
/obj/effect/immortality_talisman/void
vanish_description = "is dragged into the void"
// Shared Bag
/obj/item/shared_storage
name = "paradox bag"
desc = "Somehow, it's in two places at once."
icon = 'icons/obj/mining_zones/artefacts.dmi'
icon_state = "paradox_bag"
worn_icon_state = "paradoxbag"
slot_flags = ITEM_SLOT_BELT
resistance_flags = INDESTRUCTIBLE
/obj/item/shared_storage/red
/obj/item/shared_storage/red/Initialize(mapload)
. = ..()
create_storage(max_total_storage = 15, max_slots = 21)
new /obj/item/shared_storage/blue(drop_location(), src)
/obj/item/shared_storage/blue/Initialize(mapload, atom/master)
. = ..()
if(!istype(master))
return INITIALIZE_HINT_QDEL
create_storage(max_total_storage = 15, max_slots = 21)
atom_storage.set_real_location(master)
@@ -0,0 +1,113 @@
/obj/item/clothing/glasses/godeye
name = "eye of god"
desc = "A strange eye, said to have been torn from an omniscient creature that used to roam the wastes."
icon_state = "godeye"
inhand_icon_state = null
vision_flags = SEE_TURFS
clothing_traits = list(TRAIT_MADNESS_IMMUNE)
// Blue, light blue
color_cutoffs = list(15, 30, 40)
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
custom_materials = null
var/datum/action/cooldown/spell/pointed/scan/scan_ability
/obj/item/clothing/glasses/godeye/Initialize(mapload)
. = ..()
scan_ability = new(src)
/obj/item/clothing/glasses/godeye/Destroy()
QDEL_NULL(scan_ability)
return ..()
/obj/item/clothing/glasses/godeye/equipped(mob/living/user, slot)
. = ..()
if(ishuman(user) && (slot & ITEM_SLOT_EYES))
ADD_TRAIT(src, TRAIT_NODROP, EYE_OF_GOD_TRAIT)
pain(user)
scan_ability.Grant(user)
/obj/item/clothing/glasses/godeye/dropped(mob/living/user)
. = ..()
// Behead someone, their "glasses" drop on the floor
// and thus, the god eye should no longer be sticky
REMOVE_TRAIT(src, TRAIT_NODROP, EYE_OF_GOD_TRAIT)
// And remove the scan ability, note that if we're being called from Destroy
// that this may already be nulled and removed
scan_ability?.Remove(user)
/obj/item/clothing/glasses/godeye/proc/pain(mob/living/victim)
to_chat(victim, span_userdanger("You experience blinding pain, as [src] burrows into your skull."))
victim.emote("scream")
victim.flash_act()
/datum/action/cooldown/spell/pointed/scan
name = "Scan"
desc = "Scan an enemy, to get their location and rebuke them, increasing their time between attacks."
background_icon_state = "bg_clock"
overlay_icon_state = "bg_clock_border"
button_icon = 'icons/mob/actions/actions_items.dmi'
button_icon_state = "scan"
school = SCHOOL_HOLY
cooldown_time = 35 SECONDS
spell_requirements = SPELL_REQUIRES_NO_ANTIMAGIC
antimagic_flags = MAGIC_RESISTANCE_MIND //Even god cannot penetrate the tin foil hat
ranged_mousepointer = 'icons/effects/mouse_pointers/scan_target.dmi'
/datum/action/cooldown/spell/pointed/scan/is_valid_target(atom/cast_on)
if(!isliving(cast_on))
owner.balloon_alert(owner, "not a valid target!")
return FALSE
var/mob/living/living_cast_on = cast_on
if(living_cast_on.stat == DEAD)
owner.balloon_alert(owner, "target is dead!")
return FALSE
return TRUE
/datum/action/cooldown/spell/pointed/scan/cast(mob/living/cast_on)
. = ..()
if(cast_on.can_block_magic(MAGIC_RESISTANCE_MIND, charge_cost = 0))
to_chat(owner, span_warning("As we apply our dissecting vision, we are abruptly cut short. \
They have some kind of enigmatic mental defense. It seems we've been foiled."))
return
if(cast_on == owner)
to_chat(owner, span_warning("The last time a god stared too closely into their own reflection, they became transfixed for all of time. Do not let us become like them."))
return
var/mob/living/living_owner = owner
var/mob/living/living_scanned = cast_on
living_scanned.apply_status_effect(/datum/status_effect/rebuked)
var/datum/status_effect/agent_pinpointer/scan_pinpointer = living_owner.apply_status_effect(/datum/status_effect/agent_pinpointer/scan)
scan_pinpointer.scan_target = living_scanned
to_chat(living_scanned, span_warning("You briefly see a flash of [living_owner]'s face before being knocked off-balance by an unseen force!"))
living_scanned.add_filter("scan", 2, list("type" = "outline", "color" = COLOR_RED, "size" = 1))
addtimer(CALLBACK(living_scanned, TYPE_PROC_REF(/datum, remove_filter), "scan"), 30 SECONDS)
healthscan(living_owner, living_scanned, 1, TRUE)
owner.playsound_local(get_turf(owner), 'sound/effects/magic/smoke.ogg', 50, TRUE)
owner.balloon_alert(owner, "[living_scanned] scanned")
addtimer(CALLBACK(src, PROC_REF(send_cooldown_end_message), cooldown_time))
/datum/action/cooldown/spell/pointed/scan/proc/send_cooldown_end_message()
owner?.balloon_alert(owner, "scan recharged")
/datum/status_effect/agent_pinpointer/scan
duration = 15 SECONDS
alert_type = /atom/movable/screen/alert/status_effect/agent_pinpointer/scan
tick_interval = 2 SECONDS
range_fuzz_factor = 0
minimum_range = 1
range_mid = 5
range_far = 15
/datum/status_effect/agent_pinpointer/scan/scan_for_target()
return
/atom/movable/screen/alert/status_effect/agent_pinpointer/scan
name = "Scan Target"
desc = "Contact may or may not be close."
@@ -0,0 +1,77 @@
/obj/item/clothing/suit/hooded/cloak/godslayer
name = "godslayer armour"
icon_state = "godslayer"
desc = "A suit of armour fashioned from the remnants of a knight's armor, and parts of a wendigo."
armor_type = /datum/armor/cloak_godslayer
clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL
hoodtype = /obj/item/clothing/head/hooded/cloakhood/godslayer
cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT
heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
resistance_flags = FIRE_PROOF | ACID_PROOF | FREEZE_PROOF
transparent_protection = HIDEGLOVES|HIDESUITSTORAGE|HIDEJUMPSUIT|HIDESHOES
/// Amount to heal when the effect is triggered
var/heal_amount = 500
/// Time until the effect can take place again
var/effect_cooldown_time = 10 MINUTES
/// Current cooldown for the effect
COOLDOWN_DECLARE(effect_cooldown)
var/static/list/damage_heal_order = list(BRUTE, BURN, OXY)
/datum/armor/cloak_godslayer
melee = 50
bullet = 25
laser = 25
energy = 25
bomb = 50
bio = 50
fire = 100
acid = 100
wound = 10
/obj/item/clothing/suit/hooded/cloak/godslayer/Initialize(mapload)
. = ..()
allowed = GLOB.mining_suit_allowed
AddComponent(/datum/component/item_equipped_movement_rustle, SFX_PLATE_ARMOR_RUSTLE, 8)
/obj/item/clothing/suit/hooded/cloak/godslayer/examine(mob/user)
. = ..()
if(loc == user && !COOLDOWN_FINISHED(src, effect_cooldown))
. += "You feel like the revival effect will be able to occur again in [COOLDOWN_TIMELEFT(src, effect_cooldown) / 10] seconds."
/obj/item/clothing/suit/hooded/cloak/godslayer/equipped(mob/user, slot)
. = ..()
if(slot & ITEM_SLOT_OCLOTHING)
RegisterSignal(user, COMSIG_MOB_STATCHANGE, PROC_REF(resurrect))
return
UnregisterSignal(user, COMSIG_MOB_STATCHANGE)
/obj/item/clothing/suit/hooded/cloak/godslayer/dropped(mob/user)
..()
UnregisterSignal(user, COMSIG_MOB_STATCHANGE)
/obj/item/clothing/suit/hooded/cloak/godslayer/proc/resurrect(mob/living/carbon/user, new_stat)
SIGNAL_HANDLER
if(new_stat > CONSCIOUS && new_stat < DEAD && COOLDOWN_FINISHED(src, effect_cooldown))
COOLDOWN_START(src, effect_cooldown, effect_cooldown_time) //This needs to happen first, otherwise there's an infinite loop
user.heal_ordered_damage(heal_amount, damage_heal_order)
user.visible_message(span_notice("[user] suddenly revives, as their armor swirls with demonic energy!"), span_notice("You suddenly feel invigorated!"))
playsound(user.loc, 'sound/effects/magic/clockwork/ratvar_attack.ogg', 50)
/obj/item/clothing/head/hooded/cloakhood/godslayer
name = "godslayer helm"
icon = 'icons/obj/clothing/head/helmet.dmi'
worn_icon = 'icons/mob/clothing/head/helmet.dmi'
icon_state = "godslayer"
desc = "The horns and skull of a wendigo, held together by the remaining icy energy of a demonic miner."
armor_type = /datum/armor/cloak_godslayer
clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL | SNUG_FIT
cold_protection = HEAD
min_cold_protection_temperature = FIRE_HELM_MIN_TEMP_PROTECT
heat_protection = HEAD
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
flash_protect = FLASH_PROTECTION_WELDER
flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH | PEPPERPROOF
resistance_flags = FIRE_PROOF | ACID_PROOF | FREEZE_PROOF
@@ -0,0 +1,294 @@
// Ash drake suit
/obj/item/drake_remains
name = "drake remains"
desc = "The gathered remains of a drake. It still crackles with heat, and smells distinctly of brimstone."
icon = 'icons/obj/clothing/head/helmet.dmi'
icon_state = "dragon"
/obj/item/drake_remains/Initialize(mapload)
. = ..()
add_shared_particles(/particles/bonfire)
/obj/item/drake_remains/Destroy(force)
remove_shared_particles(/particles/bonfire)
return ..()
/obj/item/clothing/suit/hooded/cloak/drake
name = "drake armour"
icon_state = "dragon"
desc = "A suit of armour fashioned from the remains of an ash drake."
armor_type = /datum/armor/cloak_drake
hoodtype = /obj/item/clothing/head/hooded/cloakhood/drake
body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT
heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
resistance_flags = FIRE_PROOF | ACID_PROOF
transparent_protection = HIDEGLOVES|HIDESUITSTORAGE|HIDEJUMPSUIT|HIDESHOES
/datum/armor/cloak_drake
melee = 65
bullet = 15
laser = 40
energy = 40
bomb = 70
bio = 60
fire = 100
acid = 100
wound = 10
/obj/item/clothing/suit/hooded/cloak/drake/Initialize(mapload)
. = ..()
allowed = GLOB.mining_suit_allowed
/obj/item/clothing/head/hooded/cloakhood/drake
name = "drake helm"
icon = 'icons/obj/clothing/head/helmet.dmi'
worn_icon = 'icons/mob/clothing/head/helmet.dmi'
icon_state = "dragon"
desc = "The skull of a dragon."
armor_type = /datum/armor/cloak_drake
clothing_flags = SNUG_FIT
cold_protection = HEAD
min_cold_protection_temperature = FIRE_HELM_MIN_TEMP_PROTECT
heat_protection = HEAD
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
resistance_flags = FIRE_PROOF | ACID_PROOF
// Spectral blade
/obj/item/melee/ghost_sword
name = "\improper spectral blade"
desc = "A rusted and dulled blade. It doesn't look like it'd do much damage. It glows weakly."
icon = 'icons/obj/weapons/sword.dmi'
icon_state = "spectral"
inhand_icon_state = "spectral"
icon_angle = -45
lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi'
obj_flags = CONDUCTS_ELECTRICITY
sharpness = SHARP_EDGED
w_class = WEIGHT_CLASS_BULKY
force = 5 // Breakpoint past which something counts as a weapon, usually
throwforce = 5
hitsound = 'sound/effects/ghost2.ogg'
block_sound = 'sound/items/weapons/parry.ogg'
attack_verb_continuous = list("attacks", "slashes", "slices", "tears", "lacerates", "rips", "dices", "rends")
attack_verb_simple = list("attack", "slash", "slice", "tear", "lacerate", "rip", "dice", "rend")
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
var/list/mob/dead/observer/spirits
var/list/alt_continuous = list("stabs", "pierces", "impales")
var/list/alt_simple = list("stab", "pierce", "impale")
COOLDOWN_DECLARE(summon_cooldown)
/obj/item/melee/ghost_sword/Initialize(mapload)
. = ..()
spirits = list()
START_PROCESSING(SSobj, src)
SSpoints_of_interest.make_point_of_interest(src)
alt_continuous = string_list(alt_continuous)
alt_simple = string_list(alt_simple)
AddComponent(/datum/component/alternative_sharpness, SHARP_POINTY, alt_continuous, alt_simple)
AddComponent(\
/datum/component/butchering, \
speed = 15 SECONDS, \
effectiveness = 90, \
)
/obj/item/melee/ghost_sword/Destroy()
for(var/mob/dead/observer/ghost in spirits)
ghost.RemoveInvisibility(type)
spirits.Cut()
STOP_PROCESSING(SSobj, src)
. = ..()
/obj/item/melee/ghost_sword/attack_self(mob/user)
if(!COOLDOWN_FINISHED(src, summon_cooldown))
to_chat(user, span_warning("You just recently called out for aid. You don't want to annoy the spirits!"))
return
COOLDOWN_START(src, summon_cooldown, 60 SECONDS)
to_chat(user, span_notice("You call out for aid, attempting to summon spirits to your side."))
notify_ghosts(
"[user] is raising [user.p_their()] [name], calling for your help!",
source = user,
ignore_key = POLL_IGNORE_SPECTRAL_BLADE,
header = "Spectral blade",
)
/obj/item/melee/ghost_sword/process()
ghost_check()
/obj/item/melee/ghost_sword/proc/ghost_check()
var/turf/cur_turf = get_turf(src)
var/list/contents = cur_turf.get_all_contents()
var/mob/dead/observer/current_spirits = list()
for(var/atom/random_thing in contents)
random_thing.transfer_observers_to(src)
for(var/mob/dead/observer/ghost in orbiters?.orbiter_list)
ghost.SetInvisibility(INVISIBILITY_NONE, id = type, priority = INVISIBILITY_PRIORITY_BASIC_ANTI_INVISIBILITY)
current_spirits |= ghost
for(var/mob/dead/observer/ghost in spirits - current_spirits)
ghost.RemoveInvisibility(type)
var/new_force = clamp((length(current_spirits) * 4), 0, 75)
var/old_force = clamp((length(spirits) * 4), 0, 75)
force += new_force - old_force
spirits = current_spirits
return length(spirits)
/obj/item/melee/ghost_sword/attack(mob/living/target, mob/living/carbon/human/user)
var/ghost_counter = ghost_check()
user.visible_message(span_danger("[user] strikes with the force of [ghost_counter] vengeful spirits!"))
. = ..()
/obj/item/melee/ghost_sword/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK, damage_type = BRUTE)
var/ghost_counter = ghost_check()
final_block_chance += clamp((ghost_counter * 5), 0, 75)
owner.visible_message(span_danger("[owner] is protected by a ring of [ghost_counter] ghosts!"))
return ..()
// Dragon's blood
/obj/item/dragons_blood
name = "bottle of dragons blood"
desc = "You're not actually going to drink this, are you?"
icon = 'icons/obj/mining_zones/artefacts.dmi'
icon_state = "vial"
/obj/item/dragons_blood/attack_self(mob/living/carbon/human/user)
if(!istype(user))
return
var/mob/living/carbon/human/consumer = user
var/random = rand(2,4) //SKYRAT EDIT - Commenting out #1 because it makes people invisible.
switch(random)
if(1)
to_chat(user, span_danger("Your appearance morphs to that of a very small humanoid ash dragon! You get to look like a freak without the cool abilities."))
consumer.dna.features = list(
"mcolor" = "#A02720",
"tail_lizard" = "Dark Tiger",
"tail_human" = "None",
"snout" = "Sharp",
"horns" = "Curled",
"ears" = "None",
"wings" = "None",
"frills" = "None",
"spines" = "Long",
"lizard_markings" = "Dark Tiger Body",
"legs" = DIGITIGRADE_LEGS,
)
consumer.eye_color_left = "#FEE5A3"
consumer.eye_color_right = "#FEE5A3"
consumer.set_species(/datum/species/lizard)
if(2)
to_chat(user, span_danger("Your flesh begins to melt! Miraculously, you seem fine otherwise."))
consumer.set_species(/datum/species/skeleton)
if(3)
to_chat(user, span_danger("Power courses through you! You can now shift your form at will."))
var/datum/action/cooldown/spell/shapeshift/dragon/dragon_shapeshift = new(user.mind || user)
dragon_shapeshift.Grant(user)
if(4)
to_chat(user, span_danger("You feel like you could walk straight through lava now."))
ADD_TRAIT(user, TRAIT_LAVA_IMMUNE, type)
playsound(user,'sound/items/drink.ogg', 30, TRUE)
qdel(src)
// Lava staff
/obj/item/lava_staff
name = "staff of lava"
desc = "The ability to fill the emergency shuttle with lava. What more could you want out of life?"
icon_state = "lavastaff"
inhand_icon_state = "lavastaff"
icon_angle = -45
lefthand_file = 'icons/mob/inhands/weapons/staves_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi'
icon = 'icons/obj/weapons/guns/magic.dmi'
slot_flags = ITEM_SLOT_BACK
w_class = WEIGHT_CLASS_NORMAL
force = 18
damtype = BURN
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
attack_verb_continuous = list("sears", "clubs", "burn")
attack_verb_simple = list("sear", "club", "burn")
hitsound = 'sound/items/weapons/sear.ogg'
var/turf_type = /turf/open/lava/smooth/weak
var/transform_string = "lava"
var/reset_turf_type = /turf/open/misc/asteroid/basalt
var/reset_string = "basalt"
var/create_cooldown = 10 SECONDS
var/create_delay = 3 SECONDS
var/reset_cooldown = 5 SECONDS
var/static/list/banned_turfs = typecacheof(list(/turf/open/space, /turf/closed))
COOLDOWN_DECLARE(use_cooldown)
/obj/item/lava_staff/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(interacting_with.atom_storage || SHOULD_SKIP_INTERACTION(interacting_with, src, user))
return NONE
return ranged_interact_with_atom(interacting_with, user, modifiers)
/obj/item/lava_staff/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!COOLDOWN_FINISHED(src, use_cooldown))
return NONE
if(is_type_in_typecache(interacting_with, banned_turfs))
return NONE
if(!(interacting_with in view(user.client.view, get_turf(user))))
return NONE
var/turf/open/target_turf = get_turf(interacting_with)
if(!istype(target_turf))
return NONE
if(islava(target_turf))
var/old_name = target_turf.name
if(target_turf.TerraformTurf(reset_turf_type, flags = CHANGETURF_INHERIT_AIR))
return ITEM_INTERACT_FAILURE
COOLDOWN_START(src, use_cooldown, reset_cooldown)
user.visible_message(span_danger("[user] turns \the [old_name] into [reset_string]!"))
playsound(target_turf,'sound/effects/magic/fireball.ogg', 200, TRUE)
return ITEM_INTERACT_SUCCESS
var/obj/effect/temp_visual/lavastaff/lava_visual = new /obj/effect/temp_visual/lavastaff(target_turf)
lava_visual.alpha = 0
animate(lava_visual, alpha = 255, time = create_delay)
user.visible_message(span_danger("[user] points [src] at [target_turf]!"))
COOLDOWN_START(src, use_cooldown, create_delay + 1)
if(!do_after(user, create_delay, target_turf))
balloon_alert(user, "interrupted!")
COOLDOWN_RESET(src, use_cooldown)
qdel(lava_visual)
return ITEM_INTERACT_FAILURE
var/old_name = target_turf.name
if(!target_turf.TerraformTurf(turf_type, flags = CHANGETURF_INHERIT_AIR))
qdel(lava_visual)
return ITEM_INTERACT_FAILURE
user.visible_message(span_danger("[user] turns \the [old_name] into [transform_string]!"))
message_admins("[ADMIN_LOOKUPFLW(user)] fired the lava staff at [ADMIN_VERBOSEJMP(target_turf)]")
user.log_message("fired the lava staff at [AREACOORD(target_turf)].", LOG_ATTACK)
COOLDOWN_START(src, use_cooldown, create_cooldown)
playsound(target_turf,'sound/effects/magic/fireball.ogg', 200, TRUE)
qdel(lava_visual)
return ITEM_INTERACT_SUCCESS
/obj/effect/temp_visual/lavastaff
icon_state = "lavastaff_warn"
duration = 50
/turf/open/lava/smooth/weak
lava_damage = 10
lava_firestacks = 10
temperature_damage = 2500
@@ -0,0 +1,123 @@
// Cleaving saw
/obj/item/melee/cleaving_saw
name = "cleaving saw"
desc = "This saw, effective at drawing the blood of beasts, transforms into a long cleaver that makes use of centrifugal force."
icon = 'icons/obj/mining_zones/artefacts.dmi'
lefthand_file = 'icons/mob/inhands/64x64_lefthand.dmi'
righthand_file = 'icons/mob/inhands/64x64_righthand.dmi'
icon_state = "cleaving_saw"
inhand_icon_state = "cleaving_saw"
worn_icon_state = "cleaving_saw"
attack_verb_continuous = list("attacks", "saws", "slices", "tears", "lacerates", "rips", "dices", "cuts")
attack_verb_simple = list("attack", "saw", "slice", "tear", "lacerate", "rip", "dice", "cut")
force = 12
throwforce = 20
inhand_x_dimension = 64
inhand_y_dimension = 64
slot_flags = ITEM_SLOT_BELT
hitsound = 'sound/items/weapons/bladeslice.ogg'
w_class = WEIGHT_CLASS_BULKY
sharpness = SHARP_EDGED
/// List of factions we deal bonus damage to
var/list/nemesis_factions = list(FACTION_MINING, FACTION_BOSS)
/// Amount of damage we deal to the above factions
var/faction_bonus_force = 30
/// Whether the cleaver is actively AoE swiping something.
var/swiping = FALSE
/// Amount of bleed stacks gained per hit
var/bleed_stacks_per_hit = 3
/// Force when the saw is opened.
var/open_force = 20
/// Throwforce when the saw is opened.
var/open_throwforce = 20
/obj/item/melee/cleaving_saw/Initialize(mapload)
. = ..()
AddComponent( \
/datum/component/transforming, \
transform_cooldown_time = (CLICK_CD_MELEE * 0.25), \
force_on = open_force, \
throwforce_on = open_throwforce, \
sharpness_on = sharpness, \
hitsound_on = hitsound, \
w_class_on = w_class, \
attack_verb_continuous_on = list("cleaves", "swipes", "slashes", "chops"), \
attack_verb_simple_on = list("cleave", "swipe", "slash", "chop"), \
)
RegisterSignal(src, COMSIG_TRANSFORMING_ON_TRANSFORM, PROC_REF(on_transform))
/obj/item/melee/cleaving_saw/examine(mob/user)
. = ..()
. += span_notice("It is [HAS_TRAIT(src, TRAIT_TRANSFORM_ACTIVE) ? "open, will cleave enemies in a wide arc and deal additional damage to fauna":"closed, and can be used for rapid consecutive attacks that cause fauna to bleed"].")
. += span_notice("Both modes will build up existing bleed effects, doing a burst of high damage if the bleed is built up high enough.")
. += span_notice("Transforming it immediately after an attack causes the next attack to come out faster.")
/obj/item/melee/cleaving_saw/suicide_act(mob/living/user)
user.visible_message(span_suicide("[user] is [HAS_TRAIT(src, TRAIT_TRANSFORM_ACTIVE) ? "closing [src] on [user.p_their()] neck" : "opening [src] into [user.p_their()] chest"]! It looks like [user.p_theyre()] trying to commit suicide!"))
attack_self(user)
return BRUTELOSS
/obj/item/melee/cleaving_saw/melee_attack_chain(mob/user, atom/target, params)
. = ..()
if(!HAS_TRAIT(src, TRAIT_TRANSFORM_ACTIVE))
user.changeNext_move(CLICK_CD_MELEE * 0.5) //when closed, it attacks very rapidly
/obj/item/melee/cleaving_saw/attack(mob/living/target, mob/living/carbon/human/user)
var/is_open = HAS_TRAIT(src, TRAIT_TRANSFORM_ACTIVE)
if(!is_open || swiping || !target.density || get_turf(target) == get_turf(user))
if(!is_open)
faction_bonus_force = 0
var/is_nemesis_faction = FALSE
for(var/found_faction in target.faction)
if(found_faction in nemesis_factions)
is_nemesis_faction = TRUE
force += faction_bonus_force
nemesis_effects(user, target)
break
. = ..()
if(is_nemesis_faction)
force -= faction_bonus_force
if(!is_open)
faction_bonus_force = initial(faction_bonus_force)
return
var/turf/user_turf = get_turf(user)
var/dir_to_target = get_dir(user_turf, get_turf(target))
swiping = TRUE
var/static/list/cleaving_saw_cleave_angles = list(0, -45, 45) //so that the animation animates towards the target clicked and not towards a side target
for(var/i in cleaving_saw_cleave_angles)
var/turf/turf = get_step(user_turf, turn(dir_to_target, i))
for(var/mob/living/living_target in turf)
if(user.Adjacent(living_target) && living_target.body_position != LYING_DOWN)
melee_attack_chain(user, living_target)
swiping = FALSE
/*
* If we're attacking [target]s in our nemesis list, apply unique effects.
*
* user - the mob attacking with the saw
* target - the mob being attacked
*/
/obj/item/melee/cleaving_saw/proc/nemesis_effects(mob/living/user, mob/living/target)
if(istype(target, /mob/living/simple_animal/hostile/asteroid/elite))
return
var/datum/status_effect/stacking/saw_bleed/existing_bleed = target.has_status_effect(/datum/status_effect/stacking/saw_bleed)
if(existing_bleed)
existing_bleed.add_stacks(bleed_stacks_per_hit)
else
target.apply_status_effect(/datum/status_effect/stacking/saw_bleed, bleed_stacks_per_hit)
/*
* Signal proc for [COMSIG_TRANSFORMING_ON_TRANSFORM].
*
* Gives feedback and makes the nextmove after transforming much quicker.
*/
/obj/item/melee/cleaving_saw/proc/on_transform(obj/item/source, mob/user, active)
SIGNAL_HANDLER
user.changeNext_move(CLICK_CD_MELEE * 0.25)
if(user)
balloon_alert(user, "[active ? "opened" : "closed"] [src]")
playsound(src, 'sound/effects/magic/clockwork/fellowship_armory.ogg', 35, TRUE, frequency = 90000 - (active * 30000))
return COMPONENT_NO_DEFAULT_MESSAGE
@@ -0,0 +1,415 @@
// Mayhem in a bottle
/obj/item/mayhem
name = "mayhem in a bottle"
desc = "A magically infused bottle of blood, the scent of which will drive anyone nearby into a murderous frenzy."
icon = 'icons/obj/mining_zones/artefacts.dmi'
icon_state = "vial"
/obj/item/mayhem/attack_self(mob/user)
if(tgui_alert(user, "Breaking the bottle will cause nearby crewmembers to go into a murderous frenzy. Be sure you know what you are doing...", "Break the bottle?", list("Break it!", "DON'T")) != "Break it!")
return
if(QDELETED(src) || !user.is_holding(src) || user.incapacitated)
return
for(var/mob/living/carbon/human/target in range(7, user))
target.apply_status_effect(/datum/status_effect/mayhem)
to_chat(user, span_notice("You shatter the bottle!"))
playsound(user.loc, 'sound/effects/glass/glassbr1.ogg', 100, TRUE)
message_admins(span_adminnotice("[ADMIN_LOOKUPFLW(user)] has activated a bottle of mayhem!"))
user.log_message("activated a bottle of mayhem", LOG_ATTACK)
qdel(src)
// H.E.C.K. Suit
/obj/item/clothing/suit/hooded/hostile_environment
name = "H.E.C.K. suit"
desc = "Hostile Environment Cross-Kinetic Suit: A suit designed to withstand the wide variety of hazards from Lavaland. It wasn't enough for its last owner."
icon_state = "hostile_env"
hoodtype = /obj/item/clothing/head/hooded/hostile_environment
armor_type = /datum/armor/hooded_hostile_environment
cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT
heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS
clothing_flags = THICKMATERIAL|HEADINTERNALS
resistance_flags = FIRE_PROOF|LAVA_PROOF|ACID_PROOF
transparent_protection = HIDESUITSTORAGE|HIDEJUMPSUIT
allowed = null
greyscale_colors = "#4d4d4d#808080"
greyscale_config = /datum/greyscale_config/heck_suit
greyscale_config_worn = /datum/greyscale_config/heck_suit/worn
greyscale_config_worn_digi = /datum/greyscale_config/heck_suit/worn/digi //SKYRAT EDIT ADDITION - DigiGreyscale
flags_1 = IS_PLAYER_COLORABLE_1
/datum/armor/hooded_hostile_environment
melee = 70
bullet = 40
laser = 10
energy = 20
bomb = 50
fire = 100
acid = 100
/obj/item/clothing/suit/hooded/hostile_environment/Initialize(mapload)
. = ..()
AddElement(/datum/element/radiation_protected_clothing)
AddElement(/datum/element/gags_recolorable)
allowed = GLOB.mining_suit_allowed
/obj/item/clothing/suit/hooded/hostile_environment/process(seconds_per_tick)
var/mob/living/carbon/wearer = loc
if(istype(wearer) && SPT_PROB(1, seconds_per_tick)) //cursed by bubblegum
if(prob(7.5))
wearer.cause_hallucination(/datum/hallucination/oh_yeah, "H.E.C.K suit", haunt_them = TRUE)
else
if(HAS_TRAIT(wearer, TRAIT_ANOSMIA)) //Anosmia quirk holder cannot fell any smell
to_chat(wearer, span_warning("[pick("You hear faint whispers.","You feel hot.","You hear a roar in the distance.")]"))
else
to_chat(wearer, span_warning("[pick("You hear faint whispers.","You smell ash.","You feel hot.","You hear a roar in the distance.")]"))
/obj/item/clothing/head/hooded/hostile_environment
name = "H.E.C.K. helmet"
desc = "Hostile Environment Cross-Kinetic Helmet: A helmet designed to withstand the wide variety of hazards from Lavaland. It wasn't enough for its last owner."
icon = 'icons/obj/clothing/head/helmet.dmi'
worn_icon = 'icons/mob/clothing/head/helmet.dmi'
icon_state = "hostile_env"
w_class = WEIGHT_CLASS_NORMAL
armor_type = /datum/armor/hooded_hostile_environment
cold_protection = HEAD
min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT
heat_protection = HEAD
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
clothing_flags = SNUG_FIT|THICKMATERIAL
resistance_flags = FIRE_PROOF|LAVA_PROOF|ACID_PROOF
flags_inv = HIDEMASK|HIDEEARS|HIDEFACE|HIDEEYES|HIDEHAIR|HIDEFACIALHAIR|HIDESNOUT
flags_cover = HEADCOVERSMOUTH
actions_types = list()
greyscale_colors = "#4d4d4d#808080#ff3300"
greyscale_config = /datum/greyscale_config/heck_helmet
greyscale_config_worn = /datum/greyscale_config/heck_helmet/worn
greyscale_config_worn_digi = /datum/greyscale_config/heck_helmet/worn/snouted //SKYRAT EDIT ADDITION - MuzzledGreyscale (Why does this use worn_digi)
flags_1 = IS_PLAYER_COLORABLE_1
/obj/item/clothing/head/hooded/hostile_environment/Initialize(mapload)
. = ..()
update_appearance()
AddComponent(/datum/component/butchering/wearable, \
speed = 0.5 SECONDS, \
effectiveness = 150, \
bonus_modifier = 0, \
butcher_sound = null, \
disabled = null, \
can_be_blunt = TRUE, \
butcher_callback = CALLBACK(src, PROC_REF(consume)), \
)
AddElement(/datum/element/radiation_protected_clothing)
AddElement(/datum/element/gags_recolorable)
/obj/item/clothing/head/hooded/hostile_environment/equipped(mob/user, slot, initial = FALSE)
. = ..()
to_chat(user, span_notice("You feel a bloodlust. You can now butcher corpses with your bare arms."))
/obj/item/clothing/head/hooded/hostile_environment/dropped(mob/user, silent = FALSE)
. = ..()
to_chat(user, span_notice("You lose your bloodlust."))
/obj/item/clothing/head/hooded/hostile_environment/proc/consume(mob/living/user, mob/living/butchered)
if(butchered.mob_biotypes & (MOB_ROBOTIC | MOB_SPIRIT))
return
var/health_consumed = butchered.maxHealth * 0.1
user.heal_ordered_damage(health_consumed, list(BRUTE, BURN, TOX))
to_chat(user, span_notice("You heal from the corpse of [butchered]."))
var/datum/client_colour/color_effect = user.add_client_colour(/datum/client_colour/bloodlust)
QDEL_IN(color_effect, 1 SECONDS)
// Soulscythe
#define MAX_BLOOD_LEVEL 100
/obj/item/soulscythe
name = "soulscythe"
desc = "An old relic of hell created by devils to establish themselves as the leadership of hell over the demons. It grows stronger while it possesses a powerful soul."
icon = 'icons/obj/mining_zones/artefacts.dmi'
icon_state = "soulscythe"
inhand_icon_state = "soulscythe"
lefthand_file = 'icons/mob/inhands/64x64_lefthand.dmi'
righthand_file = 'icons/mob/inhands/64x64_righthand.dmi'
attack_verb_continuous = list("chops", "slices", "cuts", "reaps")
attack_verb_simple = list("chop", "slice", "cut", "reap")
hitsound = 'sound/items/weapons/bladeslice.ogg'
inhand_x_dimension = 64
inhand_y_dimension = 64
force = 20
throwforce = 17
armour_penetration = 50
sharpness = SHARP_EDGED
bare_wound_bonus = 10
layer = MOB_LAYER
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
/// Soulscythe mob in the scythe
var/mob/living/simple_animal/soulscythe/soul
/// Are we grabbing a spirit?
var/using = FALSE
/// Currently charging?
var/charging = FALSE
/// Cooldown between moves
COOLDOWN_DECLARE(move_cooldown)
/// Cooldown between attacks
COOLDOWN_DECLARE(attack_cooldown)
/obj/item/soulscythe/Initialize(mapload)
. = ..()
soul = new(src)
RegisterSignal(soul, COMSIG_LIVING_RESIST, PROC_REF(on_resist))
RegisterSignal(soul, COMSIG_MOB_ATTACK_RANGED, PROC_REF(on_attack))
RegisterSignal(soul, COMSIG_MOB_ATTACK_RANGED_SECONDARY, PROC_REF(on_secondary_attack))
RegisterSignal(src, COMSIG_ATOM_INTEGRITY_CHANGED, PROC_REF(on_integrity_change))
AddElement(/datum/element/bane, mob_biotypes = MOB_PLANT, damage_multiplier = 0.5, requires_combat_mode = FALSE)
/obj/item/soulscythe/examine(mob/user)
. = ..()
. += soul.ckey ? span_nicegreen("There is a soul inhabiting it.") : span_danger("It's dormant.")
/obj/item/soulscythe/attack(mob/living/attacked, mob/living/user, params)
. = ..()
if(attacked.stat != DEAD)
give_blood(10)
/obj/item/soulscythe/attack_hand(mob/user, list/modifiers)
if(soul.ckey && !soul.faction_check_atom(user))
to_chat(user, span_warning("You can't pick up [src]!"))
return
return ..()
/obj/item/soulscythe/pickup(mob/user)
. = ..()
if(soul.ckey)
animate(src) //stop spinnage
/obj/item/soulscythe/dropped(mob/user, silent)
. = ..()
if(soul.ckey)
reset_spin() //resume spinnage
/obj/item/soulscythe/attack_self(mob/user, modifiers)
if(using || soul.ckey || soul.stat)
return
if(!(GLOB.ghost_role_flags & GHOSTROLE_STATION_SENTIENCE))
balloon_alert(user, "you can't awaken the scythe!")
return
using = TRUE
balloon_alert(user, "you hold the scythe up...")
ADD_TRAIT(src, TRAIT_NODROP, type)
var/mob/chosen_one = SSpolling.poll_ghosts_for_target(
check_jobban = ROLE_PAI,
poll_time = 20 SECONDS,
checked_target = src,
ignore_category = POLL_IGNORE_POSSESSED_BLADE,
alert_pic = src,
role_name_text = "soulscythe soul",
chat_text_border_icon = src,
)
on_poll_concluded(user, chosen_one)
/// Ghost poll has concluded and a candidate has been chosen.
/obj/item/soulscythe/proc/on_poll_concluded(mob/living/master, mob/dead/observer/ghost)
if(isnull(ghost))
balloon_alert(master, "the scythe is dormant!")
REMOVE_TRAIT(src, TRAIT_NODROP, type)
using = FALSE
return
soul.PossessByPlayer(ghost.ckey)
soul.copy_languages(master, LANGUAGE_MASTER) //Make sure the sword can understand and communicate with the master.
soul.faction = list("[REF(master)]")
balloon_alert(master, "the scythe glows")
add_overlay("soulscythe_gem")
density = TRUE
if(!ismob(loc))
reset_spin()
REMOVE_TRAIT(src, TRAIT_NODROP, type)
using = FALSE
/obj/item/soulscythe/relaymove(mob/living/user, direction)
if(!COOLDOWN_FINISHED(src, move_cooldown) || charging)
return
if(!isturf(loc))
balloon_alert(user, "resist out!")
COOLDOWN_START(src, move_cooldown, 1 SECONDS)
return
if(!use_blood(1, FALSE))
return
if(pixel_x != base_pixel_x || pixel_y != base_pixel_y)
animate(src, 0.2 SECONDS, pixel_x = base_pixel_y, pixel_y = base_pixel_y, flags = ANIMATION_PARALLEL)
try_step_multiz(direction)
COOLDOWN_START(src, move_cooldown, (direction in GLOB.cardinals) ? 0.1 SECONDS : 0.2 SECONDS)
/obj/item/soulscythe/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
. = ..()
if(!charging)
return
charging = FALSE
throwforce *= 0.5
reset_spin()
if(ismineralturf(hit_atom))
var/turf/closed/mineral/hit_rock = hit_atom
hit_rock.gets_drilled()
if(isliving(hit_atom))
var/mob/living/hit_mob = hit_atom
if(hit_mob.stat != DEAD)
give_blood(15)
/obj/item/soulscythe/AllowClick()
return TRUE
/obj/item/soulscythe/proc/use_blood(amount = 0, message = TRUE)
if(amount > soul.blood_level)
if(message)
to_chat(soul, span_warning("Not enough blood!"))
return FALSE
soul.blood_level -= amount
return TRUE
/obj/item/soulscythe/proc/give_blood(amount)
soul.blood_level = min(MAX_BLOOD_LEVEL, soul.blood_level + amount)
/obj/item/soulscythe/proc/on_resist(mob/living/user)
SIGNAL_HANDLER
if(isturf(loc))
return
INVOKE_ASYNC(src, PROC_REF(break_out))
/obj/item/soulscythe/proc/break_out()
if(!use_blood(10))
return
balloon_alert(soul, "you resist...")
if(!do_after(soul, 5 SECONDS, target = src, timed_action_flags = IGNORE_TARGET_LOC_CHANGE))
balloon_alert(soul, "interrupted!")
return
balloon_alert(soul, "you break out")
if(ismob(loc))
var/mob/holder = loc
holder.temporarilyRemoveItemFromInventory(src)
forceMove(drop_location())
/obj/item/soulscythe/proc/on_integrity_change(datum/source, old_value, new_value)
SIGNAL_HANDLER
soul.set_health(new_value)
/obj/item/soulscythe/proc/on_attack(mob/living/source, atom/attacked_atom, modifiers)
SIGNAL_HANDLER
if(!COOLDOWN_FINISHED(src, attack_cooldown) || !isturf(loc))
return
if(get_dist(source, attacked_atom) > 1)
INVOKE_ASYNC(src, PROC_REF(shoot_target), attacked_atom)
else
INVOKE_ASYNC(src, PROC_REF(slash_target), attacked_atom)
/obj/item/soulscythe/proc/on_secondary_attack(mob/living/source, atom/attacked_atom, modifiers)
SIGNAL_HANDLER
if(!COOLDOWN_FINISHED(src, attack_cooldown) || !isturf(loc))
return
INVOKE_ASYNC(src, PROC_REF(charge_target), attacked_atom)
/obj/item/soulscythe/proc/shoot_target(atom/attacked_atom)
if(!use_blood(15))
return
COOLDOWN_START(src, attack_cooldown, 3 SECONDS)
var/obj/projectile/projectile = new /obj/projectile/soulscythe(get_turf(src))
projectile.aim_projectile(attacked_atom, src)
projectile.firer = src
projectile.fire(null, attacked_atom)
visible_message(span_danger("[src] fires at [attacked_atom]!"), span_notice("You fire at [attacked_atom]!"))
playsound(src, 'sound/effects/magic/fireball.ogg', 50, TRUE)
/obj/item/soulscythe/proc/slash_target(atom/attacked_atom)
if(isliving(attacked_atom) && use_blood(10))
var/mob/living/attacked_mob = attacked_atom
if(attacked_mob.stat != DEAD)
give_blood(15)
attacked_mob.apply_damage(damage = force * (ishostile(attacked_mob) ? 2 : 1), sharpness = SHARP_EDGED, bare_wound_bonus = 5)
to_chat(attacked_mob, span_userdanger("You're slashed by [src]!"))
else if((ismachinery(attacked_atom) || isstructure(attacked_atom)) && use_blood(5))
var/obj/attacked_obj = attacked_atom
attacked_obj.take_damage(force, BRUTE, MELEE, FALSE)
else
return
COOLDOWN_START(src, attack_cooldown, 1 SECONDS)
animate(src)
SpinAnimation(5)
addtimer(CALLBACK(src, PROC_REF(reset_spin)), 1 SECONDS)
visible_message(span_danger("[src] slashes [attacked_atom]!"), span_notice("You slash [attacked_atom]!"))
playsound(src, 'sound/items/weapons/bladeslice.ogg', 50, TRUE)
do_attack_animation(attacked_atom, ATTACK_EFFECT_SLASH)
/obj/item/soulscythe/proc/charge_target(atom/attacked_atom)
if(charging || !use_blood(30))
return
COOLDOWN_START(src, attack_cooldown, 5 SECONDS)
animate(src)
charging = TRUE
visible_message(span_danger("[src] starts charging..."))
balloon_alert(soul, "you start charging...")
if(!do_after(soul, 2 SECONDS, target = src, timed_action_flags = IGNORE_TARGET_LOC_CHANGE))
balloon_alert(soul, "interrupted!")
return
visible_message(span_danger("[src] charges at [attacked_atom]!"), span_notice("You charge at [attacked_atom]!"))
new /obj/effect/temp_visual/mook_dust(get_turf(src))
playsound(src, 'sound/items/weapons/thudswoosh.ogg', 50, TRUE)
SpinAnimation(1)
throwforce *= 2
throw_at(attacked_atom, 10, 3, soul, FALSE)
/obj/item/soulscythe/proc/reset_spin()
animate(src)
SpinAnimation(15)
/obj/item/soulscythe/Destroy(force)
soul.ghostize()
QDEL_NULL(soul)
. = ..()
/mob/living/simple_animal/soulscythe
name = "mysterious spirit"
maxHealth = 200
health = 200
gender = NEUTER
mob_biotypes = MOB_SPIRIT
faction = list()
weather_immunities = list(TRAIT_ASHSTORM_IMMUNE, TRAIT_SNOWSTORM_IMMUNE)
/// Blood level, used for movement and abilities in a soulscythe
var/blood_level = MAX_BLOOD_LEVEL
/mob/living/simple_animal/soulscythe/get_status_tab_items()
. = ..()
. += "Blood: [blood_level]/[MAX_BLOOD_LEVEL]"
/mob/living/simple_animal/soulscythe/Life(seconds_per_tick, times_fired)
. = ..()
if(!stat)
blood_level = min(MAX_BLOOD_LEVEL, blood_level + round(1 * seconds_per_tick))
/obj/projectile/soulscythe
name = "soulslash"
icon_state = "soulslash"
armor_flag = MELEE //jokair
damage = 15
light_range = 1
light_power = 1
light_color = LIGHT_COLOR_BLOOD_MAGIC
/obj/projectile/soulscythe/on_hit(atom/target, blocked = 0, pierce_hit)
if(ishostile(target))
damage *= 2
return ..()
#undef MAX_BLOOD_LEVEL
@@ -0,0 +1,441 @@
// Divine vocal cords
/obj/item/organ/vocal_cords/colossus
name = "divine vocal cords"
desc = "They carry the voice of an ancient god."
icon_state = "voice_of_god"
actions_types = list(/datum/action/item_action/organ_action/colossus)
var/next_command = 0
var/cooldown_mod = 1
var/base_multiplier = 1
spans = list("colossus","yell")
/datum/action/item_action/organ_action/colossus
name = "Voice of God"
var/obj/item/organ/vocal_cords/colossus/cords = null
/datum/action/item_action/organ_action/colossus/New()
..()
cords = target
/datum/action/item_action/organ_action/colossus/IsAvailable(feedback = FALSE)
if(!owner)
return FALSE
if(world.time < cords.next_command)
if (feedback)
owner.balloon_alert(owner, "wait [DisplayTimeText(cords.next_command - world.time)]!")
return FALSE
if(isliving(owner))
var/mob/living/living = owner
if(!living.can_speak())
if (feedback)
owner.balloon_alert(owner, "can't speak!")
return FALSE
if(check_flags & AB_CHECK_CONSCIOUS)
if(owner.stat)
if (feedback)
owner.balloon_alert(owner, "unconscious!")
return FALSE
return TRUE
/datum/action/item_action/organ_action/colossus/do_effect(trigger_flags)
var/command = tgui_input_text(owner, "Speak with the Voice of God", "Command", max_length = MAX_MESSAGE_LEN)
if(!command)
return FALSE
if(QDELETED(src) || QDELETED(owner))
return FALSE
owner.say(".x[command]")
return TRUE
/obj/item/organ/vocal_cords/colossus/can_speak_with()
if(!owner)
return FALSE
if(world.time < next_command)
to_chat(owner, span_notice("You must wait [DisplayTimeText(next_command - world.time)] before Speaking again."))
return FALSE
return owner.can_speak()
/obj/item/organ/vocal_cords/colossus/handle_speech(message)
playsound(get_turf(owner), 'sound/effects/magic/clockwork/invoke_general.ogg', 300, TRUE, 5)
return //voice of god speaks for us
/obj/item/organ/vocal_cords/colossus/speak_with(message)
var/cooldown = voice_of_god(uppertext(message), owner, spans, base_multiplier)
next_command = world.time + (cooldown * cooldown_mod)
// Anomalous crystal
#define ACTIVATE_TOUCH "touch"
#define ACTIVATE_SPEECH "speech"
#define ACTIVATE_HEAT "heat"
#define ACTIVATE_BULLET "bullet"
#define ACTIVATE_ENERGY "energy"
#define ACTIVATE_BOMB "bomb"
#define ACTIVATE_MOB_BUMP "bumping"
#define ACTIVATE_WEAPON "weapon"
#define ACTIVATE_MAGIC "magic"
/obj/machinery/anomalous_crystal
name = "anomalous crystal"
desc = "A strange chunk of crystal, being in the presence of it fills you with equal parts excitement and dread."
var/observer_desc = "Anomalous crystals have descriptions that only observers can see. But this one hasn't been changed from the default."
icon = 'icons/obj/mining_zones/artefacts.dmi'
icon_state = "anomaly_crystal"
light_range = 8
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
use_power = NO_POWER_USE
anchored = FALSE
density = TRUE
var/activation_method
var/list/possible_methods = list(ACTIVATE_TOUCH, ACTIVATE_SPEECH, ACTIVATE_HEAT, ACTIVATE_BULLET, ACTIVATE_ENERGY, ACTIVATE_BOMB, ACTIVATE_MOB_BUMP, ACTIVATE_WEAPON, ACTIVATE_MAGIC)
var/activation_damage_type = null
/// Cooldown on this crystal
var/cooldown_add = 3 SECONDS
/// Time needed to use this crystal
var/use_time = 0
/// If we are being used
var/active = FALSE
var/activation_sound = 'sound/effects/break_stone.ogg'
COOLDOWN_DECLARE(cooldown_timer)
/obj/machinery/anomalous_crystal/Initialize(mapload)
. = ..()
if(!activation_method)
activation_method = pick(possible_methods)
become_hearing_sensitive(trait_source = ROUNDSTART_TRAIT)
/obj/machinery/anomalous_crystal/examine(mob/user)
. = ..()
if(isobserver(user))
. += observer_desc
. += "It is activated by [activation_method]."
/obj/machinery/anomalous_crystal/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans, list/message_mods = list(), message_range)
. = ..()
if(isliving(speaker))
ActivationReaction(speaker, ACTIVATE_SPEECH)
/obj/machinery/anomalous_crystal/attack_hand(mob/user, list/modifiers)
. = ..()
if(.)
return
ActivationReaction(user, ACTIVATE_TOUCH)
/obj/machinery/anomalous_crystal/attackby(obj/item/I, mob/user, params)
if(I.get_temperature())
ActivationReaction(user, ACTIVATE_HEAT)
else
ActivationReaction(user, ACTIVATE_WEAPON)
..()
/obj/machinery/anomalous_crystal/bullet_act(obj/projectile/proj, def_zone)
. = ..()
if(istype(proj, /obj/projectile/magic))
ActivationReaction(proj.firer, ACTIVATE_MAGIC, proj.damage_type)
return
ActivationReaction(proj.firer, proj.armor_flag, proj.damage_type)
/obj/machinery/anomalous_crystal/proc/ActivationReaction(mob/user, method, damtype)
if(!COOLDOWN_FINISHED(src, cooldown_timer))
return FALSE
if(activation_damage_type && activation_damage_type != damtype)
return FALSE
if(method != activation_method)
return FALSE
if(active)
return FALSE
if(use_time)
charge_animation()
COOLDOWN_START(src, cooldown_timer, cooldown_add)
playsound(user, activation_sound, 100, TRUE)
log_game("[src] activated by [key_name(user)] in [AREACOORD(src)]. The last fingerprints on the [src] was [fingerprintslast].")
return TRUE
/obj/machinery/anomalous_crystal/proc/charge_animation()
icon_state = "anomaly_crystal_charging"
active = TRUE
set_anchored(TRUE)
balloon_alert_to_viewers("charging...")
playsound(src, 'sound/effects/magic/disable_tech.ogg', 50, TRUE)
sleep(use_time)
icon_state = initial(icon_state)
active = FALSE
set_anchored(FALSE)
return TRUE
/obj/machinery/anomalous_crystal/Bumped(atom/movable/AM)
..()
if(ismob(AM))
ActivationReaction(AM, ACTIVATE_MOB_BUMP)
/obj/machinery/anomalous_crystal/ex_act()
ActivationReaction(null, ACTIVATE_BOMB)
return TRUE
/obj/machinery/anomalous_crystal/honk //Revives the dead, but strips and equips them as a clown
observer_desc = "This crystal revives targets around it as clowns. Oh, that's horrible...."
activation_method = ACTIVATE_TOUCH
activation_sound = 'sound/items/bikehorn.ogg'
use_time = 3 SECONDS
/// List of REFs to mobs that have been turned into a clown
var/list/clowned_mob_refs = list()
/obj/machinery/anomalous_crystal/honk/ActivationReaction(mob/user)
. = ..()
if(!.)
return FALSE
for(var/atom/thing as anything in range(1, src))
if(isturf(thing))
new /obj/effect/decal/cleanable/confetti(thing)
continue
if(!ishuman(thing))
continue
var/mob/living/carbon/human/new_clown = thing
if(new_clown.stat != DEAD)
continue
new_clown.revive(ADMIN_HEAL_ALL, force_grab_ghost = TRUE)
var/clown_ref = REF(new_clown)
if(clown_ref in clowned_mob_refs) //one clowning per person
continue
for(var/obj/item/to_strip in new_clown.get_equipped_items())
new_clown.dropItemToGround(to_strip)
new_clown.dress_up_as_job(SSjob.get_job_type(/datum/job/clown))
clowned_mob_refs += clown_ref
return TRUE
/// Transforms the area to look like a new one
/obj/machinery/anomalous_crystal/theme_warp
observer_desc = "This crystal warps the area around it to a theme."
activation_method = ACTIVATE_TOUCH
cooldown_add = 20 SECONDS
use_time = 5 SECONDS
/// Theme which we turn areas into on activation
var/datum/dimension_theme/terrain_theme
/// List of all areas we've affected
var/list/converted_areas = list()
/obj/machinery/anomalous_crystal/theme_warp/Initialize(mapload)
. = ..()
terrain_theme = SSmaterials.dimensional_themes[pick(subtypesof(/datum/dimension_theme))]
observer_desc = "This crystal changes the area around it to match the theme of \"[terrain_theme.name]\"."
/obj/machinery/anomalous_crystal/theme_warp/ActivationReaction(mob/user, method)
. = ..()
if (!.)
return FALSE
var/area/current_area = get_area(src)
if (current_area in converted_areas)
return FALSE
terrain_theme.apply_theme_to_list_of_turfs(current_area.get_turfs_from_all_zlevels())
converted_areas += current_area
return TRUE
/obj/machinery/anomalous_crystal/theme_warp/Destroy()
terrain_theme = null
converted_areas.Cut()
return ..()
/obj/machinery/anomalous_crystal/emitter //Generates a projectile when interacted with
observer_desc = "This crystal generates a projectile when activated."
activation_method = ACTIVATE_TOUCH
cooldown_add = 5 SECONDS
var/obj/projectile/generated_projectile = /obj/projectile/colossus
/obj/machinery/anomalous_crystal/emitter/Initialize(mapload)
. = ..()
observer_desc = "This crystal generates \a [initial(generated_projectile.name)] when activated."
/obj/machinery/anomalous_crystal/emitter/ActivationReaction(mob/user, method)
if(..())
var/obj/projectile/proj = new generated_projectile(get_turf(src))
proj.firer = src
proj.fire(dir2angle(dir))
/obj/machinery/anomalous_crystal/dark_reprise //Revives anyone nearby, but turns them into shadowpeople and renders them uncloneable, so the crystal is your only hope of getting up again if you go down.
observer_desc = "When activated, this crystal revives anyone nearby, but turns them into Shadowpeople and makes them unclonable, making the crystal their only hope of getting up again."
activation_method = ACTIVATE_TOUCH
activation_sound = 'sound/effects/hallucinations/growl1.ogg'
use_time = 3 SECONDS
/obj/machinery/anomalous_crystal/dark_reprise/ActivationReaction(mob/user, method)
. = ..()
if(!.)
return FALSE
for(var/atom/thing as anything in range(1, src))
if(isturf(thing))
new /obj/effect/temp_visual/cult/sparks(thing)
continue
if(!ishuman(thing))
continue
var/mob/living/carbon/human/to_revive = thing
if(to_revive.stat != DEAD)
continue
to_revive.set_species(/datum/species/shadow, TRUE)
to_revive.revive(ADMIN_HEAL_ALL, force_grab_ghost = TRUE)
//Free revives, but significantly limits your options for reviving except via the crystal
//except JK who cares about BADDNA anymore. this even heals suicides.
ADD_TRAIT(to_revive, TRAIT_BADDNA, MAGIC_TRAIT)
return TRUE
/obj/machinery/anomalous_crystal/helpers //Lets ghost spawn as helpful creatures that can only heal people slightly. Incredibly fragile and they can't converse with humans
observer_desc = "This crystal allows ghosts to turn into a fragile creature that can heal people."
activation_method = ACTIVATE_TOUCH
activation_sound = 'sound/effects/ghost2.ogg'
use_time = 5 SECONDS
var/ready_to_deploy = FALSE
/obj/machinery/anomalous_crystal/helpers/ActivationReaction(mob/user, method)
if(..() && !ready_to_deploy)
SSpoints_of_interest.make_point_of_interest(src)
ready_to_deploy = TRUE
notify_ghosts(
"An anomalous crystal has been activated in [get_area(src)]! This crystal can always be used by ghosts hereafter.",
source = src,
header = "Anomalous crystal activated",
click_interact = TRUE,
ghost_sound = 'sound/effects/ghost2.ogg',
)
/obj/machinery/anomalous_crystal/helpers/attack_ghost(mob/dead/observer/user)
. = ..()
if(.)
return
if(ready_to_deploy)
var/be_helper = tgui_alert(usr, "Become a Lightgeist? (Warning, You can no longer be revived!)", "Lightgeist Deployment", list("Yes", "No"))
if((be_helper == "Yes") && !QDELETED(src) && isobserver(user))
var/mob/living/basic/lightgeist/deployable = new(get_turf(loc))
deployable.PossessByPlayer(user.key)
/obj/machinery/anomalous_crystal/possessor //Allows you to bodyjack small animals, then exit them at your leisure, but you can only do this once per activation. Because they blow up. Also, if the bodyjacked animal dies, SO DO YOU.
observer_desc = "When activated, this crystal allows you to take over small animals, and then exit them at the possessors leisure. Exiting the animal kills it, and if you die while possessing the animal, you die as well."
activation_method = ACTIVATE_TOUCH
use_time = 1 SECONDS
/obj/machinery/anomalous_crystal/possessor/ActivationReaction(mob/user, method)
. = ..()
if (!. || !ishuman(user))
return FALSE
var/list/valid_mobs = list()
var/list/nearby_things = range(1, src)
for(var/mob/living/basic/possible_mob in nearby_things)
if (!is_valid_animal(possible_mob))
continue
valid_mobs += possible_mob
for(var/mob/living/simple_animal/possible_mob in nearby_things)
if (!is_valid_animal(possible_mob))
continue
valid_mobs += possible_mob
if (!length(valid_mobs)) //Just in case there aren't any animals on the station, this will leave you with a terrible option to possess if you feel like it //i found it funny that in the file for a giant angel beast theres a cockroach
new /mob/living/basic/cockroach(get_step(src,dir))
return
var/mob/living/picked_mob = pick(valid_mobs)
var/obj/structure/closet/stasis/possessor_container = new /obj/structure/closet/stasis(picked_mob)
user.forceMove(possessor_container)
/// Returns true if this is a mob you're allowed to possess
/obj/machinery/anomalous_crystal/possessor/proc/is_valid_animal(mob/living/check_mob)
return check_mob.stat != DEAD && !check_mob.ckey && check_mob.mob_size < MOB_SIZE_LARGE && check_mob.melee_damage_upper <= 5
/obj/structure/closet/stasis
name = "quantum entanglement stasis warp field"
desc = "You can hardly comprehend this thing... which is why you can't see it."
icon_state = null //This shouldn't even be visible, so if it DOES show up, at least nobody will notice
enable_door_overlay = FALSE //For obvious reasons
density = TRUE
anchored = TRUE
resistance_flags = FIRE_PROOF | ACID_PROOF | INDESTRUCTIBLE
paint_jobs = null
///The animal the closet (and the user's body) is inside of
var/mob/living/holder_animal
/obj/structure/closet/stasis/Initialize(mapload)
. = ..()
if(isanimal_or_basicmob(loc))
holder_animal = loc
RegisterSignal(holder_animal, COMSIG_LIVING_DEATH, PROC_REF(on_holder_animal_death))
AddElement(/datum/element/empprotection, EMP_PROTECT_ALL)
/obj/structure/closet/stasis/Entered(atom/movable/arrived, atom/old_loc, list/atom/old_locs)
. = ..()
if(isliving(arrived) && holder_animal)
var/mob/living/possessor = arrived
possessor.add_traits(list(TRAIT_UNDENSE, TRAIT_NO_TRANSFORM, TRAIT_GODMODE), STASIS_MUTE)
possessor.mind.transfer_to(holder_animal)
var/datum/action/exit_possession/escape = new(holder_animal)
escape.Grant(holder_animal)
remove_verb(holder_animal, /mob/living/verb/pulled)
/obj/structure/closet/stasis/dump_contents(kill = TRUE)
for(var/mob/living/possessor in src)
possessor.remove_traits(list(TRAIT_UNDENSE, TRAIT_NO_TRANSFORM, TRAIT_GODMODE), STASIS_MUTE)
if(kill || !isanimal_or_basicmob(loc))
possessor.investigate_log("has died from [src].", INVESTIGATE_DEATHS)
possessor.death(FALSE)
if(holder_animal)
holder_animal.mind.transfer_to(possessor)
possessor.mind.grab_ghost(force = TRUE)
possessor.forceMove(get_turf(holder_animal))
holder_animal.investigate_log("has been gibbed by [src].", INVESTIGATE_DEATHS)
holder_animal.gib(DROP_ALL_REMAINS)
return ..()
return ..()
/obj/structure/closet/stasis/ex_act()
return FALSE
///When our host animal dies in any way, we empty the stasis closet out.
/obj/structure/closet/stasis/proc/on_holder_animal_death()
SIGNAL_HANDLER
dump_contents()
/datum/action/exit_possession
name = "Exit Possession"
desc = "Exits the body you are possessing. They will explode violently when this occurs."
button_icon = 'icons/mob/actions/actions_spells.dmi'
button_icon_state = "exit_possession"
/datum/action/exit_possession/IsAvailable(feedback = FALSE)
return ..() && isfloorturf(owner.loc)
/datum/action/exit_possession/Trigger(trigger_flags)
. = ..()
if(!.)
return FALSE
var/obj/structure/closet/stasis/stasis = locate() in owner
if(!stasis)
CRASH("[type] did not find a stasis closet thing in the owner.")
stasis.dump_contents(FALSE)
qdel(stasis)
qdel(src)
#undef ACTIVATE_BOMB
#undef ACTIVATE_BULLET
#undef ACTIVATE_ENERGY
#undef ACTIVATE_HEAT
#undef ACTIVATE_MAGIC
#undef ACTIVATE_MOB_BUMP
#undef ACTIVATE_SPEECH
#undef ACTIVATE_TOUCH
#undef ACTIVATE_WEAPON
@@ -0,0 +1,104 @@
// Resurrection crystal
/obj/item/resurrection_crystal
name = "resurrection crystal"
desc = "When used by anything holding it, this crystal gives them a second chance at life if they die."
icon = 'icons/obj/mining.dmi'
icon_state = "demonic_crystal"
/obj/item/resurrection_crystal/attack_self(mob/living/user)
if(!iscarbon(user))
to_chat(user, span_notice("A dark presence stops you from absorbing the crystal."))
return
forceMove(user)
to_chat(user, span_notice("You feel a bit safer... but a demonic presence lurks in the back of your head..."))
RegisterSignal(user, COMSIG_LIVING_DEATH, PROC_REF(resurrect))
/// Resurrects the target when they die by moving them and dusting a clone in their place, one life for another
/obj/item/resurrection_crystal/proc/resurrect(mob/living/carbon/user, gibbed)
SIGNAL_HANDLER
if(gibbed)
to_chat(user, span_notice("This power cannot be used if your entire mortal body is disintegrated..."))
return
user.visible_message(span_notice("You see [user]'s soul dragged out of their body!"), span_notice("You feel your soul dragged away to a fresh body!"))
var/typepath = user.type
var/mob/living/carbon/clone = new typepath(user.loc)
clone.real_name = user.real_name
INVOKE_ASYNC(user.dna, TYPE_PROC_REF(/datum/dna, transfer_identity), clone)
clone.updateappearance(mutcolor_update=1)
var/turf/T = find_maintenance_spawn(atmos_sensitive = TRUE, require_darkness = TRUE) || find_safe_turf()
user.forceMove(T)
user.revive(ADMIN_HEAL_ALL)
INVOKE_ASYNC(user, TYPE_PROC_REF(/mob/living/carbon, set_species), /datum/species/shadow)
to_chat(user, span_notice("You blink and find yourself in [get_area_name(T)]... feeling a bit darker."))
clone.dust()
qdel(src)
// Cursed boots
/obj/item/clothing/shoes/winterboots/ice_boots/ice_trail
name = "cursed ice hiking boots"
desc = "A pair of winter boots contractually made by a devil, they cannot be taken off once put on."
actions_types = list(/datum/action/item_action/toggle)
var/on = FALSE
var/change_turf = /turf/open/misc/ice/icemoon/no_planet_atmos
var/duration = 6 SECONDS
/obj/item/clothing/shoes/winterboots/ice_boots/ice_trail/Initialize(mapload)
. = ..()
RegisterSignal(src, COMSIG_SHOES_STEP_ACTION, PROC_REF(on_step))
/obj/item/clothing/shoes/winterboots/ice_boots/ice_trail/equipped(mob/user, slot)
. = ..()
if(slot & ITEM_SLOT_FEET)
ADD_TRAIT(src, TRAIT_NODROP, CURSED_ITEM_TRAIT(type))
/obj/item/clothing/shoes/winterboots/ice_boots/ice_trail/dropped(mob/user)
. = ..()
// Could have been blown off in an explosion from the previous owner
REMOVE_TRAIT(src, TRAIT_NODROP, CURSED_ITEM_TRAIT(type))
/obj/item/clothing/shoes/winterboots/ice_boots/ice_trail/ui_action_click(mob/user)
on = !on
to_chat(user, span_notice("You [on ? "activate" : "deactivate"] [src]."))
/obj/item/clothing/shoes/winterboots/ice_boots/ice_trail/examine(mob/user)
. = ..()
. += span_notice("The shoes are [on ? "enabled" : "disabled"].")
/obj/item/clothing/shoes/winterboots/ice_boots/ice_trail/proc/on_step()
SIGNAL_HANDLER
var/turf/T = get_turf(loc)
if(!on || isclosedturf(T) || istype(T, change_turf))
return
var/reset_turf = T.type
T.ChangeTurf(change_turf, flags = CHANGETURF_INHERIT_AIR)
addtimer(CALLBACK(T, TYPE_PROC_REF(/turf, ChangeTurf), reset_turf, null, CHANGETURF_INHERIT_AIR), duration, TIMER_OVERRIDE|TIMER_UNIQUE)
// Demonic jackhammer
/obj/item/pickaxe/drill/jackhammer/demonic
name = "demonic jackhammer"
desc = "Cracks rocks at an inhuman speed, as well as being enhanced for combat purposes."
toolspeed = 0
/obj/item/pickaxe/drill/jackhammer/demonic/Initialize(mapload)
. = ..()
AddElement(/datum/element/knockback, 4, TRUE, FALSE)
AddElement(/datum/element/lifesteal, 5)
/obj/item/pickaxe/drill/jackhammer/demonic/use_tool(atom/target, mob/living/user, delay, amount=0, volume=0, datum/callback/extra_checks)
var/turf/T = get_turf(target)
mineral_scan_pulse(T, world.view + 1, src)
. = ..()
// Ice energy crystal
/obj/item/ice_energy_crystal
name = "ice energy crystal"
desc = "Remnants of the demonic frost miners ice energy."
icon = 'icons/obj/mining_zones/artefacts.dmi'
icon_state = "ice_crystal"
w_class = WEIGHT_CLASS_TINY
throwforce = 0
@@ -0,0 +1,264 @@
// Hierophant club
/obj/item/hierophant_club
name = "hierophant club"
desc = "The strange technology of this large club allows various nigh-magical teleportation feats. It used to beat you, but now you can set the beat."
icon_state = "hierophant_club_ready_beacon"
inhand_icon_state = "hierophant_club_ready_beacon"
icon_angle = -135
icon = 'icons/obj/mining_zones/artefacts.dmi'
lefthand_file = 'icons/mob/inhands/64x64_lefthand.dmi'
righthand_file = 'icons/mob/inhands/64x64_righthand.dmi'
inhand_x_dimension = 64
inhand_y_dimension = 64
slot_flags = ITEM_SLOT_BACK
w_class = WEIGHT_CLASS_NORMAL
force = 15
attack_verb_continuous = list("clubs", "beats", "pummels")
attack_verb_simple = list("club", "beat", "pummel")
hitsound = 'sound/items/weapons/sonic_jackhammer.ogg'
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
actions_types = list(/datum/action/item_action/vortex_recall)
action_slots = ALL
/// Linked teleport beacon for the group teleport functionality.
var/obj/effect/hierophant/beacon
/// TRUE if currently doing a teleport to the beacon, FALSE otherwise.
var/teleporting = FALSE
/// Action enabling the blink-dash functionality.
var/datum/action/innate/dash/hierophant/blink
/// Whether the blink ability is activated. IF TRUE, left clicking a location will blink to it. If FALSE, this is disabled.
var/blink_activated = TRUE
/obj/item/hierophant_club/Initialize(mapload)
. = ..()
AddElement(/datum/element/update_icon_updates_onmob)
blink = new(src)
/obj/item/hierophant_club/Destroy(force)
QDEL_NULL(blink)
return ..()
/obj/item/hierophant_club/examine(mob/user)
. = ..()
if (beacon)
. += span_hierophant_warning("The beacon is currently detached.")
else
. += span_hierophant_warning("There is a beacon attached at the back end of the handle.")
/obj/item/hierophant_club/equipped(mob/user)
. = ..()
blink.Grant(user, src)
user.update_icons()
/obj/item/hierophant_club/dropped(mob/user)
. = ..()
blink.Remove(user)
user.update_icons()
/obj/item/hierophant_club/suicide_act(mob/living/user)
say("Xverwpsgexmrk...", forced = "hierophant club suicide")
user.visible_message(span_suicide("[user] holds [src] into the air! It looks like [user.p_theyre()] trying to commit suicide!"))
new/obj/effect/temp_visual/hierophant/telegraph(get_turf(user))
playsound(user,'sound/machines/airlock/airlockopen.ogg', 75, TRUE)
user.visible_message(span_hierophant_warning("[user] fades out, leaving [user.p_their()] belongings behind!"))
for (var/obj/item/user_item as anything in user.get_all_gear(FALSE, FALSE))
user.dropItemToGround(user_item)
for (var/turf/blast_turf as anything in RANGE_TURFS(1, user))
new /obj/effect/temp_visual/hierophant/blast/visual(blast_turf, user, TRUE)
user.dropItemToGround(src) //Drop us last, so it goes on top of their stuff
qdel(user)
/obj/item/hierophant_club/attack_self(mob/user)
. = ..()
blink_activated = !blink_activated
balloon_alert(user, "blinking [blink_activated ? "enabled" : "disabled"]")
/obj/item/hierophant_club/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
// If our target is the beacon and the hierostaff is next to the beacon, we're trying to pick it up.
if (interacting_with == beacon)
return NONE
if (!blink_activated)
return NONE
if (blink.teleport(user, interacting_with))
return ITEM_INTERACT_SUCCESS
return ITEM_INTERACT_BLOCKING
/obj/item/hierophant_club/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if (blink_activated)
blink.teleport(user, interacting_with)
return ITEM_INTERACT_SUCCESS
return NONE
/obj/item/hierophant_club/update_icon_state()
icon_state = inhand_icon_state = "hierophant_club[blink?.current_charges > 0 ? "_ready" : ""][!QDELETED(beacon) ? "" : "_beacon"]"
return ..()
/obj/item/hierophant_club/ui_action_click(mob/user, action)
if (teleporting)
balloon_alert(user, "already in use!")
return
if (!user.is_holding(src))
to_chat(user, span_warning("You need to hold the club in your hands to [beacon ? "teleport with it" : "detach the beacon"]!"))
return
if (!beacon)
deploy_beacon(user)
return
if (get_dist(user, beacon) <= 2)
balloon_alert(user, "too close to the beacon!")
return
var/turf/beacon_turf = get_turf(beacon)
if (!beacon_turf || beacon_turf.is_blocked_turf(TRUE))
balloon_alert(user, "the beacon is blocked!")
return
if (!isturf(user.loc))
balloon_alert(user, "not enough room to teleport!")
return
var/turf/user_turf = get_turf(user)
teleporting = TRUE
user.update_mob_action_buttons()
user.visible_message(span_hierophant_warning("[user] starts to glow faintly..."), span_hierophant_warning("You begin channeling [src]'s power..i."))
beacon.icon_state = "hierophant_tele_on"
var/obj/effect/temp_visual/hierophant/telegraph/edge/user_telegraph = new /obj/effect/temp_visual/hierophant/telegraph/edge(user_turf)
var/obj/effect/temp_visual/hierophant/telegraph/edge/beacon_telegraph = new /obj/effect/temp_visual/hierophant/telegraph/edge(beacon_turf)
if (!do_after(user, 4 SECONDS, user))
if (user)
balloon_alert(user, "interrupted!")
stop_teleport(user)
qdel(user_telegraph)
qdel(beacon_telegraph)
return
if (!beacon)
balloon_alert(user, "interrupted!")
stop_teleport(user)
return
if (beacon_turf.is_blocked_turf(TRUE))
balloon_alert(user, "the beacon is blocked!")
stop_teleport(user)
return
new /obj/effect/temp_visual/hierophant/telegraph(user_turf, user)
new /obj/effect/temp_visual/hierophant/telegraph(beacon_turf, user)
playsound(user_turf, 'sound/machines/airlock/airlockopen.ogg', 200, TRUE)
playsound(beacon_turf, 'sound/effects/magic/wand_teleport.ogg', 200, TRUE)
new /obj/effect/temp_visual/hierophant/telegraph/teleport(user_turf, user)
new /obj/effect/temp_visual/hierophant/telegraph/teleport(beacon_turf, user)
for(var/turf/turf_near_user_turf as anything in RANGE_TURFS(1, user_turf))
new /obj/effect/temp_visual/hierophant/blast/visual(turf_near_user_turf, user, TRUE)
for(var/turf/turf_near_beacon as anything in RANGE_TURFS(1, beacon_turf))
new /obj/effect/temp_visual/hierophant/blast/visual(turf_near_beacon, user, TRUE)
for(var/mob/living/victim in range(1, user_turf))
INVOKE_ASYNC(src, PROC_REF(teleport_mob), user_turf, beacon_turf, victim, user)
addtimer(CALLBACK(src, PROC_REF(stop_teleport), user), 0.6 SECONDS)
/// Just to cut down on copypasta
/obj/item/hierophant_club/proc/stop_teleport(mob/user)
teleporting = FALSE
if (beacon)
beacon.icon_state = "hierophant_tele_off"
if (user)
user.update_mob_action_buttons()
/// Teleports mobs after a short animation
/obj/item/hierophant_club/proc/teleport_mob(turf/user_turf, turf/beacon_turf, mob/victim, mob/user)
var/turf/target_turf = get_step(beacon_turf, get_dir(user_turf, victim))
if (!target_turf || target_turf.is_blocked_turf(TRUE))
return
animate(victim, alpha = 0, time = 0.2 SECONDS, easing = SINE_EASING|EASE_OUT)
sleep(0.2 SECONDS)
victim.visible_message(span_hierophant_warning("[victim] fades out!"))
var/success = do_teleport(victim, target_turf, no_effects = TRUE, channel = TELEPORT_CHANNEL_MAGIC)
animate(victim, alpha = 255, time = 0.2 SECONDS, SINE_EASING|EASE_OUT)
victim.visible_message(span_hierophant_warning("[victim] fades in!"))
if (user != victim && success)
log_combat(user, victim, "teleported", null, "from [AREACOORD(user_turf)]")
/// Attempts to place a return beacon at user's feet
/obj/item/hierophant_club/proc/deploy_beacon(mob/user)
if (!isopenturf(user.loc) && !isopenspaceturf(user.loc))
to_chat(user, span_warning("You need to be on solid ground to detach the beacon!"))
return
user.visible_message(span_hierophant_warning("[user] starts fiddling with [src]'s pommel..."), span_notice("You start detaching the hierophant beacon..."))
balloon_alert(user, "detaching the beacon...")
if (!do_after(user, 5 SECONDS, user))
balloon_alert(user, "interrupted!")
return
// Already dropped one
if (beacon)
return
var/turf/user_turf = get_turf(user)
new /obj/effect/temp_visual/hierophant/telegraph/teleport(user_turf, user)
beacon = new /obj/effect/hierophant(user_turf)
playsound(beacon, 'sound/effects/magic/blind.ogg', 200, TRUE, -4)
RegisterSignal(beacon, COMSIG_QDELETING, PROC_REF(beacon_destroyed))
user.update_mob_action_buttons()
user.visible_message(span_hierophant_warning("[user] places a strange machine beneath [user.p_their()] feet!"), span_hierophant("You detach the hierophant beacon, allowing you to teleport yourself and any allies to it at any time!"))
to_chat(user, span_hierophant("You can remove the beacon to place it again by striking it with the club."))
update_appearance(UPDATE_ICON_STATE)
/obj/item/hierophant_club/proc/beacon_destroyed(datum/source)
SIGNAL_HANDLER
beacon = null
if (ismob(loc))
to_chat(loc, span_hierophant("With a loud snap, a new beacon appears at [src]'s pommel."))
else
visible_message(span_hierophant("With a loud snap, a new beacon appears at [src]'s pommel."))
playsound(src, 'sound/effects/magic/blind.ogg', 50, TRUE, -4)
update_appearance(UPDATE_ICON_STATE)
#define HIEROPHANT_BLINK_RANGE 5
#define HIEROPHANT_BLINK_COOLDOWN (15 SECONDS)
/datum/action/innate/dash/hierophant
current_charges = 1
max_charges = 1
charge_rate = HIEROPHANT_BLINK_COOLDOWN
recharge_sound = null
phasein = /obj/effect/temp_visual/hierophant/blast/visual
phaseout = /obj/effect/temp_visual/hierophant/blast/visual
// It's a simple purple beam, works well enough for the purple hiero effects.
beam_effect = "plasmabeam"
/datum/action/innate/dash/hierophant/teleport(mob/user, atom/target)
var/dist = get_dist(user, target)
if(dist > HIEROPHANT_BLINK_RANGE)
user.balloon_alert(user, "destination out of range!")
return FALSE
var/turf/target_turf = get_turf(target)
if(target_turf.is_blocked_turf_ignore_climbable())
user.balloon_alert(user, "destination blocked!")
return FALSE
. = ..()
var/obj/item/hierophant_club/club = target
if(!istype(club))
club.update_appearance(UPDATE_ICON_STATE)
/datum/action/innate/dash/hierophant/charge()
. = ..()
var/obj/item/hierophant_club/club = target
if(istype(club))
club.update_appearance(UPDATE_ICON_STATE)
#undef HIEROPHANT_BLINK_RANGE
#undef HIEROPHANT_BLINK_COOLDOWN
@@ -0,0 +1,129 @@
// Staff of storms
/obj/item/storm_staff
name = "staff of storms"
desc = "An ancient staff retrieved from the remains of Legion. The wind stirs as you move it."
icon_state = "staffofstorms"
inhand_icon_state = "staffofstorms"
icon_angle = -45
icon = 'icons/obj/weapons/guns/magic.dmi'
lefthand_file = 'icons/mob/inhands/weapons/staves_lefthand.dmi'
righthand_file = 'icons/mob/inhands/weapons/staves_righthand.dmi'
slot_flags = ITEM_SLOT_BACK
w_class = WEIGHT_CLASS_BULKY
force = 20
damtype = BURN
hitsound = 'sound/items/weapons/taserhit.ogg'
wound_bonus = -30
bare_wound_bonus = 20
resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF
var/max_thunder_charges = 3
var/thunder_charges = 3
var/thunder_charge_time = 15 SECONDS
var/static/list/excluded_areas = list(/area/space)
var/list/targeted_turfs = list()
/obj/item/storm_staff/examine(mob/user)
. = ..()
. += span_notice("It has [thunder_charges] charges remaining.")
. += span_notice("Use it in hand to dispel storms.")
. += span_notice("Use it on targets to summon thunderbolts from the sky.")
. += span_notice("The thunderbolts are boosted if in an area with weather effects.")
/obj/item/storm_staff/attack_self(mob/user)
var/area/user_area = get_area(user)
var/turf/user_turf = get_turf(user)
if(!user_area || !user_turf || (is_type_in_list(user_area, excluded_areas)))
to_chat(user, span_warning("Something is preventing you from using the staff here."))
return
var/datum/weather/affected_weather
for(var/datum/weather/weather as anything in SSweather.processing)
if((user_turf.z in weather.impacted_z_levels) && ispath(user_area.type, weather.area_type))
affected_weather = weather
break
if(!affected_weather)
return
if(affected_weather.stage == END_STAGE)
balloon_alert(user, "already ended!")
return
if(affected_weather.stage == WIND_DOWN_STAGE)
balloon_alert(user, "already ending!")
return
balloon_alert(user, "you hold the staff up...")
if(!do_after(user, 3 SECONDS, target = src))
balloon_alert(user, "interrupted!")
return
user.visible_message(span_warning("[user] holds [src] skywards as an orange beam travels into the sky!"), \
span_notice("You hold [src] skyward, dispelling the storm!"))
playsound(user, 'sound/effects/magic/staff_change.ogg', 200, FALSE)
var/old_color = user.color
user.color = list(340/255, 240/255, 0,0, 0,0,0,0, 0,0,0,0, 0,0,0,1, 0,0,0,0)
var/old_transform = user.transform
user.transform *= 1.2
animate(user, color = old_color, transform = old_transform, time = 1 SECONDS)
affected_weather.wind_down()
user.log_message("has dispelled a storm at [AREACOORD(user_turf)].", LOG_GAME)
/obj/item/storm_staff/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
return thunder_blast(interacting_with, user) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING
/obj/item/storm_staff/afterattack(atom/target, mob/user, click_parameters)
thunder_blast(target, user)
/obj/item/storm_staff/proc/thunder_blast(atom/target, mob/user)
if(!thunder_charges)
balloon_alert(user, "needs to charge!")
return FALSE
var/turf/target_turf = get_turf(target)
var/area/target_area = get_area(target)
if(!target_turf || !target_area || (is_type_in_list(target_area, excluded_areas)))
balloon_alert(user, "can't bolt here!")
return FALSE
if(target_turf in targeted_turfs)
balloon_alert(user, "already targeted!")
return FALSE
if(HAS_TRAIT(user, TRAIT_PACIFISM))
balloon_alert(user, "you don't want to harm!")
return FALSE
var/power_boosted = FALSE
for(var/datum/weather/weather as anything in SSweather.processing)
if(weather.stage != MAIN_STAGE)
continue
if((target_turf.z in weather.impacted_z_levels) && ispath(target_area.type, weather.area_type))
power_boosted = TRUE
break
playsound(src, 'sound/effects/magic/lightningshock.ogg', 10, TRUE, extrarange = SILENCED_SOUND_EXTRARANGE, falloff_distance = 0)
targeted_turfs += target_turf
balloon_alert(user, "you aim at [target_turf]...")
new /obj/effect/temp_visual/telegraphing/thunderbolt(target_turf)
addtimer(CALLBACK(src, PROC_REF(throw_thunderbolt), target_turf, power_boosted), 1.5 SECONDS)
thunder_charges--
addtimer(CALLBACK(src, PROC_REF(recharge)), thunder_charge_time)
user.log_message("fired the staff of storms at [AREACOORD(target_turf)].", LOG_ATTACK)
return TRUE
/obj/item/storm_staff/proc/recharge(mob/user)
thunder_charges = min(thunder_charges + 1, max_thunder_charges)
playsound(src, 'sound/effects/magic/charge.ogg', 10, TRUE, extrarange = SILENCED_SOUND_EXTRARANGE, falloff_distance = 0)
/obj/item/storm_staff/proc/throw_thunderbolt(turf/target, boosted)
targeted_turfs -= target
new /obj/effect/temp_visual/thunderbolt(target)
var/list/affected_turfs = list(target)
if(boosted)
for(var/direction in GLOB.alldirs)
var/turf_to_add = get_step(target, direction)
if(!turf_to_add)
continue
affected_turfs += turf_to_add
for(var/turf/turf as anything in affected_turfs)
new /obj/effect/temp_visual/electricity(turf)
for(var/mob/living/hit_mob in turf)
to_chat(hit_mob, span_userdanger("You've been struck by lightning!"))
hit_mob.electrocute_act(15 * (isanimal_or_basicmob(hit_mob) ? 3 : 1) * (turf == target ? 2 : 1) * (boosted ? 2 : 1), src, flags = SHOCK_TESLA|SHOCK_NOSTUN)
for(var/obj/hit_thing in turf)
hit_thing.take_damage(20, BURN, ENERGY, FALSE)
playsound(target, 'sound/effects/magic/lightningbolt.ogg', 100, TRUE)
target.visible_message(span_danger("A thunderbolt strikes [target]!"))
explosion(target, light_impact_range = (boosted ? 1 : 0), flame_range = (boosted ? 2 : 1), silent = TRUE)
@@ -0,0 +1,170 @@
/datum/action/innate/brain_undeployment
name = "Disconnect from shell"
desc = "Stop controlling your shell and resume normal core operations."
button_icon = 'icons/mob/actions/actions_AI.dmi'
button_icon_state = "ai_core"
/datum/action/innate/brain_undeployment/Trigger(trigger_flags)
if(!..())
return FALSE
var/obj/item/organ/brain/cybernetic/ai/shell_to_disconnect = owner.get_organ_by_type(/obj/item/organ/brain/cybernetic/ai)
shell_to_disconnect.undeploy()
return TRUE
/obj/item/organ/brain/cybernetic/ai
name = "AI-uplink brain"
desc = "Can be inserted into a body with NO ORGANIC INTERNAL ORGANS (robotic organs only) to allow AIs to control it. Comes with its own health sensors beacon. MUST be a humanoid or bad things happen to the consciousness."
can_smoothen_out = FALSE
/// if connected, our AI
var/mob/living/silicon/ai/mainframe
/// action for undeployment
var/datum/action/innate/brain_undeployment/undeployment_action = new
/obj/item/organ/brain/cybernetic/ai/Initialize(mapload)
. = ..()
AddElement(/datum/element/noticable_organ, "%PRONOUN_Their eyes move with machine precision, their expression completely blank.")
/obj/item/organ/brain/cybernetic/ai/Destroy()
. = ..()
undeploy()
mainframe = null
QDEL_NULL(undeployment_action)
/obj/item/organ/brain/cybernetic/ai/on_mob_insert(mob/living/carbon/brain_owner, special, movement_flags)
. = ..()
brain_owner.add_traits(list(HUMAN_SENSORS_VISIBLE_WITHOUT_SUIT, TRAIT_NO_MINDSWAP, TRAIT_CORPSELOCKED), REF(src))
update_med_hud_status(brain_owner)
RegisterSignal(brain_owner, COMSIG_LIVING_HEALTH_UPDATE, PROC_REF(update_med_hud_status))
RegisterSignal(brain_owner, COMSIG_CLICK, PROC_REF(owner_clicked))
RegisterSignal(brain_owner, COMSIG_MOB_GET_STATUS_TAB_ITEMS, PROC_REF(get_status_tab_item))
RegisterSignal(brain_owner, COMSIG_MOB_MIND_BEFORE_MIDROUND_ROLL, PROC_REF(cancel_rolls))
RegisterSignals(brain_owner, list(COMSIG_QDELETING, COMSIG_LIVING_PRE_WABBAJACKED), PROC_REF(undeploy))
RegisterSignal(brain_owner, COMSIG_CARBON_GAIN_ORGAN, PROC_REF(on_organ_gain))
/obj/item/organ/brain/cybernetic/ai/on_mob_remove(mob/living/carbon/organ_owner, special, movement_flags)
undeploy()
. = ..()
organ_owner.remove_traits(list(HUMAN_SENSORS_VISIBLE_WITHOUT_SUIT, TRAIT_NO_MINDSWAP, TRAIT_CORPSELOCKED), REF(src))
UnregisterSignal(organ_owner, list(COMSIG_LIVING_HEALTH_UPDATE, COMSIG_CLICK, COMSIG_MOB_GET_STATUS_TAB_ITEMS, COMSIG_MOB_MIND_BEFORE_MIDROUND_ROLL, COMSIG_QDELETING, COMSIG_LIVING_PRE_WABBAJACKED))
/obj/item/organ/brain/cybernetic/ai/proc/cancel_rolls(mob/living/source, datum/mind/mind, datum/antagonist/antagonist)
SIGNAL_HANDLER
if(ispath(antagonist, /datum/antagonist/malf_ai))
return
return CANCEL_ROLL
/obj/item/organ/brain/cybernetic/ai/proc/get_status_tab_item(mob/living/source, list/items)
SIGNAL_HANDLER
if(!mainframe)
return
items += mainframe.get_status_tab_items()
/obj/item/organ/brain/cybernetic/ai/proc/update_med_hud_status(mob/living/mob_parent)
SIGNAL_HANDLER
var/image/holder = mob_parent.hud_list?[STATUS_HUD]
if(isnull(holder))
return
var/icon/size_check = icon(mob_parent.icon, mob_parent.icon_state, mob_parent.dir)
holder.pixel_y = size_check.Height() - ICON_SIZE_Y
if(mob_parent.stat == DEAD || HAS_TRAIT(mob_parent, TRAIT_FAKEDEATH) || isnull(mainframe))
holder.icon_state = "huddead2"
holder.pixel_x = -8 // new icon states? nuh uh
else
holder.icon_state = "hudtrackingai"
holder.pixel_x = -16
// no thoughts only wifi
/obj/item/organ/brain/cybernetic/ai/can_gain_trauma(datum/brain_trauma/trauma, resilience, natural_gain = FALSE)
return FALSE
/obj/item/organ/brain/cybernetic/ai/proc/owner_clicked(datum/source, atom/location, control, params, mob/user)
SIGNAL_HANDLER
if(!isAI(user))
return
var/list/lines = list()
lines += span_bold("[owner]")
lines += "Target is currently [!HAS_TRAIT(owner, TRAIT_INCAPACITATED) ? "functional" : "incapacitated"]"
lines += "Estimated organic/inorganic integrity: [owner.health]"
if(mainframe)
lines += span_warning("Already occupied by another digital entity.")
else if(!is_sufficiently_augmented())
lines += span_warning("Organic organs detected. Robotic organs only, cannot take over.")
else
lines += "<a href='byond://?src=[REF(src)];ai_take_control=[REF(user)]'>[span_boldnotice("Take control?")]</a><br>"
to_chat(user, boxed_message(jointext(lines, "\n")), type = MESSAGE_TYPE_INFO)
/obj/item/organ/brain/cybernetic/ai/Topic(href, href_list)
..()
if(!href_list["ai_take_control"] || !is_sufficiently_augmented() || mainframe)
return
var/mob/living/silicon/ai/AI = locate(href_list["ai_take_control"]) in GLOB.silicon_mobs
if(isnull(AI))
return
if(AI.controlled_equipment)
to_chat(AI, span_warning("You are already loaded into an onboard computer!"))
return
if(!GLOB.cameranet.checkCameraVis(owner))
to_chat(AI, span_warning("Target is no longer near active cameras."))
return
if(!isturf(AI.loc))
to_chat(AI, span_warning("You aren't in your core!"))
return
RegisterSignal(owner, COMSIG_LIVING_DEATH, PROC_REF(undeploy))
AI.deployed_shell = owner
deploy_init(AI)
ADD_TRAIT(AI.mind, TRAIT_UNCONVERTABLE, REF(src))
ADD_TRAIT(AI, TRAIT_MIND_TEMPORARILY_GONE, REF(src))
AI.mind.transfer_to(owner)
/obj/item/organ/brain/cybernetic/ai/proc/deploy_init(mob/living/silicon/ai/AI)
//todo camera maybe
mainframe = AI
RegisterSignal(AI, COMSIG_QDELETING, PROC_REF(ai_deleted))
undeployment_action.Grant(owner)
update_med_hud_status(owner)
to_chat(owner, span_boldbig("You are still considered a silicon/cyborg/AI. Follow your laws."))
/obj/item/organ/brain/cybernetic/ai/proc/undeploy(datum/source)
SIGNAL_HANDLER
if(!owner?.mind || !mainframe)
return
UnregisterSignal(owner, list(COMSIG_LIVING_DEATH, COMSIG_QDELETING))
UnregisterSignal(mainframe, COMSIG_QDELETING)
mainframe.redeploy_action.Remove(mainframe)
mainframe.redeploy_action.last_used_shell = null
owner.mind.transfer_to(mainframe)
mainframe.deployed_shell = null
undeployment_action.Remove(owner)
if(mainframe.laws)
mainframe.laws.show_laws(mainframe)
if(mainframe.eyeobj)
mainframe.eyeobj.setLoc(loc)
REMOVE_TRAIT(mainframe.mind, TRAIT_UNCONVERTABLE, REF(src))
REMOVE_TRAIT(mainframe, TRAIT_MIND_TEMPORARILY_GONE, REF(src))
mainframe = null
update_med_hud_status(owner)
/obj/item/organ/brain/cybernetic/ai/proc/is_sufficiently_augmented()
var/mob/living/carbon/carb_owner = owner
. = TRUE
if(!istype(carb_owner))
return
for(var/obj/item/organ/organ as anything in carb_owner.organs)
if(organ.organ_flags & ORGAN_EXTERNAL)
continue
if(!IS_ROBOTIC_ORGAN(organ) && !istype(organ, /obj/item/organ/tongue)) //tongues are not in the exosuit fab and nobody is going to bother to find them so
return FALSE
/obj/item/organ/brain/cybernetic/ai/proc/on_organ_gain(datum/source, obj/item/organ/new_organ, special)
SIGNAL_HANDLER
if(!is_sufficiently_augmented())
to_chat(owner, span_danger("Connection failure. Organics detected."))
undeploy()
/obj/item/organ/brain/cybernetic/ai/proc/ai_deleted(datum/source)
SIGNAL_HANDLER
to_chat(owner, span_danger("Your core has been rendered inoperable..."))
undeploy()
@@ -0,0 +1,29 @@
// Wendigo blood
/obj/item/wendigo_blood
name = "bottle of wendigo blood"
desc = "A bottle of viscous red liquid... You're not actually going to drink this, are you?"
icon = 'icons/obj/mining_zones/artefacts.dmi'
icon_state = "vial"
/obj/item/wendigo_blood/attack_self(mob/living/user)
if(!ishuman(user))
return
var/mob/living/carbon/human/human_user = user
if(!human_user.mind)
return
to_chat(human_user, span_danger("Power courses through you! You can now shift your form at will."))
var/datum/action/cooldown/spell/shapeshift/polar_bear/transformation_spell = new(user.mind || user)
transformation_spell.Grant(user)
playsound(human_user.loc, 'sound/items/drink.ogg', rand(10,50), TRUE)
qdel(src)
// Wendigo skull
/obj/item/wendigo_skull
name = "wendigo skull"
desc = "A bloody skull torn from a murderous beast, the soulless eye sockets seem to constantly track your movement."
icon = 'icons/obj/mining_zones/artefacts.dmi'
icon_state = "wendigo_skull"
w_class = WEIGHT_CLASS_TINY
throwforce = 0
File diff suppressed because it is too large Load Diff
@@ -224,378 +224,4 @@
else
SSexplosions.medturf += target
///Anomolous Crystal///
#define ACTIVATE_TOUCH "touch"
#define ACTIVATE_SPEECH "speech"
#define ACTIVATE_HEAT "heat"
#define ACTIVATE_BULLET "bullet"
#define ACTIVATE_ENERGY "energy"
#define ACTIVATE_BOMB "bomb"
#define ACTIVATE_MOB_BUMP "bumping"
#define ACTIVATE_WEAPON "weapon"
#define ACTIVATE_MAGIC "magic"
/obj/machinery/anomalous_crystal
name = "anomalous crystal"
desc = "A strange chunk of crystal, being in the presence of it fills you with equal parts excitement and dread."
var/observer_desc = "Anomalous crystals have descriptions that only observers can see. But this one hasn't been changed from the default."
icon = 'icons/obj/mining_zones/artefacts.dmi'
icon_state = "anomaly_crystal"
light_range = 8
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
use_power = NO_POWER_USE
anchored = FALSE
density = TRUE
var/activation_method
var/list/possible_methods = list(ACTIVATE_TOUCH, ACTIVATE_SPEECH, ACTIVATE_HEAT, ACTIVATE_BULLET, ACTIVATE_ENERGY, ACTIVATE_BOMB, ACTIVATE_MOB_BUMP, ACTIVATE_WEAPON, ACTIVATE_MAGIC)
var/activation_damage_type = null
/// Cooldown on this crystal
var/cooldown_add = 3 SECONDS
/// Time needed to use this crystal
var/use_time = 0
/// If we are being used
var/active = FALSE
var/activation_sound = 'sound/effects/break_stone.ogg'
COOLDOWN_DECLARE(cooldown_timer)
/obj/machinery/anomalous_crystal/Initialize(mapload)
. = ..()
if(!activation_method)
activation_method = pick(possible_methods)
become_hearing_sensitive(trait_source = ROUNDSTART_TRAIT)
/obj/machinery/anomalous_crystal/examine(mob/user)
. = ..()
if(isobserver(user))
. += observer_desc
. += "It is activated by [activation_method]."
/obj/machinery/anomalous_crystal/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans, list/message_mods = list(), message_range)
. = ..()
if(isliving(speaker))
ActivationReaction(speaker, ACTIVATE_SPEECH)
/obj/machinery/anomalous_crystal/attack_hand(mob/user, list/modifiers)
. = ..()
if(.)
return
ActivationReaction(user, ACTIVATE_TOUCH)
/obj/machinery/anomalous_crystal/attackby(obj/item/I, mob/user, params)
if(I.get_temperature())
ActivationReaction(user, ACTIVATE_HEAT)
else
ActivationReaction(user, ACTIVATE_WEAPON)
..()
/obj/machinery/anomalous_crystal/bullet_act(obj/projectile/proj, def_zone)
. = ..()
if(istype(proj, /obj/projectile/magic))
ActivationReaction(proj.firer, ACTIVATE_MAGIC, proj.damage_type)
return
ActivationReaction(proj.firer, proj.armor_flag, proj.damage_type)
/obj/machinery/anomalous_crystal/proc/ActivationReaction(mob/user, method, damtype)
if(!COOLDOWN_FINISHED(src, cooldown_timer))
return FALSE
if(activation_damage_type && activation_damage_type != damtype)
return FALSE
if(method != activation_method)
return FALSE
if(active)
return FALSE
if(use_time)
charge_animation()
COOLDOWN_START(src, cooldown_timer, cooldown_add)
playsound(user, activation_sound, 100, TRUE)
log_game("[src] activated by [key_name(user)] in [AREACOORD(src)]. The last fingerprints on the [src] was [fingerprintslast].")
return TRUE
/obj/machinery/anomalous_crystal/proc/charge_animation()
icon_state = "anomaly_crystal_charging"
active = TRUE
set_anchored(TRUE)
balloon_alert_to_viewers("charging...")
playsound(src, 'sound/effects/magic/disable_tech.ogg', 50, TRUE)
sleep(use_time)
icon_state = initial(icon_state)
active = FALSE
set_anchored(FALSE)
return TRUE
/obj/machinery/anomalous_crystal/Bumped(atom/movable/AM)
..()
if(ismob(AM))
ActivationReaction(AM, ACTIVATE_MOB_BUMP)
/obj/machinery/anomalous_crystal/ex_act()
ActivationReaction(null, ACTIVATE_BOMB)
return TRUE
/obj/machinery/anomalous_crystal/honk //Revives the dead, but strips and equips them as a clown
observer_desc = "This crystal revives targets around it as clowns. Oh, that's horrible...."
activation_method = ACTIVATE_TOUCH
activation_sound = 'sound/items/bikehorn.ogg'
use_time = 3 SECONDS
/// List of REFs to mobs that have been turned into a clown
var/list/clowned_mob_refs = list()
/obj/machinery/anomalous_crystal/honk/ActivationReaction(mob/user)
. = ..()
if(!.)
return FALSE
for(var/atom/thing as anything in range(1, src))
if(isturf(thing))
new /obj/effect/decal/cleanable/confetti(thing)
continue
if(!ishuman(thing))
continue
var/mob/living/carbon/human/new_clown = thing
if(new_clown.stat != DEAD)
continue
new_clown.revive(ADMIN_HEAL_ALL, force_grab_ghost = TRUE)
var/clown_ref = REF(new_clown)
if(clown_ref in clowned_mob_refs) //one clowning per person
continue
for(var/obj/item/to_strip in new_clown.get_equipped_items())
new_clown.dropItemToGround(to_strip)
new_clown.dress_up_as_job(SSjob.get_job_type(/datum/job/clown))
clowned_mob_refs += clown_ref
return TRUE
/// Transforms the area to look like a new one
/obj/machinery/anomalous_crystal/theme_warp
observer_desc = "This crystal warps the area around it to a theme."
activation_method = ACTIVATE_TOUCH
cooldown_add = 20 SECONDS
use_time = 5 SECONDS
/// Theme which we turn areas into on activation
var/datum/dimension_theme/terrain_theme
/// List of all areas we've affected
var/list/converted_areas = list()
/obj/machinery/anomalous_crystal/theme_warp/Initialize(mapload)
. = ..()
terrain_theme = SSmaterials.dimensional_themes[pick(subtypesof(/datum/dimension_theme))]
observer_desc = "This crystal changes the area around it to match the theme of \"[terrain_theme.name]\"."
/obj/machinery/anomalous_crystal/theme_warp/ActivationReaction(mob/user, method)
. = ..()
if (!.)
return FALSE
var/area/current_area = get_area(src)
if (current_area in converted_areas)
return FALSE
terrain_theme.apply_theme_to_list_of_turfs(current_area.get_turfs_from_all_zlevels())
converted_areas += current_area
return TRUE
/obj/machinery/anomalous_crystal/theme_warp/Destroy()
terrain_theme = null
converted_areas.Cut()
return ..()
/obj/machinery/anomalous_crystal/emitter //Generates a projectile when interacted with
observer_desc = "This crystal generates a projectile when activated."
activation_method = ACTIVATE_TOUCH
cooldown_add = 5 SECONDS
var/obj/projectile/generated_projectile = /obj/projectile/colossus
/obj/machinery/anomalous_crystal/emitter/Initialize(mapload)
. = ..()
observer_desc = "This crystal generates \a [initial(generated_projectile.name)] when activated."
/obj/machinery/anomalous_crystal/emitter/ActivationReaction(mob/user, method)
if(..())
var/obj/projectile/proj = new generated_projectile(get_turf(src))
proj.firer = src
proj.fire(dir2angle(dir))
/obj/machinery/anomalous_crystal/dark_reprise //Revives anyone nearby, but turns them into shadowpeople and renders them uncloneable, so the crystal is your only hope of getting up again if you go down.
observer_desc = "When activated, this crystal revives anyone nearby, but turns them into Shadowpeople and makes them unclonable, making the crystal their only hope of getting up again."
activation_method = ACTIVATE_TOUCH
activation_sound = 'sound/effects/hallucinations/growl1.ogg'
use_time = 3 SECONDS
/obj/machinery/anomalous_crystal/dark_reprise/ActivationReaction(mob/user, method)
. = ..()
if(!.)
return FALSE
for(var/atom/thing as anything in range(1, src))
if(isturf(thing))
new /obj/effect/temp_visual/cult/sparks(thing)
continue
if(!ishuman(thing))
continue
var/mob/living/carbon/human/to_revive = thing
if(to_revive.stat != DEAD)
continue
to_revive.set_species(/datum/species/shadow, TRUE)
to_revive.revive(ADMIN_HEAL_ALL, force_grab_ghost = TRUE)
//Free revives, but significantly limits your options for reviving except via the crystal
//except JK who cares about BADDNA anymore. this even heals suicides.
ADD_TRAIT(to_revive, TRAIT_BADDNA, MAGIC_TRAIT)
return TRUE
/obj/machinery/anomalous_crystal/helpers //Lets ghost spawn as helpful creatures that can only heal people slightly. Incredibly fragile and they can't converse with humans
observer_desc = "This crystal allows ghosts to turn into a fragile creature that can heal people."
activation_method = ACTIVATE_TOUCH
activation_sound = 'sound/effects/ghost2.ogg'
use_time = 5 SECONDS
var/ready_to_deploy = FALSE
/obj/machinery/anomalous_crystal/helpers/ActivationReaction(mob/user, method)
if(..() && !ready_to_deploy)
SSpoints_of_interest.make_point_of_interest(src)
ready_to_deploy = TRUE
notify_ghosts(
"An anomalous crystal has been activated in [get_area(src)]! This crystal can always be used by ghosts hereafter.",
source = src,
header = "Anomalous crystal activated",
click_interact = TRUE,
ghost_sound = 'sound/effects/ghost2.ogg',
)
/obj/machinery/anomalous_crystal/helpers/attack_ghost(mob/dead/observer/user)
. = ..()
if(.)
return
if(ready_to_deploy)
var/be_helper = tgui_alert(usr, "Become a Lightgeist? (Warning, You can no longer be revived!)", "Lightgeist Deployment", list("Yes", "No"))
if((be_helper == "Yes") && !QDELETED(src) && isobserver(user))
var/mob/living/basic/lightgeist/deployable = new(get_turf(loc))
deployable.PossessByPlayer(user.key)
/obj/machinery/anomalous_crystal/possessor //Allows you to bodyjack small animals, then exit them at your leisure, but you can only do this once per activation. Because they blow up. Also, if the bodyjacked animal dies, SO DO YOU.
observer_desc = "When activated, this crystal allows you to take over small animals, and then exit them at the possessors leisure. Exiting the animal kills it, and if you die while possessing the animal, you die as well."
activation_method = ACTIVATE_TOUCH
use_time = 1 SECONDS
/obj/machinery/anomalous_crystal/possessor/ActivationReaction(mob/user, method)
. = ..()
if (!. || !ishuman(user))
return FALSE
var/list/valid_mobs = list()
var/list/nearby_things = range(1, src)
for(var/mob/living/basic/possible_mob in nearby_things)
if (!is_valid_animal(possible_mob))
continue
valid_mobs += possible_mob
for(var/mob/living/simple_animal/possible_mob in nearby_things)
if (!is_valid_animal(possible_mob))
continue
valid_mobs += possible_mob
if (!length(valid_mobs)) //Just in case there aren't any animals on the station, this will leave you with a terrible option to possess if you feel like it //i found it funny that in the file for a giant angel beast theres a cockroach
new /mob/living/basic/cockroach(get_step(src,dir))
return
var/mob/living/picked_mob = pick(valid_mobs)
var/obj/structure/closet/stasis/possessor_container = new /obj/structure/closet/stasis(picked_mob)
user.forceMove(possessor_container)
/// Returns true if this is a mob you're allowed to possess
/obj/machinery/anomalous_crystal/possessor/proc/is_valid_animal(mob/living/check_mob)
return check_mob.stat != DEAD && !check_mob.ckey && check_mob.mob_size < MOB_SIZE_LARGE && check_mob.melee_damage_upper <= 5
/obj/structure/closet/stasis
name = "quantum entanglement stasis warp field"
desc = "You can hardly comprehend this thing... which is why you can't see it."
icon_state = null //This shouldn't even be visible, so if it DOES show up, at least nobody will notice
enable_door_overlay = FALSE //For obvious reasons
density = TRUE
anchored = TRUE
resistance_flags = FIRE_PROOF | ACID_PROOF | INDESTRUCTIBLE
paint_jobs = null
///The animal the closet (and the user's body) is inside of
var/mob/living/holder_animal
/obj/structure/closet/stasis/Initialize(mapload)
. = ..()
if(isanimal_or_basicmob(loc))
holder_animal = loc
RegisterSignal(holder_animal, COMSIG_LIVING_DEATH, PROC_REF(on_holder_animal_death))
AddElement(/datum/element/empprotection, EMP_PROTECT_ALL)
/obj/structure/closet/stasis/Entered(atom/movable/arrived, atom/old_loc, list/atom/old_locs)
. = ..()
if(isliving(arrived) && holder_animal)
var/mob/living/possessor = arrived
possessor.add_traits(list(TRAIT_UNDENSE, TRAIT_NO_TRANSFORM, TRAIT_GODMODE), STASIS_MUTE)
possessor.mind.transfer_to(holder_animal)
var/datum/action/exit_possession/escape = new(holder_animal)
escape.Grant(holder_animal)
remove_verb(holder_animal, /mob/living/verb/pulled)
/obj/structure/closet/stasis/dump_contents(kill = TRUE)
for(var/mob/living/possessor in src)
possessor.remove_traits(list(TRAIT_UNDENSE, TRAIT_NO_TRANSFORM, TRAIT_GODMODE), STASIS_MUTE)
if(kill || !isanimal_or_basicmob(loc))
possessor.investigate_log("has died from [src].", INVESTIGATE_DEATHS)
possessor.death(FALSE)
if(holder_animal)
holder_animal.mind.transfer_to(possessor)
possessor.mind.grab_ghost(force = TRUE)
possessor.forceMove(get_turf(holder_animal))
holder_animal.investigate_log("has been gibbed by [src].", INVESTIGATE_DEATHS)
holder_animal.gib(DROP_ALL_REMAINS)
return ..()
return ..()
/obj/structure/closet/stasis/ex_act()
return FALSE
///When our host animal dies in any way, we empty the stasis closet out.
/obj/structure/closet/stasis/proc/on_holder_animal_death()
SIGNAL_HANDLER
dump_contents()
/datum/action/exit_possession
name = "Exit Possession"
desc = "Exits the body you are possessing. They will explode violently when this occurs."
button_icon = 'icons/mob/actions/actions_spells.dmi'
button_icon_state = "exit_possession"
/datum/action/exit_possession/IsAvailable(feedback = FALSE)
return ..() && isfloorturf(owner.loc)
/datum/action/exit_possession/Trigger(trigger_flags)
. = ..()
if(!.)
return FALSE
var/obj/structure/closet/stasis/stasis = locate() in owner
if(!stasis)
CRASH("[type] did not find a stasis closet thing in the owner.")
stasis.dump_contents(FALSE)
qdel(stasis)
qdel(src)
#undef ACTIVATE_BOMB
#undef ACTIVATE_BULLET
#undef ACTIVATE_ENERGY
#undef ACTIVATE_HEAT
#undef ACTIVATE_MAGIC
#undef ACTIVATE_MOB_BUMP
#undef ACTIVATE_SPEECH
#undef ACTIVATE_TOUCH
#undef ACTIVATE_WEAPON
#undef COLOSSUS_ENRAGED
@@ -232,95 +232,6 @@ Difficulty: Extremely Hard
if(isturf(target) || isobj(target))
EX_ACT(target, EXPLODE_HEAVY)
/obj/item/resurrection_crystal
name = "resurrection crystal"
desc = "When used by anything holding it, this crystal gives them a second chance at life if they die."
icon = 'icons/obj/mining.dmi'
icon_state = "demonic_crystal"
/obj/item/resurrection_crystal/attack_self(mob/living/user)
if(!iscarbon(user))
to_chat(user, span_notice("A dark presence stops you from absorbing the crystal."))
return
forceMove(user)
to_chat(user, span_notice("You feel a bit safer... but a demonic presence lurks in the back of your head..."))
RegisterSignal(user, COMSIG_LIVING_DEATH, PROC_REF(resurrect))
/// Resurrects the target when they die by moving them and dusting a clone in their place, one life for another
/obj/item/resurrection_crystal/proc/resurrect(mob/living/carbon/user, gibbed)
SIGNAL_HANDLER
if(gibbed)
to_chat(user, span_notice("This power cannot be used if your entire mortal body is disintegrated..."))
return
user.visible_message(span_notice("You see [user]'s soul dragged out of their body!"), span_notice("You feel your soul dragged away to a fresh body!"))
var/typepath = user.type
var/mob/living/carbon/clone = new typepath(user.loc)
clone.real_name = user.real_name
INVOKE_ASYNC(user.dna, TYPE_PROC_REF(/datum/dna, transfer_identity), clone)
clone.updateappearance(mutcolor_update=1)
var/turf/T = find_maintenance_spawn(atmos_sensitive = TRUE, require_darkness = TRUE) || find_safe_turf()
user.forceMove(T)
user.revive(ADMIN_HEAL_ALL)
INVOKE_ASYNC(user, TYPE_PROC_REF(/mob/living/carbon, set_species), /datum/species/shadow)
to_chat(user, span_notice("You blink and find yourself in [get_area_name(T)]... feeling a bit darker."))
clone.dust()
qdel(src)
/obj/item/clothing/shoes/winterboots/ice_boots/ice_trail
name = "cursed ice hiking boots"
desc = "A pair of winter boots contractually made by a devil, they cannot be taken off once put on."
actions_types = list(/datum/action/item_action/toggle)
var/on = FALSE
var/change_turf = /turf/open/misc/ice/icemoon/no_planet_atmos
var/duration = 6 SECONDS
/obj/item/clothing/shoes/winterboots/ice_boots/ice_trail/Initialize(mapload)
. = ..()
RegisterSignal(src, COMSIG_SHOES_STEP_ACTION, PROC_REF(on_step))
/obj/item/clothing/shoes/winterboots/ice_boots/ice_trail/equipped(mob/user, slot)
. = ..()
if(slot & ITEM_SLOT_FEET)
ADD_TRAIT(src, TRAIT_NODROP, CURSED_ITEM_TRAIT(type))
/obj/item/clothing/shoes/winterboots/ice_boots/ice_trail/dropped(mob/user)
. = ..()
// Could have been blown off in an explosion from the previous owner
REMOVE_TRAIT(src, TRAIT_NODROP, CURSED_ITEM_TRAIT(type))
/obj/item/clothing/shoes/winterboots/ice_boots/ice_trail/ui_action_click(mob/user)
on = !on
to_chat(user, span_notice("You [on ? "activate" : "deactivate"] [src]."))
/obj/item/clothing/shoes/winterboots/ice_boots/ice_trail/examine(mob/user)
. = ..()
. += span_notice("The shoes are [on ? "enabled" : "disabled"].")
/obj/item/clothing/shoes/winterboots/ice_boots/ice_trail/proc/on_step()
SIGNAL_HANDLER
var/turf/T = get_turf(loc)
if(!on || isclosedturf(T) || istype(T, change_turf))
return
var/reset_turf = T.type
T.ChangeTurf(change_turf, flags = CHANGETURF_INHERIT_AIR)
addtimer(CALLBACK(T, TYPE_PROC_REF(/turf, ChangeTurf), reset_turf, null, CHANGETURF_INHERIT_AIR), duration, TIMER_OVERRIDE|TIMER_UNIQUE)
/obj/item/pickaxe/drill/jackhammer/demonic
name = "demonic jackhammer"
desc = "Cracks rocks at an inhuman speed, as well as being enhanced for combat purposes."
toolspeed = 0
/obj/item/pickaxe/drill/jackhammer/demonic/Initialize(mapload)
. = ..()
AddElement(/datum/element/knockback, 4, TRUE, FALSE)
AddElement(/datum/element/lifesteal, 5)
/obj/item/pickaxe/drill/jackhammer/demonic/use_tool(atom/target, mob/living/user, delay, amount=0, volume=0, datum/callback/extra_checks)
var/turf/T = get_turf(target)
mineral_scan_pulse(T, world.view + 1, src)
. = ..()
/datum/status_effect/ice_block_talisman
id = "ice_block_talisman"
duration = 4 SECONDS
@@ -365,14 +276,6 @@ Difficulty: Extremely Hard
owner.cut_overlay(cube)
UnregisterSignal(owner, COMSIG_MOVABLE_PRE_MOVE)
/obj/item/ice_energy_crystal
name = "ice energy crystal"
desc = "Remnants of the demonic frost miners ice energy."
icon = 'icons/obj/mining_zones/artefacts.dmi'
icon_state = "ice_crystal"
w_class = WEIGHT_CLASS_TINY
throwforce = 0
/obj/structure/frost_miner_prism
name = "frost miner light prism"
desc = "A magical crystal enhanced by a demonic presence."
@@ -222,32 +222,6 @@ Difficulty: Hard
pixel_moves += .
set_angle(original_angle + pixel_moves * wave_speed)
/obj/item/wendigo_blood
name = "bottle of wendigo blood"
desc = "A bottle of viscous red liquid... You're not actually going to drink this, are you?"
icon = 'icons/obj/mining_zones/artefacts.dmi'
icon_state = "vial"
/obj/item/wendigo_blood/attack_self(mob/living/user)
if(!ishuman(user))
return
var/mob/living/carbon/human/human_user = user
if(!human_user.mind)
return
to_chat(human_user, span_danger("Power courses through you! You can now shift your form at will."))
var/datum/action/cooldown/spell/shapeshift/polar_bear/transformation_spell = new(user.mind || user)
transformation_spell.Grant(user)
playsound(human_user.loc, 'sound/items/drink.ogg', rand(10,50), TRUE)
qdel(src)
/obj/item/wendigo_skull
name = "wendigo skull"
desc = "A bloody skull torn from a murderous beast, the soulless eye sockets seem to constantly track your movement."
icon = 'icons/obj/mining_zones/artefacts.dmi'
icon_state = "wendigo_skull"
w_class = WEIGHT_CLASS_TINY
throwforce = 0
/mob/living/simple_animal/hostile/megafauna/wendigo/noportal/create_portal()
return
@@ -255,3 +255,37 @@
)
departmental_flags = DEPARTMENT_BITFLAG_CARGO
/datum/design/unique_modkit
category = list(
RND_CATEGORY_TOOLS + RND_SUBCATEGORY_TOOLS_PKA_MODS,
)
build_type = PROTOLATHE
departmental_flags = DEPARTMENT_BITFLAG_CARGO
/datum/design/unique_modkit/offensive_turf_aoe
name = "Kinetic Accelerator Offensive Mining Explosion Mod"
desc = "A device which causes kinetic accelerators to fire AoE blasts that destroy rock and damage creatures."
id = "hyperaoemod"
materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT*3.5, /datum/material/glass = SHEET_MATERIAL_AMOUNT*1.5, /datum/material/silver =SHEET_MATERIAL_AMOUNT*1.5, /datum/material/gold =SHEET_MATERIAL_AMOUNT*1.5, /datum/material/diamond = SHEET_MATERIAL_AMOUNT*2)
build_path = /obj/item/borg/upgrade/modkit/aoe/turfs/andmobs
/datum/design/unique_modkit/rapid_repeater
name = "Kinetic Accelerator Rapid Repeater Mod"
desc = "A device which greatly reduces a kinetic accelerator's cooldown on striking a living target or rock, but greatly increases its base cooldown."
id = "repeatermod"
materials = list(/datum/material/iron =HALF_SHEET_MATERIAL_AMOUNT * 5, /datum/material/glass =SHEET_MATERIAL_AMOUNT * 2.5, /datum/material/uranium = SHEET_MATERIAL_AMOUNT*4, /datum/material/bluespace =SHEET_MATERIAL_AMOUNT)
build_path = /obj/item/borg/upgrade/modkit/cooldown/repeater
/datum/design/unique_modkit/resonator_blast
name = "Kinetic Accelerator Resonator Blast Mod"
desc = "A device which causes kinetic accelerators to fire shots that leave and detonate resonator blasts."
id = "resonatormod"
materials = list(/datum/material/iron =HALF_SHEET_MATERIAL_AMOUNT*5, /datum/material/glass =HALF_SHEET_MATERIAL_AMOUNT*5, /datum/material/silver =HALF_SHEET_MATERIAL_AMOUNT*5, /datum/material/uranium =SHEET_MATERIAL_AMOUNT * 2.5)
build_path = /obj/item/borg/upgrade/modkit/resonator_blasts
/datum/design/unique_modkit/bounty
name = "Kinetic Accelerator Death Syphon Mod"
desc = "A device which causes kinetic accelerators to permanently gain damage against creature types killed with it."
id = "bountymod"
materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT*2, /datum/material/silver = SHEET_MATERIAL_AMOUNT*2, /datum/material/gold = SHEET_MATERIAL_AMOUNT*2, /datum/material/bluespace = SHEET_MATERIAL_AMOUNT*2)
build_path = /obj/item/borg/upgrade/modkit/bounty
@@ -17,72 +17,6 @@
/obj/item/organ/vocal_cords/proc/handle_speech(message) //actually say the message
owner.say(message, spans = spans, sanitize = FALSE)
//Colossus drop, forces the listeners to obey certain commands
/obj/item/organ/vocal_cords/colossus
name = "divine vocal cords"
desc = "They carry the voice of an ancient god."
icon_state = "voice_of_god"
actions_types = list(/datum/action/item_action/organ_action/colossus)
var/next_command = 0
var/cooldown_mod = 1
var/base_multiplier = 1
spans = list("colossus","yell")
/datum/action/item_action/organ_action/colossus
name = "Voice of God"
var/obj/item/organ/vocal_cords/colossus/cords = null
/datum/action/item_action/organ_action/colossus/New()
..()
cords = target
/datum/action/item_action/organ_action/colossus/IsAvailable(feedback = FALSE)
if(!owner)
return FALSE
if(world.time < cords.next_command)
if (feedback)
owner.balloon_alert(owner, "wait [DisplayTimeText(cords.next_command - world.time)]!")
return FALSE
if(isliving(owner))
var/mob/living/living = owner
if(!living.can_speak())
if (feedback)
owner.balloon_alert(owner, "can't speak!")
return FALSE
if(check_flags & AB_CHECK_CONSCIOUS)
if(owner.stat)
if (feedback)
owner.balloon_alert(owner, "unconscious!")
return FALSE
return TRUE
/datum/action/item_action/organ_action/colossus/do_effect(trigger_flags)
var/command = tgui_input_text(owner, "Speak with the Voice of God", "Command", max_length = MAX_MESSAGE_LEN)
if(!command)
return FALSE
if(QDELETED(src) || QDELETED(owner))
return FALSE
owner.say(".x[command]")
return TRUE
/obj/item/organ/vocal_cords/colossus/can_speak_with()
if(!owner)
return FALSE
if(world.time < next_command)
to_chat(owner, span_notice("You must wait [DisplayTimeText(next_command - world.time)] before Speaking again."))
return FALSE
return owner.can_speak()
/obj/item/organ/vocal_cords/colossus/handle_speech(message)
playsound(get_turf(owner), 'sound/effects/magic/clockwork/invoke_general.ogg', 300, TRUE, 5)
return //voice of god speaks for us
/obj/item/organ/vocal_cords/colossus/speak_with(message)
var/cooldown = voice_of_god(uppertext(message), owner, spans, base_multiplier)
next_command = world.time + (cooldown * cooldown_mod)
/obj/item/organ/adamantine_resonator
name = "adamantine resonator"
desc = "Fragments of adamantine exist in all golems, stemming from their origins as purely magical constructs. These are used to \"hear\" messages from their leaders."
+16 -2
View File
@@ -4922,9 +4922,23 @@
#include "code\modules\mining\laborcamp\laborshuttle.dm"
#include "code\modules\mining\laborcamp\laborstacker.dm"
#include "code\modules\mining\lavaland\ash_flora.dm"
#include "code\modules\mining\lavaland\megafauna_loot.dm"
#include "code\modules\mining\lavaland\necropolis_chests.dm"
#include "code\modules\mining\lavaland\tendril_loot.dm"
#include "code\modules\mining\lavaland\mining_loot\berserker.dm"
#include "code\modules\mining\lavaland\mining_loot\clothing.dm"
#include "code\modules\mining\lavaland\mining_loot\consumables.dm"
#include "code\modules\mining\lavaland\mining_loot\cursed_katana.dm"
#include "code\modules\mining\lavaland\mining_loot\equipment.dm"
#include "code\modules\mining\lavaland\mining_loot\eye_of_god.dm"
#include "code\modules\mining\lavaland\mining_loot\godslayer.dm"
#include "code\modules\mining\lavaland\mining_loot\megafauna\ash_drake.dm"
#include "code\modules\mining\lavaland\mining_loot\megafauna\blood_drunk.dm"
#include "code\modules\mining\lavaland\mining_loot\megafauna\bubblegum.dm"
#include "code\modules\mining\lavaland\mining_loot\megafauna\colossus.dm"
#include "code\modules\mining\lavaland\mining_loot\megafauna\demonic_frost_miner.dm"
#include "code\modules\mining\lavaland\mining_loot\megafauna\hierophant.dm"
#include "code\modules\mining\lavaland\mining_loot\megafauna\legion.dm"
#include "code\modules\mining\lavaland\mining_loot\megafauna\the_thing.dm"
#include "code\modules\mining\lavaland\mining_loot\megafauna\wendigo.dm"
#include "code\modules\mob\emote.dm"
#include "code\modules\mob\inventory.dm"
#include "code\modules\mob\login.dm"