mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-13 16:13:19 +01:00
68fb77a19a
* WE HAVE LIFTOFF * Reinforced wall + fixes * (Reinforced) windows * Adds nameless plasmaglass sprites * Plasma windows * Unnamed cult walls * Add window edges back * Wooden walls * Plasma walls + THANK YOU CHAP * Oops * Wooden names * Cult walls * Plasma walls * Uranium walls * Golden walls * Silver walls * False wall basics * All false walls * Remove old walls * Fixes * First girders * Build steps * New floors and decalized floor tiles. * satisfy linter * Add command decals, remove old "blue tile" decal * update script number * have ATMs put their decals on last * add engineering decals * update spritesheets * lots of tile coloring fixes * more engi tile fixes * more tile fixes * linters * fixes conflict? * conflict fixes * fix layering issue * cult, necropolis, plastitanium, rocks, backrooms walls * survival pod walls, prepare for titanium, plastitanium fwall fix removes diagonal smoothing and the nodiagonal subtype from titanium walls as survival pod walls are a subtype of titanium * linters * linters again * linters number 1 million and counting * titanium walls * brass walls, floors, windows * titanium window, plastitanium window * brass window smooths with wood and brass walls * linters number 1 million and one * all walls smooth with airlocks in preparation for airlock sprites in a separate PR * now all walls smooth with airlocks * windows smooth with airlocks * separate wallbumps, partially add apc * tinted window * survival pod windows * oops i reverted apc.dm * mapping fixes * more mapping sprites * more mapping stuff, fix my ungodly smooth rocks * linters * apc fix * air alarm, apc, fire alarm offset preparations * fire alarm implementation + rock fixes + firelock smoothing * airlocks + supposed map fixes * engi/atmos airlocks + overlays * the rest of the doors lol * linters + freezer fix * fixes * shuttle airlock + misc fixes * firelocks * fix * oops * i need to stop pushing fixes early * shuttle airlock quickfix * external airlocks + hatches + fixes * centcom doors * highsec airlocks * vault airlock, double airlocks * yaya deconflictsies * lotsa fixes * light fixes + blastdoor fixes * firelock gap fix * light construction fix + rcd fix --------- Co-authored-by: DGamerL <108773801+DGamerL@users.noreply.github.com> Co-authored-by: DGamerL <daan.lyklema@gmail.com> Co-authored-by: Alexios <skillpointHD@Gmail.com> Co-authored-by: warriorstar-orion <orion@snowfrost.garden>
686 lines
26 KiB
Plaintext
686 lines
26 KiB
Plaintext
//////////////////////////////
|
|
// MARK: DEMONIC WHISPER
|
|
//////////////////////////////
|
|
/datum/action/innate/demon_whisper
|
|
name = "Demonic Whisper"
|
|
button_icon_state = "demon_comms"
|
|
background_icon_state = "bg_demon"
|
|
|
|
/datum/action/innate/demon_whisper/proc/choose_targets(mob/user = usr)
|
|
var/list/validtargets = list()
|
|
for(var/mob/living/M in view(user.client.maxview(), get_turf(user)))
|
|
if(M && M.mind && M.stat != DEAD)
|
|
if(M == user)
|
|
continue
|
|
|
|
validtargets += M
|
|
|
|
if(!length(validtargets))
|
|
to_chat(usr, SPAN_WARNING("There are no valid targets!"))
|
|
return
|
|
|
|
var/mob/living/target = tgui_input_list(user, "Choose the target to talk to", "Targeting", validtargets)
|
|
return target
|
|
|
|
/datum/action/innate/demon_whisper/Activate()
|
|
var/mob/living/choice = choose_targets()
|
|
if(!choice)
|
|
return
|
|
|
|
var/msg = tgui_input_text(usr, "What do you wish to tell [choice]?", null, "")
|
|
if(!msg)
|
|
return
|
|
log_say("(SLAUGHTER to [key_name(choice)]) [msg]", usr)
|
|
to_chat(usr, SPAN_NOTICE("<b>You whisper to [choice]: </b>[msg]"))
|
|
to_chat(choice, "[SPAN_DEADSAY("<b>Suddenly a strange, demonic voice resonates in your head... </b>")]<i>[SPAN_DANGER(" [msg]")]</i>")
|
|
for(var/mob/dead/observer/G in GLOB.player_list)
|
|
G.show_message("<i>Demonic message from <b>[usr]</b> ([ghost_follow_link(usr, ghost=G)]) to <b>[choice]</b> ([ghost_follow_link(choice, ghost=G)]): [msg]</i>")
|
|
|
|
//////////////////////////////
|
|
// MARK: CULT DEMON
|
|
//////////////////////////////
|
|
/datum/spell/sense_victims
|
|
name = "Sense Victims"
|
|
desc = "Sense the location of heretics."
|
|
base_cooldown = 0
|
|
clothes_req = FALSE
|
|
overlay = null
|
|
action_icon_state = "bloodcrawl"
|
|
action_background_icon_state = "bg_cult"
|
|
|
|
/datum/spell/sense_victims/create_new_targeting()
|
|
return new /datum/spell_targeting/alive_mob_list
|
|
|
|
/datum/spell/sense_victims/valid_target(mob/living/target, user)
|
|
return target.stat == CONSCIOUS && target.key && !IS_CULTIST(target) // Only conscious, non cultist players
|
|
|
|
/datum/spell/sense_victims/cast(list/targets, mob/user)
|
|
var/mob/living/victim = targets[1]
|
|
to_chat(victim, SPAN_USERDANGER("You feel an awful sense of being watched..."))
|
|
victim.Stun(6 SECONDS) //HUE
|
|
var/area/A = get_area(victim)
|
|
if(!A)
|
|
to_chat(user, SPAN_WARNING("You could not locate any sapient heretics for the Slaughter."))
|
|
return 0
|
|
to_chat(user, SPAN_DANGER("You sense a terrified soul at [A]. <b>Show [A.p_them()] the error of [A.p_their()] ways.</b>"))
|
|
|
|
//////////////////////////////
|
|
// MARK: SHADOW DEMON
|
|
//////////////////////////////
|
|
/datum/spell/fireball/shadow_grapple
|
|
name = "Shadow Grapple"
|
|
desc = "Fire one of your hands, if it hits a person it pulls them in. If you hit a structure you get pulled to the structure. Any light source hit with this will be disabled in a two tile radius."
|
|
base_cooldown = 10 SECONDS
|
|
fireball_type = /obj/projectile/magic/shadow_hand
|
|
|
|
selection_activated_message = SPAN_NOTICE("You raise your hand, full of demonic energy! <b>Left-click to cast at a target!</b>")
|
|
selection_deactivated_message = SPAN_NOTICE("You re-absorb the energy...for now.")
|
|
|
|
action_background_icon_state = "shadow_demon_bg"
|
|
action_icon_state = "shadow_grapple"
|
|
sound = null
|
|
invocation_type = "none"
|
|
invocation = null
|
|
|
|
/datum/spell/fireball/shadow_grapple/update_spell_icon()
|
|
return
|
|
|
|
/obj/projectile/magic/shadow_hand
|
|
name = "shadow hand"
|
|
icon_state = "shadow_hand"
|
|
plane = FLOOR_PLANE
|
|
hitsound = 'sound/shadowdemon/shadowattack1.ogg' // Plays when hitting something living or a light
|
|
var/hit = FALSE
|
|
|
|
/obj/projectile/magic/shadow_hand/pixel_move(trajectory_multiplier, hitscanning)
|
|
. = ..()
|
|
var/obj/machinery/light/floor/floor_light = locate(/obj/machinery/light/floor) in get_turf(src)
|
|
if(floor_light)
|
|
Bump(floor_light)
|
|
|
|
/obj/projectile/magic/shadow_hand/fire(setAngle)
|
|
if(firer)
|
|
var/mob/living/basic/demon/shadow/current_demon = firer
|
|
if(istype(current_demon))
|
|
current_demon.block_shadow_crawl()
|
|
firer.Beam(src, icon_state = "grabber_beam", time = INFINITY, maxdistance = INFINITY, beam_type = /obj/effect/ebeam/floor)
|
|
return ..()
|
|
|
|
/obj/projectile/magic/shadow_hand/on_hit(atom/target, blocked, hit_zone)
|
|
if(hit)
|
|
return
|
|
hit = TRUE // to prevent double hits from the pull
|
|
. = ..()
|
|
for(var/atom/extinguish_target in range(2, src))
|
|
extinguish_target.extinguish_light(TRUE)
|
|
if(!isliving(target))
|
|
if(isshadowdemon(firer))
|
|
firer.throw_at(get_step(target, get_dir(target, firer)), 50, 10, callback = CALLBACK(firer, TYPE_PROC_REF(/mob/living/basic/demon/shadow, unblock_shadow_crawl)))
|
|
else
|
|
firer.throw_at(get_step(target, get_dir(target, firer)), 50, 10)
|
|
else
|
|
unblock_shadowdemon_crawl()
|
|
if(!.)
|
|
return
|
|
else
|
|
var/mob/living/L = target
|
|
L.Immobilize(2 SECONDS)
|
|
L.apply_damage(40, BRUTE, BODY_ZONE_CHEST)
|
|
L.throw_at(get_step(firer, get_dir(firer, target)), 50, 10)
|
|
|
|
/obj/projectile/magic/shadow_hand/Destroy()
|
|
if(!hit)
|
|
unblock_shadowdemon_crawl()
|
|
return ..()
|
|
|
|
/obj/projectile/magic/shadow_hand/proc/unblock_shadowdemon_crawl()
|
|
var/mob/living/basic/demon/shadow/current_demon = firer
|
|
if(istype(current_demon))
|
|
current_demon.unblock_shadow_crawl()
|
|
|
|
/obj/effect/ebeam/floor
|
|
plane = FLOOR_PLANE
|
|
|
|
//////////////////////////////
|
|
// MARK: PULSE DEMON
|
|
//////////////////////////////
|
|
#define PULSEDEMON_REMOTE_DRAIN_MULTIPLIER 5
|
|
|
|
#define PD_UPGRADE_HIJACK_SPEED "Speed"
|
|
#define PD_UPGRADE_DRAIN_SPEED "Absorption"
|
|
#define PD_UPGRADE_HEALTH_LOSS "Endurance"
|
|
#define PD_UPGRADE_HEALTH_REGEN "Recovery"
|
|
#define PD_UPGRADE_MAX_HEALTH "Strength"
|
|
#define PD_UPGRADE_HEALTH_COST "Efficiency"
|
|
#define PD_UPGRADE_MAX_CHARGE "Capacity"
|
|
|
|
/datum/spell/pulse_demon
|
|
clothes_req = FALSE
|
|
antimagic_flags = NONE
|
|
action_background_icon_state = "bg_pulsedemon"
|
|
var/locked = TRUE
|
|
var/unlock_cost = 1
|
|
var/cast_cost = 1 KJ
|
|
var/upgrade_cost = 1
|
|
var/requires_area = FALSE
|
|
var/revealing = FALSE
|
|
var/reveal_time = 10 SECONDS
|
|
base_cooldown = 20 SECONDS
|
|
|
|
/datum/spell/pulse_demon/New()
|
|
. = ..()
|
|
update_info()
|
|
|
|
/datum/spell/pulse_demon/proc/update_info()
|
|
if(locked)
|
|
name = "[initial(name)] (Locked) ([format_si_suffix(unlock_cost)] APC\s)"
|
|
desc = "[initial(desc)] It costs [format_si_suffix(unlock_cost)] APC\s to unlock. <b>Alt-Click</b> this spell to unlock it."
|
|
else
|
|
name = "[initial(name)][cast_cost == 0 ? "" : " ([format_si_suffix(cast_cost)]W)"]"
|
|
desc = "[initial(desc)][spell_level == level_max ? "" : " It costs [format_si_suffix(upgrade_cost)] APC\s to upgrade. <b>Alt-Click</b> this spell to upgrade it."]"
|
|
action.name = name
|
|
action.desc = desc
|
|
action.build_all_button_icons()
|
|
|
|
/datum/spell/pulse_demon/can_cast(mob/living/basic/demon/pulse_demon/user, charge_check, show_message)
|
|
if(!..())
|
|
return FALSE
|
|
if(!istype(user))
|
|
return FALSE
|
|
if(locked)
|
|
if(show_message)
|
|
to_chat(user, SPAN_WARNING("This ability is locked! Alt-click the button to purchase this ability."))
|
|
to_chat(user, SPAN_NOTICE("It costs [format_si_suffix(unlock_cost)] APC\s to unlock."))
|
|
return FALSE
|
|
if(user.charge < cast_cost)
|
|
if(show_message)
|
|
to_chat(user, SPAN_WARNING("You do not have enough charge to use this ability!"))
|
|
to_chat(user, SPAN_NOTICE("It costs [format_si_suffix(cast_cost)]W to use."))
|
|
return FALSE
|
|
if(requires_area && !user.controlling_area)
|
|
if(show_message)
|
|
to_chat(user, SPAN_WARNING("You need to be controlling an area to use this ability!"))
|
|
return FALSE
|
|
return TRUE
|
|
|
|
/datum/spell/pulse_demon/cast(list/targets, mob/living/basic/demon/pulse_demon/user)
|
|
if(!istype(user) || locked || user.charge < cast_cost || !length(targets))
|
|
return FALSE
|
|
if(requires_area && !user.controlling_area)
|
|
return FALSE
|
|
if(requires_area && user.controlling_area != get_area(targets[1]))
|
|
to_chat(user, SPAN_WARNING("You can only use this ability in your controlled area!"))
|
|
return FALSE
|
|
if(try_cast_action(user, targets[1]))
|
|
user.adjust_charge(-cast_cost)
|
|
if(revealing)
|
|
INVOKE_ASYNC(src, PROC_REF(reveal_demon), user, reveal_time)
|
|
return TRUE
|
|
else
|
|
revert_cast(user)
|
|
return FALSE
|
|
|
|
/datum/spell/pulse_demon/create_new_targeting()
|
|
return new /datum/spell_targeting/clicked_atom
|
|
|
|
/datum/spell/pulse_demon/proc/try_cast_action(mob/living/basic/demon/pulse_demon/user, atom/target)
|
|
return FALSE
|
|
|
|
/datum/spell/pulse_demon/proc/reveal_demon(mob/user, reveal_time)
|
|
user.layer = ABOVE_NORMAL_TURF_LAYER
|
|
do_sparks(rand(2, 4), FALSE, user)
|
|
sleep(reveal_time)
|
|
user.layer = ABOVE_PLATING_LAYER
|
|
|
|
// handles purchasing and upgrading abilities
|
|
/datum/spell/pulse_demon/AltClick(mob/living/basic/demon/pulse_demon/user)
|
|
if(!istype(user))
|
|
return
|
|
|
|
if(locked)
|
|
if(user.apcs_remaining >= unlock_cost)
|
|
user.apcs_remaining -= unlock_cost
|
|
locked = FALSE
|
|
to_chat(user, SPAN_NOTICE("You have unlocked [initial(name)]!"))
|
|
|
|
if(cast_cost > 0)
|
|
to_chat(user, SPAN_NOTICE("It costs [format_si_suffix(cast_cost)]W to use once."))
|
|
if(level_max > 0 && spell_level < level_max)
|
|
to_chat(user, SPAN_NOTICE("It will cost [format_si_suffix(upgrade_cost)] APC\s to upgrade."))
|
|
|
|
update_info()
|
|
else
|
|
to_chat(user, SPAN_WARNING("You cannot afford this ability! It costs [format_si_suffix(unlock_cost)] APC\s to unlock."))
|
|
else
|
|
if(spell_level >= level_max)
|
|
to_chat(user, SPAN_WARNING("You have already fully upgraded this ability!"))
|
|
else if(user.apcs_remaining >= upgrade_cost)
|
|
user.apcs_remaining -= upgrade_cost
|
|
spell_level = min(spell_level + 1, level_max)
|
|
do_upgrade(user)
|
|
|
|
if(spell_level == level_max)
|
|
to_chat(user, SPAN_NOTICE("You have fully upgraded [initial(name)]!"))
|
|
else
|
|
to_chat(user, SPAN_NOTICE("The next upgrade will cost [format_si_suffix(upgrade_cost)] APC\s to unlock."))
|
|
|
|
update_info()
|
|
else
|
|
to_chat(user, SPAN_WARNING("You cannot afford to upgrade this ability! It costs [format_si_suffix(upgrade_cost)] APC\s to upgrade."))
|
|
|
|
/datum/spell/pulse_demon/proc/do_upgrade(mob/living/basic/demon/pulse_demon/user)
|
|
cooldown_handler.recharge_duration = round(base_cooldown / (1.5 ** spell_level))
|
|
to_chat(user, SPAN_NOTICE("You have upgraded [initial(name)] to level [spell_level + 1], it now takes [cooldown_handler.recharge_duration / 10] seconds to recharge."))
|
|
|
|
/datum/spell/pulse_demon/cablehop
|
|
name = "Cable Hop"
|
|
desc = "Jump to another cable in view."
|
|
action_icon_state = "pd_cablehop"
|
|
unlock_cost = 4
|
|
cast_cost = 200 KJ
|
|
upgrade_cost = 2
|
|
revealing = TRUE
|
|
reveal_time = 5 SECONDS
|
|
|
|
/datum/spell/pulse_demon/cablehop/try_cast_action(mob/living/basic/demon/pulse_demon/user, atom/target)
|
|
var/turf/O = get_turf(user)
|
|
var/turf/T = get_turf(target)
|
|
var/obj/structure/cable/C = locate(/obj/structure/cable) in T
|
|
if(!istype(C))
|
|
to_chat(user, SPAN_WARNING("No cable found!"))
|
|
return FALSE
|
|
if(get_dist(O, T) > 15) //Some extra range to account for them possessing machines away from their APC, but blocking demons from using a camera console to zap across the station.
|
|
to_chat(user, SPAN_WARNING("That cable is too far away!"))
|
|
return FALSE
|
|
playsound(T, 'sound/magic/lightningshock.ogg', 50, TRUE)
|
|
O.Beam(target, icon_state = "lightning[rand(1, 12)]", icon = 'icons/effects/effects.dmi', time = 1 SECONDS)
|
|
for(var/turf/working in get_line(O, T))
|
|
for(var/mob/living/L in working)
|
|
if(!electrocute_mob(L, C.powernet, user)) // give a little bit of non-lethal counterplay against insuls
|
|
L.Jitter(5 SECONDS)
|
|
L.apply_status_effect(STATUS_EFFECT_DELAYED, 1 SECONDS, CALLBACK(L, TYPE_PROC_REF(/mob/living, KnockDown), 5 SECONDS), COMSIG_LIVING_CLEAR_STUNS)
|
|
user.forceMove(T)
|
|
user.Move(T)
|
|
return TRUE
|
|
|
|
/datum/spell/pulse_demon/emagtamper
|
|
name = "Electromagnetic Tamper"
|
|
desc = "Unlocks hidden programming in machines. Must be inside a hijacked APC to use."
|
|
action_icon_state = "pd_emag"
|
|
unlock_cost = 4
|
|
cast_cost = 200 KJ
|
|
upgrade_cost = 2
|
|
requires_area = TRUE
|
|
revealing = TRUE
|
|
|
|
/datum/spell/pulse_demon/emagtamper/try_cast_action(mob/living/basic/demon/pulse_demon/user, atom/target)
|
|
to_chat(user, SPAN_WARNING("You attempt to tamper with [target]!"))
|
|
target.emag_act(user)
|
|
return TRUE
|
|
|
|
/datum/spell/pulse_demon/emp
|
|
name = "Electromagnetic Pulse"
|
|
desc = "Creates an EMP where you click. Be careful not to use it on yourself!"
|
|
action_icon_state = "pd_emp"
|
|
unlock_cost = 4
|
|
cast_cost = 500 KJ
|
|
upgrade_cost = 2
|
|
requires_area = TRUE
|
|
revealing = TRUE
|
|
|
|
/datum/spell/pulse_demon/emp/try_cast_action(mob/living/basic/demon/pulse_demon/user, atom/target)
|
|
to_chat(user, SPAN_WARNING("You attempt to EMP [target]!"))
|
|
empulse(get_turf(target), 1, 1)
|
|
return TRUE
|
|
|
|
/datum/spell/pulse_demon/overload
|
|
name = "Overload Machine"
|
|
desc = "Overloads a machine, causing it to explode. Becomes powerful enough to breach when fully upgraded."
|
|
action_icon_state = "pd_overload"
|
|
unlock_cost = 8
|
|
cast_cost = 1000 KJ
|
|
upgrade_cost = 4
|
|
requires_area = TRUE
|
|
revealing = TRUE
|
|
base_cooldown = 60 SECONDS
|
|
reveal_time = 20 SECONDS
|
|
|
|
/datum/spell/pulse_demon/overload/try_cast_action(mob/living/basic/demon/pulse_demon/user, atom/target)
|
|
var/obj/machinery/M = target
|
|
if(!istype(M))
|
|
to_chat(user, SPAN_WARNING("That is not a machine."))
|
|
return FALSE
|
|
if(target.flags_2 & NO_MALF_EFFECT_2)
|
|
to_chat(user, SPAN_WARNING("That machine cannot be overloaded."))
|
|
return FALSE
|
|
target.audible_message(SPAN_ITALICS("You hear a loud electrical buzzing sound coming from [target]!"))
|
|
addtimer(CALLBACK(src, PROC_REF(detonate), user, M), 5 SECONDS)
|
|
return TRUE
|
|
|
|
/datum/spell/pulse_demon/overload/proc/detonate(mob/living/basic/demon/pulse_demon/user, obj/machinery/target)
|
|
if(!QDELETED(target))
|
|
if(spell_level == level_max)
|
|
explosion(get_turf(target), 0, 1, 2, 2, cause = "Pulse Demon: [name]")
|
|
else
|
|
explosion(get_turf(target), 0, 0, 2, 2, cause = "Pulse Demon: [name]")
|
|
if(!QDELETED(target))
|
|
qdel(target)
|
|
|
|
/datum/spell/pulse_demon/remotehijack
|
|
name = "Remote Hijack"
|
|
desc = "Remotely hijacks an APC."
|
|
action_icon_state = "pd_remotehack"
|
|
unlock_cost = 2
|
|
cast_cost = 200 KJ
|
|
level_max = 0
|
|
base_cooldown = 3 SECONDS // you have to wait for the regular hijack time anyway
|
|
|
|
/datum/spell/pulse_demon/remotehijack/try_cast_action(mob/living/basic/demon/pulse_demon/user, atom/target)
|
|
var/obj/machinery/power/apc/A = target
|
|
if(!istype(A))
|
|
to_chat(user, SPAN_WARNING("That is not an APC."))
|
|
return FALSE
|
|
if(!user.try_hijack_apc(A, TRUE))
|
|
to_chat(user, SPAN_WARNING("You cannot hijack that APC right now!"))
|
|
return TRUE
|
|
|
|
/datum/spell/pulse_demon/remotedrain
|
|
name = "Remote Drain"
|
|
desc = "Remotely drains a power source."
|
|
action_icon_state = "pd_remotedrain"
|
|
unlock_cost = 2
|
|
cast_cost = 50 KJ
|
|
upgrade_cost = 2
|
|
|
|
/datum/spell/pulse_demon/remotedrain/try_cast_action(mob/living/basic/demon/pulse_demon/user, atom/target)
|
|
if(isapc(target))
|
|
var/drained = user.drain_APC(target, PULSEDEMON_REMOTE_DRAIN_MULTIPLIER)
|
|
if(drained == PULSEDEMON_SOURCE_DRAIN_INVALID)
|
|
to_chat(user, SPAN_WARNING("This APC is being hijacked, you cannot drain from it right now."))
|
|
else
|
|
to_chat(user, SPAN_NOTICE("You drain [format_si_suffix(drained)]W from [target]."))
|
|
else if(istype(target, /obj/machinery/power/smes))
|
|
var/drained = user.drain_SMES(target, PULSEDEMON_REMOTE_DRAIN_MULTIPLIER)
|
|
to_chat(user, SPAN_NOTICE("You drain [format_si_suffix(drained)]W from [target]."))
|
|
else
|
|
to_chat(user, SPAN_WARNING("That is not a valid source."))
|
|
return FALSE
|
|
return TRUE
|
|
|
|
/datum/spell/pulse_demon/toggle
|
|
base_cooldown = 0
|
|
cast_cost = 0
|
|
create_attack_logs = FALSE
|
|
var/base_message = "see messages you shouldn't!"
|
|
|
|
/datum/spell/pulse_demon/toggle/New(initstate = FALSE)
|
|
. = ..()
|
|
do_toggle(initstate, null)
|
|
|
|
/datum/spell/pulse_demon/toggle/create_new_targeting()
|
|
return new /datum/spell_targeting/self
|
|
|
|
/datum/spell/pulse_demon/toggle/proc/do_toggle(varstate, mob/user)
|
|
if(action)
|
|
action.background_icon_state = varstate ? action_background_icon_state : "[action_background_icon_state]_disabled"
|
|
action.build_all_button_icons()
|
|
if(user)
|
|
to_chat(user, SPAN_NOTICE("You will [varstate ? "now" : "no longer"] [base_message]"))
|
|
return varstate
|
|
|
|
/datum/spell/pulse_demon/toggle/do_drain
|
|
name = "Toggle Draining"
|
|
desc = "Toggle whether you drain charge from power sources."
|
|
base_message = "drain charge from power sources."
|
|
action_icon_state = "pd_toggle_steal"
|
|
locked = FALSE
|
|
level_max = 0
|
|
|
|
/datum/spell/pulse_demon/toggle/do_drain/try_cast_action(mob/living/basic/demon/pulse_demon/user, atom/target)
|
|
user.do_drain = do_toggle(!user.do_drain, user)
|
|
return TRUE
|
|
|
|
/datum/spell/pulse_demon/toggle/do_drain/AltClick(mob/living/basic/demon/pulse_demon/user)
|
|
if(!istype(user))
|
|
return
|
|
|
|
var/amount = text2num(input(user, "Input a value between 1 and [user.max_drain_rate]. 0 will reset it to the maximum.", "Drain Speed Setting"))
|
|
if(amount == null || amount < 0)
|
|
to_chat(user, SPAN_WARNING("Invalid input. Drain speed has not been modified."))
|
|
return
|
|
|
|
if(amount == 0)
|
|
amount = user.max_drain_rate
|
|
user.power_drain_rate = amount
|
|
to_chat(user, SPAN_NOTICE("Drain speed has been set to [format_si_suffix(user.power_drain_rate)]W per second."))
|
|
|
|
/datum/spell/pulse_demon/toggle/can_exit_cable
|
|
name = "Toggle Self-Sustaining"
|
|
desc = "Toggle whether you can move outside of cables or power sources."
|
|
base_message = "move outside of cables."
|
|
action_icon_state = "pd_toggle_exit"
|
|
upgrade_cost = 2
|
|
level_max = 3
|
|
locked = FALSE
|
|
|
|
/datum/spell/pulse_demon/toggle/can_exit_cable/try_cast_action(mob/living/basic/demon/pulse_demon/user, atom/target)
|
|
if(user.can_exit_cable && !(user.current_cable || user.current_power))
|
|
to_chat(user, SPAN_WARNING("Enter a cable or power source first!"))
|
|
return FALSE
|
|
user.can_exit_cable = do_toggle(!user.can_exit_cable, user)
|
|
return TRUE
|
|
|
|
/datum/spell/pulse_demon/toggle/can_exit_cable/do_upgrade(mob/living/basic/demon/pulse_demon/user)
|
|
user.outside_cable_speed = max(initial(user.outside_cable_speed) - spell_level, 1)
|
|
to_chat(user, SPAN_NOTICE("You have upgraded [initial(name)] to level [spell_level + 1], you will now move faster outside of cables."))
|
|
|
|
/datum/spell/pulse_demon/cycle_camera
|
|
name = "Cycle Camera View"
|
|
desc = "Jump between the cameras in your APC's area. Alt-click to return to the APC."
|
|
action_icon_state = "pd_camera_view"
|
|
create_attack_logs = FALSE
|
|
locked = FALSE
|
|
cast_cost = 0
|
|
level_max = 0
|
|
base_cooldown = 0
|
|
requires_area = TRUE
|
|
var/current_camera = 0
|
|
|
|
/datum/spell/pulse_demon/cycle_camera/create_new_targeting()
|
|
return new /datum/spell_targeting/self
|
|
|
|
/datum/spell/pulse_demon/cycle_camera/AltClick(mob/living/basic/demon/pulse_demon/user)
|
|
if(!istype(user))
|
|
return
|
|
current_camera = 0
|
|
|
|
if(!isapc(user.current_power))
|
|
return
|
|
if(get_area(user.loc) != user.controlling_area)
|
|
return
|
|
user.forceMove(user.current_power)
|
|
|
|
/datum/spell/pulse_demon/cycle_camera/try_cast_action(mob/living/basic/demon/pulse_demon/user, atom/target)
|
|
if(!length(user.controlling_area.cameras))
|
|
return FALSE
|
|
|
|
if(isapc(user.loc))
|
|
current_camera = 0
|
|
else if(istype(user.loc, /obj/machinery/camera))
|
|
current_camera = (current_camera + 1) % length(user.controlling_area.cameras)
|
|
if(current_camera == 0)
|
|
user.forceMove(user.current_power)
|
|
return TRUE
|
|
|
|
if(length(user.controlling_area.cameras) < current_camera)
|
|
current_camera = 0
|
|
|
|
user.forceMove(locateUID(user.controlling_area.cameras[current_camera + 1]))
|
|
return TRUE
|
|
|
|
/datum/spell/pulse_demon/toggle/penetrating_shock
|
|
name = "Toggle Intense Shocks"
|
|
desc = "Toggle whether to use 200 KJ of energy to bypass electric-resistant victims immunity when attacking."
|
|
base_message = "use strong shocks when attacking."
|
|
action_icon_state = "pd_strong_shocks"
|
|
unlock_cost = 4
|
|
level_max = 0
|
|
|
|
/datum/spell/pulse_demon/toggle/penetrating_shock/create_new_targeting()
|
|
return new /datum/spell_targeting/self
|
|
|
|
/datum/spell/pulse_demon/toggle/penetrating_shock/try_cast_action(mob/living/basic/demon/pulse_demon/user, atom/target)
|
|
user.strong_shocks = do_toggle(!user.strong_shocks, user)
|
|
|
|
/datum/spell/pulse_demon/open_upgrades
|
|
name = "Open Upgrade Menu"
|
|
desc = "Open the upgrades menu. Alt-click for descriptions and costs."
|
|
action_icon_state = "pd_upgrade"
|
|
create_attack_logs = FALSE
|
|
locked = FALSE
|
|
cast_cost = 0
|
|
level_max = 0
|
|
base_cooldown = 0
|
|
var/static/list/upgrade_icons = list(
|
|
PD_UPGRADE_HIJACK_SPEED = image(icon = 'icons/obj/wallbumps/apc.dmi', icon_state = "apcemag"),
|
|
PD_UPGRADE_DRAIN_SPEED = image(icon = 'icons/obj/power.dmi', icon_state = "ccharger"),
|
|
PD_UPGRADE_MAX_HEALTH = image(icon = 'icons/obj/stock_parts.dmi', icon_state = "bluespace_matter_bin"),
|
|
PD_UPGRADE_HEALTH_REGEN = image(icon = 'icons/obj/stock_parts.dmi', icon_state = "femto_mani"),
|
|
PD_UPGRADE_HEALTH_LOSS = image(icon = 'icons/obj/stock_parts.dmi', icon_state = "triphasic_scan_module"),
|
|
PD_UPGRADE_HEALTH_COST = image(icon = 'icons/obj/stock_parts.dmi', icon_state = "quadultra_micro_laser"),
|
|
PD_UPGRADE_MAX_CHARGE = image(icon = 'icons/obj/stock_parts.dmi', icon_state = "quadratic_capacitor")
|
|
)
|
|
var/static/list/upgrade_descs = list(
|
|
PD_UPGRADE_HIJACK_SPEED = "Decrease the amount of time required to hijack an APC.",
|
|
PD_UPGRADE_DRAIN_SPEED = "Increase the amount of charge drained from a power source per cycle.",
|
|
PD_UPGRADE_MAX_HEALTH = "Increase the total amount of health you can have at once.",
|
|
PD_UPGRADE_HEALTH_REGEN = "Increase the amount of health regenerated when powered per cycle.",
|
|
PD_UPGRADE_HEALTH_LOSS = "Decrease the amount of health lost when unpowered per cycle.",
|
|
PD_UPGRADE_HEALTH_COST = "Decrease the amount of power required to regenerate per cycle.",
|
|
PD_UPGRADE_MAX_CHARGE = "Increase the total amount of charge you can have at once."
|
|
)
|
|
|
|
/datum/spell/pulse_demon/open_upgrades/create_new_targeting()
|
|
return new /datum/spell_targeting/self
|
|
|
|
/datum/spell/pulse_demon/open_upgrades/proc/calc_cost(mob/living/basic/demon/pulse_demon/user, upgrade)
|
|
var/cost
|
|
switch(upgrade)
|
|
if(PD_UPGRADE_HIJACK_SPEED)
|
|
if(user.hijack_time <= 6 SECONDS)
|
|
return -1
|
|
if(user.hijack_time > 12 SECONDS)
|
|
cost = 1
|
|
else
|
|
cost = 2
|
|
if(PD_UPGRADE_DRAIN_SPEED)
|
|
if(user.max_drain_rate >= 500 KJ)
|
|
return -1
|
|
cost = 1
|
|
if(PD_UPGRADE_MAX_HEALTH)
|
|
if(user.maxHealth >= 200)
|
|
return -1
|
|
if(user.maxHealth <= 100)
|
|
cost = 1
|
|
else
|
|
cost = 2
|
|
if(PD_UPGRADE_HEALTH_REGEN)
|
|
if(user.health_regen_rate >= 10)
|
|
return -1
|
|
cost = 1
|
|
if(PD_UPGRADE_HEALTH_LOSS)
|
|
if(user.health_loss_rate <= 0)
|
|
return -1
|
|
if(user.health_loss_rate >= 3)
|
|
cost = 1
|
|
else
|
|
cost = 2
|
|
if(PD_UPGRADE_HEALTH_COST)
|
|
if(user.power_per_regen <= 1 KJ)
|
|
return -1
|
|
cost = 1
|
|
if(PD_UPGRADE_MAX_CHARGE)
|
|
cost = 1
|
|
else
|
|
return -1
|
|
return cost
|
|
|
|
/datum/spell/pulse_demon/open_upgrades/proc/get_upgrades(mob/living/basic/demon/pulse_demon/user)
|
|
var/upgrades = list()
|
|
for(var/upgrade in upgrade_icons)
|
|
var/cost = calc_cost(user, upgrade)
|
|
if(cost == -1)
|
|
continue
|
|
upgrades["[upgrade] ([format_si_suffix(cost)] APC\s)"] = upgrade_icons[upgrade]
|
|
return upgrades
|
|
|
|
/datum/spell/pulse_demon/open_upgrades/AltClick(mob/living/basic/demon/pulse_demon/user)
|
|
if(!istype(user))
|
|
return
|
|
|
|
to_chat(user, "<b>Pulse Demon upgrades:</b>")
|
|
for(var/upgrade in upgrade_descs)
|
|
var/cost = calc_cost(user, upgrade)
|
|
to_chat(user, "<b>[upgrade]</b> ([cost == -1 ? "Fully Upgraded" : "[format_si_suffix(cost)]J"]) - [upgrade_descs[upgrade]]")
|
|
|
|
/datum/spell/pulse_demon/open_upgrades/try_cast_action(mob/living/basic/demon/pulse_demon/user, atom/target)
|
|
var/upgrades = get_upgrades(user)
|
|
if(!length(upgrades))
|
|
to_chat(user, SPAN_WARNING("You have already fully upgraded everything available!"))
|
|
return FALSE
|
|
|
|
var/raw_choice = show_radial_menu(user, user, upgrades, radius = 48)
|
|
if(!raw_choice)
|
|
return
|
|
var/choice = splittext(raw_choice, " ")[1]
|
|
|
|
var/cost = calc_cost(user, choice)
|
|
if(cost == -1)
|
|
return FALSE
|
|
if(user.apcs_remaining < cost)
|
|
to_chat(user, SPAN_WARNING("You do not have enough unused APCs to purchase this upgrade!"))
|
|
return FALSE
|
|
|
|
user.apcs_remaining -= cost
|
|
switch(choice)
|
|
if(PD_UPGRADE_HIJACK_SPEED)
|
|
user.hijack_time = max(round(user.hijack_time - 3 SECONDS), 6 SECONDS)
|
|
to_chat(user, SPAN_NOTICE("You have upgraded your [choice], it now takes [user.hijack_time / (1 SECONDS)] second\s to hijack APCs."))
|
|
if(PD_UPGRADE_DRAIN_SPEED)
|
|
var/old = user.max_drain_rate
|
|
user.max_drain_rate = user.max_drain_rate + 20 KJ
|
|
if(user.power_drain_rate == old)
|
|
user.power_drain_rate = user.max_drain_rate
|
|
to_chat(user, SPAN_NOTICE("You have upgraded your [choice], you can now drain [format_si_suffix(user.max_drain_rate)]W."))
|
|
if(PD_UPGRADE_MAX_HEALTH)
|
|
user.maxHealth = min(round(user.maxHealth * 1.5), 200)
|
|
to_chat(user, SPAN_NOTICE("You have upgraded your [choice], your max health is now [user.maxHealth]."))
|
|
if(PD_UPGRADE_HEALTH_REGEN)
|
|
user.health_regen_rate = min(round(user.health_regen_rate + 2), 10)
|
|
to_chat(user, SPAN_NOTICE("You have upgraded your [choice], you will now regenerate [user.health_regen_rate] health per cycle when powered."))
|
|
if(PD_UPGRADE_HEALTH_LOSS)
|
|
user.health_loss_rate = max(round(user.health_loss_rate - 1), 0)
|
|
if(user.health_loss_rate == 0)
|
|
to_chat(user, SPAN_NOTICE("You have upgraded your [choice], You will no longer lose health when on an unpowered cable."))
|
|
else
|
|
to_chat(user, SPAN_NOTICE("You have upgraded your [choice], you will now lose [user.health_loss_rate] health per cycle when unpowered."))
|
|
if(PD_UPGRADE_HEALTH_COST)
|
|
user.power_per_regen = max(round(user.power_per_regen / 1.5), 1)
|
|
to_chat(user, SPAN_NOTICE("You have upgraded your [choice], it now takes [format_si_suffix(user.power_per_regen)]W of power to regenerate health."))
|
|
to_chat(user, SPAN_NOTICE("Additionally, if you enable draining while on a cable, any excess power that would've been used regenerating will be added to your charge."))
|
|
if(PD_UPGRADE_MAX_CHARGE)
|
|
user.maxcharge = user.maxcharge + 50 KJ
|
|
to_chat(user, SPAN_NOTICE("You have upgraded your [choice], you can now store [format_si_suffix(user.maxcharge)]J of energy."))
|
|
else
|
|
return FALSE
|
|
return TRUE
|
|
|
|
#undef PULSEDEMON_REMOTE_DRAIN_MULTIPLIER
|
|
#undef PD_UPGRADE_HIJACK_SPEED
|
|
#undef PD_UPGRADE_DRAIN_SPEED
|
|
#undef PD_UPGRADE_HEALTH_LOSS
|
|
#undef PD_UPGRADE_HEALTH_REGEN
|
|
#undef PD_UPGRADE_MAX_HEALTH
|
|
#undef PD_UPGRADE_HEALTH_COST
|
|
#undef PD_UPGRADE_MAX_CHARGE
|