diff --git a/code/game/gamemodes/miniantags/pulsedemon/pulsedemon.dm b/code/game/gamemodes/miniantags/pulsedemon/pulsedemon.dm index afb642ee636..526b6fcd444 100644 --- a/code/game/gamemodes/miniantags/pulsedemon/pulsedemon.dm +++ b/code/game/gamemodes/miniantags/pulsedemon/pulsedemon.dm @@ -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("You are a pulse demon.") greeting.Add("A being made of pure electrical energy, you travel through the station's wires and infest machinery.") - greeting.Add("Navigate the station's power cables to find power sources to steal from, and hijack APCs to interact with their connected machines.") - greeting.Add("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.") + greeting.Add("Navigate the station's power cables to find power sources to steal from to power your abilities.") + greeting.Add("Hijack APCs by entering them to unlock more powerful abilities, gain more maximum charge, and gain access to connected machines.") + greeting.Add("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.") greeting.Add("For more information, check the wiki page: ([GLOB.configuration.url.wiki_url]/index.php/Pulse_Demon)") 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, "Hijacking complete! You now control [length(hijacked_apcs)] APCs.") + to_chat(src, "Hijacking complete! You now control [length(hijacked_apcs)] APCs and have [apcs_remaining] left to spend.") + 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, "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) diff --git a/code/game/gamemodes/miniantags/pulsedemon/pulsedemon_abilities.dm b/code/game/gamemodes/miniantags/pulsedemon/pulsedemon_abilities.dm index f73166576c1..1bb1504bdaf 100644 --- a/code/game/gamemodes/miniantags/pulsedemon/pulsedemon_abilities.dm +++ b/code/game/gamemodes/miniantags/pulsedemon/pulsedemon_abilities.dm @@ -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. Alt-Click 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. Alt-Click 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. Alt-Click this spell to upgrade it."]" + desc = "[initial(desc)][spell_level == level_max ? "" : " It costs [format_si_suffix(upgrade_cost)] APC\s to upgrade. Alt-Click 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, "This ability is locked! Alt-click the button to purchase this ability.") - to_chat(user, "It costs [format_si_suffix(unlock_cost)]W to unlock.") + to_chat(user, "It costs [format_si_suffix(unlock_cost)] APC\s to unlock.") 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, "You have unlocked [initial(name)]!") if(cast_cost > 0) to_chat(user, "It costs [format_si_suffix(cast_cost)]W to use once.") if(level_max > 0 && spell_level < level_max) - to_chat(user, "It will cost [format_si_suffix(upgrade_cost)]W to upgrade.") + to_chat(user, "It will cost [format_si_suffix(upgrade_cost)] APC\s to upgrade.") update_info() else - to_chat(user, "You cannot afford this ability! It costs [format_si_suffix(unlock_cost)]W to unlock.") + to_chat(user, "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, "You have already fully upgraded this ability!") - 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, "You have fully upgraded [initial(name)]!") else - to_chat(user, "The next upgrade will cost [format_si_suffix(upgrade_cost)]W to unlock.") + to_chat(user, "The next upgrade will cost [format_si_suffix(upgrade_cost)] APC\s to unlock.") update_info() else - to_chat(user, "You cannot afford to upgrade this ability! It costs [format_si_suffix(upgrade_cost)]W to upgrade.") + to_chat(user, "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/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, "You attempt to tamper with [target]!") @@ -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, "You attempt to EMP [target]!") @@ -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, "That machine cannot be overloaded.") return FALSE target.audible_message("You hear a loud electrical buzzing sound coming from [target]!") - 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, "You do not have enough charge to purchase this upgrade!") + if(user.apcs_remaining < cost) + to_chat(user, "You do not have enough unused APCs to purchase this upgrade!") 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, "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 = 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, "You have upgraded your [choice], you can now drain [format_si_suffix(user.max_drain_rate)]W.") @@ -469,23 +514,25 @@ user.maxHealth = min(round(user.maxHealth * 1.5), 200) to_chat(user, "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 * 1.5), 100) + user.health_regen_rate = min(round(user.health_regen_rate + 2), 10) to_chat(user, "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.5), 1) - to_chat(user, "You have upgraded your [choice], you will now lose [user.health_loss_rate] health per cycle when unpowered.") + user.health_loss_rate = max(round(user.health_loss_rate - 1), 0) + if(user.health_loss_rate == 0) + to_chat(user, "You have upgraded your [choice], You will no longer lose health when on an unpowered cable.") + else + to_chat(user, "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, "You have upgraded your [choice], it now takes [format_si_suffix(user.power_per_regen)]W of power to regenerate health.") to_chat(user, "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 = round(user.maxcharge * 2) + user.maxcharge = user.maxcharge + 50 KJ to_chat(user, "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 diff --git a/code/modules/antagonists/_common/antag_spawner.dm b/code/modules/antagonists/_common/antag_spawner.dm index 92a69487236..87702960167 100644 --- a/code/modules/antagonists/_common/antag_spawner.dm +++ b/code/modules/antagonists/_common/antag_spawner.dm @@ -401,7 +401,7 @@ var/shatter_msg = "You shatter the bulb, no turning back now!" var/veil_msg = "The creature sparks energetically and zips away..." 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 diff --git a/code/modules/power/cables/cable.dm b/code/modules/power/cables/cable.dm index c67ec5e8ff0..f29723edfc7 100644 --- a/code/modules/power/cables/cable.dm +++ b/code/modules/power/cables/cable.dm @@ -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, "The cable resists your attempts to cut it!") + return user.visible_message("[user] cuts the cable.", "You cut the cable.") 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 diff --git a/icons/mob/actions/actions.dmi b/icons/mob/actions/actions.dmi index b2860c62af9..22ca74f6e2f 100644 Binary files a/icons/mob/actions/actions.dmi and b/icons/mob/actions/actions.dmi differ