mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-26 05:27:01 +01:00
Pulse Demon Rework (#28731)
* first pass * almost there * done! * tweaks * de-linting? * Update code/game/gamemodes/miniantags/pulsedemon/pulsedemon_abilities.dm Co-authored-by: 1080pCat <96908085+1080pCat@users.noreply.github.com> Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com> * tweaks * tweak * wizard enhancement * fix --------- Signed-off-by: Kyani <65205627+EmeraldCandy@users.noreply.github.com> Co-authored-by: 1080pCat <96908085+1080pCat@users.noreply.github.com>
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
// original implementation: https://ss13.moe/wiki/index.php/Pulse_Demon
|
||||
|
||||
|
||||
|
||||
#define PULSEDEMON_PLATING_SPARK_CHANCE 20
|
||||
#define PULSEDEMON_APC_CHARGE_MULTIPLIER 2
|
||||
#define PULSEDEMON_SMES_DRAIN_MULTIPLIER 10
|
||||
@@ -14,7 +16,7 @@
|
||||
gender = NEUTER
|
||||
speak_chance = 20
|
||||
|
||||
damage_coeff = list(BRUTE = 0, BURN = 0.5, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0) // Pulse demons take damage from nothing except some from lasers
|
||||
damage_coeff = list(BRUTE = 0.25, BURN = 0.5, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0) // Pulse demons take reduced damage from most sources. Use ions
|
||||
|
||||
emote_hear = list("vibrates", "sizzles")
|
||||
speak_emote = list("modulates")
|
||||
@@ -33,7 +35,7 @@
|
||||
|
||||
maxHealth = 50
|
||||
health = 50
|
||||
speed = -0.5
|
||||
speed = -0.3
|
||||
mob_size = MOB_SIZE_TINY
|
||||
density = FALSE
|
||||
del_on_death = TRUE
|
||||
@@ -58,24 +60,24 @@
|
||||
var/list/hurt_sounds = list("sound/voice/pdwail1.ogg", "sound/voice/pdwail2.ogg", "sound/voice/pdwail3.ogg")
|
||||
|
||||
/// Current quantity of energy the demon currently holds (Joules), spent while purchasing, upgrading or using spells or upgrades. Use adjust_charge to modify this.
|
||||
var/charge = 1000
|
||||
var/charge = 100 KJ
|
||||
/// Maximum quantity of energy the demon can hold at once (Joules).
|
||||
var/maxcharge = 1000
|
||||
var/maxcharge = 100 KJ
|
||||
/// Book keeping for objective win conditions (Joules).
|
||||
var/charge_drained = 0
|
||||
/// Controls whether the demon will drain power from sources. Toggled by a spell.
|
||||
var/do_drain = TRUE
|
||||
/// Amount of power (Watts) to drain from power sources every Life tick.
|
||||
var/power_drain_rate = 1000
|
||||
var/power_drain_rate = 20 KJ
|
||||
/// Maximum value for power_drain_rate based on upgrades. (Watts)
|
||||
var/max_drain_rate = 1000
|
||||
var/max_drain_rate = 100 KJ
|
||||
|
||||
/// Amount of power (Watts) required to regenerate health.
|
||||
var/power_per_regen = 1000
|
||||
var/power_per_regen = 200 KJ
|
||||
/// Amount of health lost per Life tick when the power requirement was not met.
|
||||
var/health_loss_rate = 5
|
||||
/// Amount of health regenerated per Life tick when the power requirement was met.
|
||||
var/health_regen_rate = 3
|
||||
var/health_regen_rate = 2
|
||||
/// Lock health regeneration while this is not 0, decreases by 1 every Life tick.
|
||||
var/regen_lock = 0
|
||||
/// Tracking to prevent multiple EMPs in the same tick from instakilling a demon.
|
||||
@@ -84,12 +86,12 @@
|
||||
/// Controls whether the demon can move outside of cables. Toggled by a spell.
|
||||
var/can_exit_cable = FALSE
|
||||
/// Speed used while moving inside cables.
|
||||
var/inside_cable_speed = -0.5
|
||||
var/inside_cable_speed = -0.3
|
||||
/// Speed used while moving outside cables. Can be upgraded.
|
||||
var/outside_cable_speed = 5
|
||||
|
||||
/// The time it takes to hijack APCs and cyborgs.
|
||||
var/hijack_time = 30 SECONDS
|
||||
var/hijack_time = 20 SECONDS
|
||||
|
||||
/// The color of light the demon emits. The range of the light is proportional to energy stored.
|
||||
var/glow_color = "#bbbb00"
|
||||
@@ -118,9 +120,24 @@
|
||||
var/list/apc_images = list()
|
||||
/// List of all previously hijacked APCs.
|
||||
var/list/hijacked_apcs = list()
|
||||
/// Current APC amount for use as upgrade currency
|
||||
var/list/apcs_remaining = 0
|
||||
/// Does the pulse demon attempt to use internal power to bypass shock immunity
|
||||
var/strong_shocks = FALSE
|
||||
/// Reference to the APC currently being hijacked.
|
||||
var/obj/machinery/power/apc/apc_being_hijacked
|
||||
|
||||
/mob/living/simple_animal/demon/pulse_demon/wizard
|
||||
name = "Empowered Pulse Demon"
|
||||
real_name = "Empowered Pulse Demon"
|
||||
desc = "A strange electrical apparition that lives in wires. This one appears more charged than usual."
|
||||
|
||||
/mob/living/simple_animal/demon/pulse_demon/wizard/Initialize(mapload)
|
||||
. = ..()
|
||||
src.apcs_remaining = 20
|
||||
src.maxcharge = 500 KJ
|
||||
src.charge = 100 KJ
|
||||
|
||||
/mob/living/simple_animal/demon/pulse_demon/Initialize(mapload)
|
||||
. = ..()
|
||||
if(!mapload)
|
||||
@@ -249,8 +266,9 @@
|
||||
var/list/greeting = list()
|
||||
greeting.Add("<span class='warning'><font size=3><b>You are a pulse demon.</b></font></span>")
|
||||
greeting.Add("<b>A being made of pure electrical energy, you travel through the station's wires and infest machinery.</b>")
|
||||
greeting.Add("<b>Navigate the station's power cables to find power sources to steal from, and hijack APCs to interact with their connected machines.</b>")
|
||||
greeting.Add("<b>If the wire or power source you're connected to runs out of power you'll start losing health and eventually die, but you are otherwise immune to damage.</b>")
|
||||
greeting.Add("<b>Navigate the station's power cables to find power sources to steal from to power your abilities.</b>")
|
||||
greeting.Add("<b>Hijack APCs by entering them to unlock more powerful abilities, gain more maximum charge, and gain access to connected machines.</b>")
|
||||
greeting.Add("<b>If the wire or power source you're connected to runs out of power you'll start losing health and eventually die, but you are otherwise resistant to damage.</b>")
|
||||
greeting.Add("<span class='motd'>For more information, check the wiki page: ([GLOB.configuration.url.wiki_url]/index.php/Pulse_Demon)</span>")
|
||||
for(var/datum/objective/new_obj in list(/datum/objective/pulse_demon/infest, /datum/objective/pulse_demon/drain, /datum/objective/pulse_demon/tamper))
|
||||
mind.add_mind_objective(new_obj)
|
||||
@@ -259,7 +277,9 @@
|
||||
SSticker.mode.traitors |= mind
|
||||
|
||||
/mob/living/simple_animal/demon/pulse_demon/proc/give_spells()
|
||||
AddSpell(new /datum/spell/pulse_demon/open_upgrades)
|
||||
AddSpell(new /datum/spell/pulse_demon/cycle_camera)
|
||||
AddSpell(new /datum/spell/pulse_demon/toggle/penetrating_shock(strong_shocks))
|
||||
AddSpell(new /datum/spell/pulse_demon/toggle/do_drain(do_drain))
|
||||
AddSpell(new /datum/spell/pulse_demon/toggle/can_exit_cable(can_exit_cable))
|
||||
AddSpell(new /datum/spell/pulse_demon/cablehop)
|
||||
@@ -268,7 +288,6 @@
|
||||
AddSpell(new /datum/spell/pulse_demon/overload)
|
||||
AddSpell(new /datum/spell/pulse_demon/remotehijack)
|
||||
AddSpell(new /datum/spell/pulse_demon/remotedrain)
|
||||
AddSpell(new /datum/spell/pulse_demon/open_upgrades)
|
||||
|
||||
/mob/living/simple_animal/demon/pulse_demon/get_status_tab_items()
|
||||
var/list/status_tab_data = ..()
|
||||
@@ -277,6 +296,7 @@
|
||||
status_tab_data[++status_tab_data.len] = list("Maximum Energy:", "[format_si_suffix(maxcharge)]J")
|
||||
status_tab_data[++status_tab_data.len] = list("Drained Energy:", "[format_si_suffix(charge_drained)]J")
|
||||
status_tab_data[++status_tab_data.len] = list("Hijacked APCs:", "[length(hijacked_apcs)]")
|
||||
status_tab_data[++status_tab_data.len] = list("Unused APCs:", "[apcs_remaining]")
|
||||
status_tab_data[++status_tab_data.len] = list("Drain Rate:", "[format_si_suffix(power_drain_rate)]W")
|
||||
status_tab_data[++status_tab_data.len] = list("Hijack Time:", "[hijack_time / 10] seconds")
|
||||
|
||||
@@ -295,6 +315,7 @@
|
||||
var/light_radius = min(charge / 25000, 25)
|
||||
empulse(T, heavy_radius, light_radius)
|
||||
playsound(T, pick(hurt_sounds), 30, TRUE)
|
||||
SEND_SIGNAL(src, COMSIG_MOB_DEATH)
|
||||
|
||||
/mob/living/simple_animal/demon/pulse_demon/proc/exit_to_turf()
|
||||
var/turf/T = get_turf(src)
|
||||
@@ -443,15 +464,15 @@
|
||||
S.action.UpdateButtons()
|
||||
return realdelta
|
||||
|
||||
// logarithmic scale for glow strength, see table:
|
||||
// 1.5 <= 25k
|
||||
// 2 at 50k
|
||||
// 2.5 at 100k
|
||||
// 3 at 200k
|
||||
// 3.5 at 400k, etc
|
||||
// linear scale for glow strength, see table:
|
||||
// 1.5 <= 300000 ()
|
||||
// 2 at 400000
|
||||
// 2.5 at 50000
|
||||
// 3 at 600000 etc
|
||||
|
||||
/mob/living/simple_animal/demon/pulse_demon/proc/update_glow()
|
||||
var/range = 2 + (log(2, charge + 1) - log(2, 50000)) / 2
|
||||
range = max(range, 1.5)
|
||||
var/range = charge / 200000
|
||||
range = clamp(range, 1.5, 5)
|
||||
set_light(range, 2, glow_color)
|
||||
|
||||
/mob/living/simple_animal/demon/pulse_demon/proc/drain_APC(obj/machinery/power/apc/A, multiplier = 1)
|
||||
@@ -627,8 +648,8 @@
|
||||
// Looks weird but it gets the job done
|
||||
/mob/living/simple_animal/demon/pulse_demon/proc/calc_maxcharge(hijacked_apcs)
|
||||
if(!hijacked_apcs) // No APCs hijacked? No extra charge
|
||||
return 1000
|
||||
return 20000 * clamp(hijacked_apcs, 0, 20) + 500000 * clamp(hijacked_apcs - 20, 0, 30) + 1000000 * clamp(hijacked_apcs - 50, 0, 50) + 500000000 * max(0, hijacked_apcs - 100)
|
||||
return 100000
|
||||
return 100000 + (hijacked_apcs * 25000)
|
||||
|
||||
/mob/living/simple_animal/demon/pulse_demon/proc/finish_hijack_apc(obj/machinery/power/apc/A, remote = FALSE)
|
||||
var/image/apc_image = image('icons/obj/power.dmi', A, "apcemag", ABOVE_LIGHTING_LAYER, A.dir)
|
||||
@@ -636,12 +657,33 @@
|
||||
LAZYADD(apc_images[get_turf(A)], apc_image)
|
||||
client.images += apc_image
|
||||
|
||||
apcs_remaining = apcs_remaining + 1
|
||||
hijacked_apcs += A
|
||||
RegisterSignal(A, COMSIG_PARENT_QDELETING, PROC_REF(apc_deleted_handler))
|
||||
if(!remote)
|
||||
update_controlling_area()
|
||||
maxcharge = calc_maxcharge(length(hijacked_apcs)) + (maxcharge - calc_maxcharge(length(hijacked_apcs) - 1))
|
||||
to_chat(src, "<span class='notice'>Hijacking complete! You now control [length(hijacked_apcs)] APCs.</span>")
|
||||
to_chat(src, "<span class='notice'>Hijacking complete! You now control [length(hijacked_apcs)] APCs and have [apcs_remaining] left to spend.</span>")
|
||||
var/turf/T = get_turf(A)
|
||||
var/distance = 0
|
||||
strengthen_cables(T, distance)
|
||||
|
||||
/mob/living/simple_animal/demon/pulse_demon/proc/strengthen_cables(turf/T, distance)
|
||||
distance += 1
|
||||
for(var/obj/structure/cable/cable in T.contents)
|
||||
if(cable.strengthened == TRUE)
|
||||
continue
|
||||
cable.strengthened = TRUE
|
||||
cable.RegisterSignal(src, COMSIG_MOB_DEATH, TYPE_PROC_REF(/obj/structure/cable, unstrengthen_cables))
|
||||
if(distance >= 15)
|
||||
return
|
||||
for(var/obj/structure/cable/cable in range(1, T))
|
||||
if(get_turf(cable) == T)
|
||||
continue
|
||||
if(cable.strengthened == TRUE)
|
||||
continue
|
||||
var/turf/next_turf = get_turf(cable)
|
||||
strengthen_cables(next_turf, distance)
|
||||
|
||||
/mob/living/simple_animal/demon/pulse_demon/proc/on_atom_entered(datum/source, atom/movable/entered)
|
||||
SIGNAL_HANDLER // COMSIG_ATOM_ENTERED
|
||||
@@ -665,11 +707,18 @@
|
||||
if(current_cable && current_cable.powernet && current_cable.powernet.available_power)
|
||||
// returns used energy, not damage dealt, but ez conversion with /20
|
||||
dealt = electrocute_mob(L, current_cable.powernet, src, siemens_coeff) / 20
|
||||
else if(charge >= 1000)
|
||||
else
|
||||
dealt = L.electrocute_act(30, src, siemens_coeff)
|
||||
adjust_charge(-1000)
|
||||
if(dealt > 0)
|
||||
do_sparks(rand(2, 4), FALSE, src)
|
||||
if(dealt == 0 && strong_shocks)
|
||||
if(charge >= 200 KJ)
|
||||
charge -= 200 KJ
|
||||
do_sparks(rand(2, 4), FALSE, src)
|
||||
dealt = L.electrocute_act(30, src, siemens_coeff = 1, flags = SHOCK_NOGLOVES) //bypass that nasty shock resistance
|
||||
else
|
||||
to_chat(src, "<span class = 'danger'>You dont have enough charge to bypass their insulation! You need at least 50KJ of energy!")
|
||||
|
||||
add_attack_logs(src, L, "shocked ([dealt] damage)")
|
||||
|
||||
/mob/living/simple_animal/demon/pulse_demon/proc/is_under_tile()
|
||||
@@ -723,10 +772,10 @@
|
||||
switch(severity)
|
||||
if(EMP_LIGHT)
|
||||
adjustHealth(round(max(initial(health) / 4, round(maxHealth / 8))))
|
||||
regen_lock = 3
|
||||
regen_lock = 5
|
||||
if(EMP_HEAVY)
|
||||
adjustHealth(round(max(initial(health) / 3, round(maxHealth / 6))))
|
||||
regen_lock = 5
|
||||
regen_lock = 8
|
||||
emp_debounce = TRUE
|
||||
addtimer(VARSET_CALLBACK(src, emp_debounce, FALSE), 0.1 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE)
|
||||
|
||||
|
||||
@@ -13,10 +13,12 @@
|
||||
antimagic_flags = NONE
|
||||
action_background_icon_state = "bg_pulsedemon"
|
||||
var/locked = TRUE
|
||||
var/unlock_cost = 1 KJ
|
||||
var/unlock_cost = 1
|
||||
var/cast_cost = 1 KJ
|
||||
var/upgrade_cost = 1 KJ
|
||||
var/upgrade_cost = 1
|
||||
var/requires_area = FALSE
|
||||
var/revealing = FALSE
|
||||
var/reveal_time = 10 SECONDS
|
||||
base_cooldown = 20 SECONDS
|
||||
level_max = 4
|
||||
|
||||
@@ -26,11 +28,11 @@
|
||||
|
||||
/datum/spell/pulse_demon/proc/update_info()
|
||||
if(locked)
|
||||
name = "[initial(name)] (Locked) ([format_si_suffix(unlock_cost)]W)"
|
||||
desc = "[initial(desc)] It costs [format_si_suffix(unlock_cost)]W to unlock. <b>Alt-Click</b> this spell to unlock it."
|
||||
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)]W to upgrade. <b>Alt-Click</b> this spell to upgrade it."]"
|
||||
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.UpdateButtons()
|
||||
@@ -43,7 +45,7 @@
|
||||
if(locked)
|
||||
if(show_message)
|
||||
to_chat(user, "<span class='warning'>This ability is locked! Alt-click the button to purchase this ability.</span>")
|
||||
to_chat(user, "<span class='notice'>It costs [format_si_suffix(unlock_cost)]W to unlock.</span>")
|
||||
to_chat(user, "<span class='notice'>It costs [format_si_suffix(unlock_cost)] APC\s to unlock.</span>")
|
||||
return FALSE
|
||||
if(user.charge < cast_cost)
|
||||
if(show_message)
|
||||
@@ -66,6 +68,8 @@
|
||||
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)
|
||||
@@ -77,42 +81,47 @@
|
||||
/datum/spell/pulse_demon/proc/try_cast_action(mob/living/simple_animal/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/simple_animal/demon/pulse_demon/user)
|
||||
if(!istype(user))
|
||||
return
|
||||
|
||||
if(locked)
|
||||
if(user.charge >= unlock_cost)
|
||||
user.adjust_charge(-unlock_cost)
|
||||
if(user.apcs_remaining >= unlock_cost)
|
||||
user.apcs_remaining -= unlock_cost
|
||||
locked = FALSE
|
||||
to_chat(user, "<span class='notice'>You have unlocked [initial(name)]!</span>")
|
||||
|
||||
if(cast_cost > 0)
|
||||
to_chat(user, "<span class='notice'>It costs [format_si_suffix(cast_cost)]W to use once.</span>")
|
||||
if(level_max > 0 && spell_level < level_max)
|
||||
to_chat(user, "<span class='notice'>It will cost [format_si_suffix(upgrade_cost)]W to upgrade.</span>")
|
||||
to_chat(user, "<span class='notice'>It will cost [format_si_suffix(upgrade_cost)] APC\s to upgrade.</span>")
|
||||
|
||||
update_info()
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You cannot afford this ability! It costs [format_si_suffix(unlock_cost)]W to unlock.</span>")
|
||||
to_chat(user, "<span class='warning'>You cannot afford this ability! It costs [format_si_suffix(unlock_cost)] APC\s to unlock.</span>")
|
||||
else
|
||||
if(spell_level >= level_max)
|
||||
to_chat(user, "<span class='warning'>You have already fully upgraded this ability!</span>")
|
||||
else if(user.charge >= upgrade_cost)
|
||||
user.adjust_charge(-upgrade_cost)
|
||||
else if(user.apcs_remaining >= upgrade_cost)
|
||||
user.apcs_remaining -= upgrade_cost
|
||||
spell_level = min(spell_level + 1, level_max)
|
||||
upgrade_cost = round(initial(upgrade_cost) * (1.5 ** spell_level))
|
||||
do_upgrade(user)
|
||||
|
||||
if(spell_level == level_max)
|
||||
to_chat(user, "<span class='notice'>You have fully upgraded [initial(name)]!</span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>The next upgrade will cost [format_si_suffix(upgrade_cost)]W to unlock.</span>")
|
||||
to_chat(user, "<span class='notice'>The next upgrade will cost [format_si_suffix(upgrade_cost)] APC\s to unlock.</span>")
|
||||
|
||||
update_info()
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You cannot afford to upgrade this ability! It costs [format_si_suffix(upgrade_cost)]W to upgrade.</span>")
|
||||
to_chat(user, "<span class='warning'>You cannot afford to upgrade this ability! It costs [format_si_suffix(upgrade_cost)] APC\s to upgrade.</span>")
|
||||
|
||||
/datum/spell/pulse_demon/proc/do_upgrade(mob/living/simple_animal/demon/pulse_demon/user)
|
||||
cooldown_handler.recharge_duration = round(base_cooldown / (1.5 ** spell_level))
|
||||
@@ -122,9 +131,11 @@
|
||||
name = "Cable Hop"
|
||||
desc = "Jump to another cable in view."
|
||||
action_icon_state = "pd_cablehop"
|
||||
unlock_cost = 15 KJ
|
||||
cast_cost = 5 KJ
|
||||
upgrade_cost = 75 KJ
|
||||
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/simple_animal/demon/pulse_demon/user, atom/target)
|
||||
var/turf/O = get_turf(user)
|
||||
@@ -151,10 +162,11 @@
|
||||
name = "Electromagnetic Tamper"
|
||||
desc = "Unlocks hidden programming in machines. Must be inside a hijacked APC to use."
|
||||
action_icon_state = "pd_emag"
|
||||
unlock_cost = 50 KJ
|
||||
cast_cost = 20 KJ
|
||||
upgrade_cost = 200 KJ
|
||||
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/simple_animal/demon/pulse_demon/user, atom/target)
|
||||
to_chat(user, "<span class='warning'>You attempt to tamper with [target]!</span>")
|
||||
@@ -165,10 +177,11 @@
|
||||
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 = 50 KJ
|
||||
cast_cost = 10 KJ
|
||||
upgrade_cost = 200 KJ
|
||||
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/simple_animal/demon/pulse_demon/user, atom/target)
|
||||
to_chat(user, "<span class='warning'>You attempt to EMP [target]!</span>")
|
||||
@@ -177,12 +190,16 @@
|
||||
|
||||
/datum/spell/pulse_demon/overload
|
||||
name = "Overload Machine"
|
||||
desc = "Overloads a machine, causing it to explode."
|
||||
desc = "Overloads a machine, causing it to explode. Becomes powerful enough to breach when fully upgraded."
|
||||
action_icon_state = "pd_overload"
|
||||
unlock_cost = 300 KJ
|
||||
cast_cost = 50 KJ
|
||||
upgrade_cost = 500 KJ
|
||||
unlock_cost = 8
|
||||
cast_cost = 1000 KJ
|
||||
upgrade_cost = 4
|
||||
level_max = 4
|
||||
requires_area = TRUE
|
||||
revealing = TRUE
|
||||
base_cooldown = 60 SECONDS
|
||||
reveal_time = 20 SECONDS
|
||||
|
||||
/datum/spell/pulse_demon/overload/try_cast_action(mob/living/simple_animal/demon/pulse_demon/user, atom/target)
|
||||
var/obj/machinery/M = target
|
||||
@@ -193,12 +210,15 @@
|
||||
to_chat(user, "<span class='warning'>That machine cannot be overloaded.</span>")
|
||||
return FALSE
|
||||
target.audible_message("<span class='italics'>You hear a loud electrical buzzing sound coming from [target]!</span>")
|
||||
addtimer(CALLBACK(src, PROC_REF(detonate), M), 5 SECONDS)
|
||||
addtimer(CALLBACK(src, PROC_REF(detonate), user, M), 5 SECONDS)
|
||||
return TRUE
|
||||
|
||||
/datum/spell/pulse_demon/overload/proc/detonate(obj/machinery/target)
|
||||
/datum/spell/pulse_demon/overload/proc/detonate(mob/living/simple_animal/demon/pulse_demon/user, obj/machinery/target)
|
||||
if(!QDELETED(target))
|
||||
explosion(get_turf(target), 0, 1, 1, 0, cause = "Pulse Demon: [name]")
|
||||
if(spell_level == level_max)
|
||||
explosion(get_turf(target), 0, 1, 2, 2, smoke = TRUE, cause = "Pulse Demon: [name]")
|
||||
else
|
||||
explosion(get_turf(target), 0, 0, 2, 2, smoke = TRUE, cause = "Pulse Demon: [name]")
|
||||
if(!QDELETED(target))
|
||||
qdel(target)
|
||||
|
||||
@@ -206,8 +226,8 @@
|
||||
name = "Remote Hijack"
|
||||
desc = "Remotely hijacks an APC."
|
||||
action_icon_state = "pd_remotehack"
|
||||
unlock_cost = 15 KJ
|
||||
cast_cost = 10 KJ
|
||||
unlock_cost = 2
|
||||
cast_cost = 200 KJ
|
||||
level_max = 0
|
||||
base_cooldown = 3 SECONDS // you have to wait for the regular hijack time anyway
|
||||
|
||||
@@ -224,9 +244,9 @@
|
||||
name = "Remote Drain"
|
||||
desc = "Remotely drains a power source."
|
||||
action_icon_state = "pd_remotedrain"
|
||||
unlock_cost = 5 KJ
|
||||
cast_cost = 100
|
||||
upgrade_cost = 100 KJ
|
||||
unlock_cost = 2
|
||||
cast_cost = 50 KJ
|
||||
upgrade_cost = 2
|
||||
|
||||
/datum/spell/pulse_demon/remotedrain/try_cast_action(mob/living/simple_animal/demon/pulse_demon/user, atom/target)
|
||||
if(isapc(target))
|
||||
@@ -295,9 +315,9 @@
|
||||
desc = "Toggle whether you can move outside of cables or power sources."
|
||||
base_message = "move outside of cables."
|
||||
action_icon_state = "pd_toggle_exit"
|
||||
unlock_cost = 100 KJ
|
||||
upgrade_cost = 300 KJ
|
||||
upgrade_cost = 2
|
||||
level_max = 3
|
||||
locked = FALSE
|
||||
|
||||
/datum/spell/pulse_demon/toggle/can_exit_cable/try_cast_action(mob/living/simple_animal/demon/pulse_demon/user, atom/target)
|
||||
if(user.can_exit_cable && !(user.current_cable || user.current_power))
|
||||
@@ -354,6 +374,22 @@
|
||||
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"
|
||||
locked = TRUE
|
||||
unlock_cost = 4
|
||||
cast_cost = 0
|
||||
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/simple_animal/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."
|
||||
@@ -389,34 +425,43 @@
|
||||
var/cost
|
||||
switch(upgrade)
|
||||
if(PD_UPGRADE_HIJACK_SPEED)
|
||||
if(user.hijack_time <= 1 SECONDS)
|
||||
if(user.hijack_time <= 6 SECONDS)
|
||||
return -1
|
||||
cost = (100 / (user.hijack_time / (1 SECONDS))) * 20 KJ
|
||||
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 = user.max_drain_rate * 15
|
||||
cost = 1
|
||||
if(PD_UPGRADE_MAX_HEALTH)
|
||||
if(user.maxHealth >= 200)
|
||||
return -1
|
||||
cost = user.maxHealth * 5 KJ
|
||||
if(user.maxHealth <= 100)
|
||||
cost = 1
|
||||
else
|
||||
cost = 2
|
||||
if(PD_UPGRADE_HEALTH_REGEN)
|
||||
if(user.health_regen_rate >= 100)
|
||||
if(user.health_regen_rate >= 10)
|
||||
return -1
|
||||
cost = user.health_regen_rate * 50 KJ
|
||||
cost = 1
|
||||
if(PD_UPGRADE_HEALTH_LOSS)
|
||||
if(user.health_loss_rate <= 1)
|
||||
if(user.health_loss_rate <= 0)
|
||||
return -1
|
||||
cost = (100 / user.health_loss_rate) * 20 KJ
|
||||
if(user.health_loss_rate >= 3)
|
||||
cost = 1
|
||||
else
|
||||
cost = 2
|
||||
if(PD_UPGRADE_HEALTH_COST)
|
||||
if(user.power_per_regen <= 1)
|
||||
if(user.power_per_regen <= 1 KJ)
|
||||
return -1
|
||||
cost = (100 / user.power_per_regen) * 50 KJ
|
||||
cost = 1
|
||||
if(PD_UPGRADE_MAX_CHARGE)
|
||||
cost = user.maxcharge
|
||||
cost = 1
|
||||
else
|
||||
return -1
|
||||
return round(cost)
|
||||
return cost
|
||||
|
||||
/datum/spell/pulse_demon/open_upgrades/proc/get_upgrades(mob/living/simple_animal/demon/pulse_demon/user)
|
||||
var/upgrades = list()
|
||||
@@ -424,7 +469,7 @@
|
||||
var/cost = calc_cost(user, upgrade)
|
||||
if(cost == -1)
|
||||
continue
|
||||
upgrades["[upgrade] ([format_si_suffix(cost)]W)"] = upgrade_icons[upgrade]
|
||||
upgrades["[upgrade] ([format_si_suffix(cost)] APC\s)"] = upgrade_icons[upgrade]
|
||||
return upgrades
|
||||
|
||||
/datum/spell/pulse_demon/open_upgrades/AltClick(mob/living/simple_animal/demon/pulse_demon/user)
|
||||
@@ -450,18 +495,18 @@
|
||||
var/cost = calc_cost(user, choice)
|
||||
if(cost == -1)
|
||||
return FALSE
|
||||
if(user.charge < cost)
|
||||
to_chat(user, "<span class='warning'>You do not have enough charge to purchase this upgrade!</span>")
|
||||
if(user.apcs_remaining < cost)
|
||||
to_chat(user, "<span class='warning'>You do not have enough unused APCs to purchase this upgrade!</span>")
|
||||
return FALSE
|
||||
|
||||
user.adjust_charge(-cost)
|
||||
user.apcs_remaining -= cost
|
||||
switch(choice)
|
||||
if(PD_UPGRADE_HIJACK_SPEED)
|
||||
user.hijack_time = max(round(user.hijack_time / 1.5), 1 SECONDS)
|
||||
user.hijack_time = max(round(user.hijack_time - 3 SECONDS), 6 SECONDS)
|
||||
to_chat(user, "<span class='notice'>You have upgraded your [choice], it now takes [user.hijack_time / (1 SECONDS)] second\s to hijack APCs.</span>")
|
||||
if(PD_UPGRADE_DRAIN_SPEED)
|
||||
var/old = user.max_drain_rate
|
||||
user.max_drain_rate = min(round(user.max_drain_rate * 1.5), 500 KJ)
|
||||
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 class='notice'>You have upgraded your [choice], you can now drain [format_si_suffix(user.max_drain_rate)]W.</span>")
|
||||
@@ -469,23 +514,25 @@
|
||||
user.maxHealth = min(round(user.maxHealth * 1.5), 200)
|
||||
to_chat(user, "<span class='notice'>You have upgraded your [choice], your max health is now [user.maxHealth].</span>")
|
||||
if(PD_UPGRADE_HEALTH_REGEN)
|
||||
user.health_regen_rate = min(round(user.health_regen_rate * 1.5), 100)
|
||||
user.health_regen_rate = min(round(user.health_regen_rate + 2), 10)
|
||||
to_chat(user, "<span class='notice'>You have upgraded your [choice], you will now regenerate [user.health_regen_rate] health per cycle when powered.</span>")
|
||||
if(PD_UPGRADE_HEALTH_LOSS)
|
||||
user.health_loss_rate = max(round(user.health_loss_rate / 1.5), 1)
|
||||
to_chat(user, "<span class='notice'>You have upgraded your [choice], you will now lose [user.health_loss_rate] health per cycle when unpowered.</span>")
|
||||
user.health_loss_rate = max(round(user.health_loss_rate - 1), 0)
|
||||
if(user.health_loss_rate == 0)
|
||||
to_chat(user, "<span class='notice'>You have upgraded your [choice], You will no longer lose health when on an unpowered cable.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You have upgraded your [choice], you will now lose [user.health_loss_rate] health per cycle when unpowered.</span>")
|
||||
if(PD_UPGRADE_HEALTH_COST)
|
||||
user.power_per_regen = max(round(user.power_per_regen / 1.5), 1)
|
||||
to_chat(user, "<span class='notice'>You have upgraded your [choice], it now takes [format_si_suffix(user.power_per_regen)]W of power to regenerate health.</span>")
|
||||
to_chat(user, "<span class='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.</span>")
|
||||
if(PD_UPGRADE_MAX_CHARGE)
|
||||
user.maxcharge = round(user.maxcharge * 2)
|
||||
user.maxcharge = user.maxcharge + 50 KJ
|
||||
to_chat(user, "<span class='notice'>You have upgraded your [choice], you can now store [format_si_suffix(user.maxcharge)]J of energy.</span>")
|
||||
else
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
|
||||
#undef PULSEDEMON_REMOTE_DRAIN_MULTIPLIER
|
||||
#undef PD_UPGRADE_HIJACK_SPEED
|
||||
#undef PD_UPGRADE_DRAIN_SPEED
|
||||
|
||||
@@ -401,7 +401,7 @@
|
||||
var/shatter_msg = "<span class='notice'>You shatter the bulb, no turning back now!</span>"
|
||||
var/veil_msg = "<span class='warning'>The creature sparks energetically and zips away...</span>"
|
||||
var/objective_verb = "Electrocute"
|
||||
var/mob/living/demon_type = /mob/living/simple_animal/demon/pulse_demon
|
||||
var/mob/living/demon_type = /mob/living/simple_animal/demon/pulse_demon/wizard
|
||||
|
||||
/obj/item/antag_spawner/pulse_demon/attack_self__legacy__attackchain(mob/user)
|
||||
if(level_blocks_magic(user.z))
|
||||
@@ -440,7 +440,7 @@
|
||||
var/datum/mind/player_mind = new /datum/mind(C.key)
|
||||
player_mind.active = TRUE
|
||||
|
||||
var/mob/living/simple_animal/demon/pulse_demon/demon = new(T)
|
||||
var/mob/living/simple_animal/demon/pulse_demon/wizard/demon = new(T)
|
||||
player_mind.transfer_to(demon)
|
||||
player_mind.assigned_role = SPECIAL_ROLE_DEMON
|
||||
player_mind.special_role = SPECIAL_ROLE_DEMON
|
||||
|
||||
@@ -40,6 +40,7 @@ By design, d1 is the smallest direction and d2 is the highest
|
||||
var/tmp/d2 = 1
|
||||
/// The regional powernet this cable is registered to
|
||||
var/datum/regional_powernet/powernet
|
||||
var/strengthened = FALSE
|
||||
|
||||
/obj/structure/cable/Initialize(mapload)
|
||||
. = ..()
|
||||
@@ -143,6 +144,9 @@ By design, d1 is the smallest direction and d2 is the highest
|
||||
return
|
||||
if(shock(user, 50))
|
||||
return
|
||||
if(strengthened)
|
||||
to_chat(user, "<span class = 'danger'>The cable resists your attempts to cut it!")
|
||||
return
|
||||
user.visible_message("[user] cuts the cable.", "<span class='notice'>You cut the cable.</span>")
|
||||
investigate_log("was cut by [key_name(usr, 1)] in [get_area(user)]([T.x], [T.y], [T.z] - [ADMIN_JMP(T)])",INVESTIGATE_WIRES)
|
||||
deconstruct()
|
||||
@@ -430,6 +434,11 @@ By design, d1 is the smallest direction and d2 is the highest
|
||||
/obj/structure/cable/white
|
||||
color = COLOR_WHITE
|
||||
|
||||
/obj/structure/cable/proc/unstrengthen_cables(mob/demon)
|
||||
SIGNAL_HANDLER // COMSIG_MOB_DEATH
|
||||
src.strengthened = FALSE
|
||||
UnregisterSignal(demon, COMSIG_MOB_DEATH)
|
||||
|
||||
//
|
||||
// This ASCII art represents my brain after looking at cable
|
||||
// code for too long, half of this was written before I was even
|
||||
|
||||
Reference in New Issue
Block a user