diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index c211b501fc1..d7bb6714614 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -611,6 +611,8 @@ #define COMSIG_GRILL_COMPLETED "item_grill_completed" ///Called when an armor plate is successfully applied to an object #define COMSIG_ARMOR_PLATED "armor_plated" +///Called when an item gets recharged by the ammo powerup +#define COMSIG_ITEM_RECHARGED "item_recharged" ///from base of [/obj/item/proc/tool_check_callback]: (mob/living/user) #define COMSIG_TOOL_IN_USE "tool_in_use" diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm index 2c4a7bad3b0..57c9708bff4 100644 --- a/code/__DEFINES/status_effects.dm +++ b/code/__DEFINES/status_effects.dm @@ -33,6 +33,10 @@ #define STATUS_EFFECT_DETERMINED /datum/status_effect/determined //currently in a combat high from being seriously wounded +#define STATUS_EFFECT_LIGHTNINGORB /datum/status_effect/lightningorb //Speed from a lightning orb! + +#define STATUS_EFFECT_MAYHEM /datum/status_effect/mayhem //Total bloodbath. Activated by orb of mayhem pickup/bottle of mayhem item. + ///////////// // DEBUFFS // ///////////// diff --git a/code/datums/status_effects/buffs.dm b/code/datums/status_effects/buffs.dm index e710cc06e0e..84c315993b1 100644 --- a/code/datums/status_effects/buffs.dm +++ b/code/datums/status_effects/buffs.dm @@ -462,3 +462,51 @@ name = "Blessing of Wounded Soldier" desc = "Some people seek power through redemption, one thing many people don't know is that battle is the ultimate redemption and wounds let you bask in eternal glory." icon_state = "wounded_soldier" + +/datum/status_effect/lightningorb + id = "Lightning Orb" + duration = 30 SECONDS + alert_type = /atom/movable/screen/alert/status_effect/lightningorb + +/datum/status_effect/lightningorb/on_apply() + . = ..() + owner.add_movespeed_modifier(/datum/movespeed_modifier/yellow_orb) + to_chat(owner, "You feel fast!") + +/datum/status_effect/lightningorb/on_remove() + . = ..() + owner.remove_movespeed_modifier(/datum/movespeed_modifier/yellow_orb) + to_chat(owner, "You slow down.") + +/atom/movable/screen/alert/status_effect/lightningorb + name = "Lightning Orb" + desc = "The speed surges through you!" + icon_state = "lightningorb" + +/datum/status_effect/mayhem + id = "Mayhem" + duration = 2 MINUTES + /// The chainsaw spawned by the status effect + var/obj/item/chainsaw/doomslayer/chainsaw + +/datum/status_effect/mayhem/on_apply() + . = ..() + to_chat(owner, "RIP AND TEAR") + SEND_SOUND(owner, sound('sound/hallucinations/veryfar_noise.ogg')) + new /datum/hallucination/delusion(owner, forced = TRUE, force_kind = "demon", duration = duration, skip_nearby = FALSE) + chainsaw = new(get_turf(owner)) + owner.log_message("entered a blood frenzy", LOG_ATTACK) + ADD_TRAIT(chainsaw, TRAIT_NODROP, CHAINSAW_FRENZY_TRAIT) + owner.drop_all_held_items() + owner.put_in_hands(chainsaw, forced = TRUE) + chainsaw.attack_self(owner) + owner.reagents.add_reagent(/datum/reagent/medicine/adminordrazine,25) + to_chat(owner, "KILL, KILL, KILL! YOU HAVE NO ALLIES ANYMORE, KILL THEM ALL!") + var/datum/client_colour/colour = owner.add_client_colour(/datum/client_colour/bloodlust) + QDEL_IN(colour, 1.1 SECONDS) + +/datum/status_effect/mayhem/on_remove() + . = ..() + to_chat(owner, "Your bloodlust seeps back into the bog of your subconscious and you regain self control.") + owner.log_message("exited a blood frenzy", LOG_ATTACK) + QDEL_NULL(chainsaw) diff --git a/code/game/objects/effects/mines.dm b/code/game/objects/effects/mines.dm index 9080f136e76..50488d59f4d 100644 --- a/code/game/objects/effects/mines.dm +++ b/code/game/objects/effects/mines.dm @@ -130,95 +130,6 @@ name = "bwoink mine" sound = 'sound/effects/adminhelp.ogg' -/obj/effect/mine/pickup - name = "pickup" - desc = "pick me up" - icon = 'icons/effects/effects.dmi' - icon_state = "electricity2" - density = FALSE - var/duration = 0 - -/obj/effect/mine/pickup/Initialize() - . = ..() - animate(src, pixel_y = 4, time = 20, loop = -1) - -/obj/effect/mine/pickup/triggermine(mob/victim) - if(triggered) - return - triggered = 1 - invisibility = INVISIBILITY_ABSTRACT - mineEffect(victim) - qdel(src) - - -/obj/effect/mine/pickup/bloodbath - name = "Red Orb" - desc = "You feel angry just looking at it." - duration = 1200 //2min - color = "#FF0000" - var/mob/living/doomslayer - var/obj/item/chainsaw/doomslayer/chainsaw - -/obj/effect/mine/pickup/bloodbath/mineEffect(mob/living/carbon/victim) - if(!victim.client || !istype(victim)) - return - to_chat(victim, "RIP AND TEAR") - - INVOKE_ASYNC(src, .proc/blood_delusion, victim) - - chainsaw = new(victim.loc) - victim.log_message("entered a blood frenzy", LOG_ATTACK) - - ADD_TRAIT(chainsaw, TRAIT_NODROP, CHAINSAW_FRENZY_TRAIT) - victim.drop_all_held_items() - victim.put_in_hands(chainsaw, forced = TRUE) - chainsaw.attack_self(victim) - victim.reagents.add_reagent(/datum/reagent/medicine/adminordrazine,25) - to_chat(victim, "KILL, KILL, KILL! YOU HAVE NO ALLIES ANYMORE, KILL THEM ALL!") - - var/datum/client_colour/colour = victim.add_client_colour(/datum/client_colour/bloodlust) - QDEL_IN(colour, 11) - doomslayer = victim - RegisterSignal(src, COMSIG_PARENT_QDELETING, .proc/end_blood_frenzy) - QDEL_IN(WEAKREF(src), duration) - -/obj/effect/mine/pickup/bloodbath/proc/end_blood_frenzy() - if(doomslayer) - to_chat(doomslayer, "Your bloodlust seeps back into the bog of your subconscious and you regain self control.") - doomslayer.log_message("exited a blood frenzy", LOG_ATTACK) - if(chainsaw) - qdel(chainsaw) - -/obj/effect/mine/pickup/bloodbath/proc/blood_delusion(mob/living/carbon/victim) - new /datum/hallucination/delusion(victim, TRUE, "demon", duration, 0) - -/obj/effect/mine/pickup/healing - name = "Blue Orb" - desc = "You feel better just looking at it." - color = "#0000FF" - -/obj/effect/mine/pickup/healing/mineEffect(mob/living/carbon/victim) - if(!victim.client || !istype(victim)) - return - to_chat(victim, "You feel great!") - victim.revive(full_heal = TRUE, admin_revive = TRUE) - -/obj/effect/mine/pickup/speed - name = "Yellow Orb" - desc = "You feel faster just looking at it." - color = "#FFFF00" - duration = 300 - -/obj/effect/mine/pickup/speed/mineEffect(mob/living/carbon/victim) - if(!victim.client || !istype(victim)) - return - to_chat(victim, "You feel fast!") - victim.add_movespeed_modifier(/datum/movespeed_modifier/yellow_orb) - sleep(duration) - victim.remove_movespeed_modifier(/datum/movespeed_modifier/yellow_orb) - to_chat(victim, "You slow down.") - - /// These mines spawn pellet_clouds around them when triggered /obj/effect/mine/shrapnel name = "shrapnel mine" diff --git a/code/game/objects/effects/powerup.dm b/code/game/objects/effects/powerup.dm new file mode 100644 index 00000000000..7d68f9e5352 --- /dev/null +++ b/code/game/objects/effects/powerup.dm @@ -0,0 +1,126 @@ +/obj/effect/powerup + name = "power-up" + icon = 'icons/effects/effects.dmi' + density = FALSE + anchored = TRUE + resistance_flags = INDESTRUCTIBLE + /// How long in deciseconds it will take for the powerup to respawn, if no value it won't respawn + var/respawn_time + /// How long the powerup stays on the ground, if no value it will stay forever + var/lifetime + /// Message given when powerup is picked up + var/pickup_message + /// Sound played when powerup is picked up + var/pickup_sound + /// Cooldown for the powerup to respawn after it's been used + COOLDOWN_DECLARE(respawn_cooldown) + +/obj/effect/powerup/Initialize() + ..() + if(lifetime) + QDEL_IN(src, lifetime) + +/obj/effect/powerup/Crossed(atom/movable/movable_atom) + . = ..() + trigger(movable_atom) + +/obj/effect/powerup/Bump(atom/bumped_atom) + trigger(bumped_atom) + +/obj/effect/powerup/Bumped(atom/movable/movable_atom) + trigger(movable_atom) + +/// Triggers the effect of the powerup on the target, returns FALSE if the target is not /mob/living, is dead or the cooldown hasn't finished, returns TRUE otherwise +/obj/effect/powerup/proc/trigger(mob/living/target) + if(!istype(target) || target.stat == DEAD) + return FALSE + if(respawn_time) + if(!COOLDOWN_FINISHED(src, respawn_cooldown)) + return FALSE + COOLDOWN_START(src, respawn_cooldown, respawn_time) + alpha = 100 + addtimer(VARSET_CALLBACK(src, alpha, initial(alpha)), respawn_time) + else + qdel(src) + if(pickup_message) + to_chat(target, "[pickup_message]") + if(pickup_sound) + playsound(get_turf(target), pickup_sound, 50, TRUE, -1) + return TRUE + +/obj/effect/powerup/health + name = "health pickup" + desc = "Blessing from the havens." + icon = 'icons/obj/storage.dmi' + icon_state = "medicalpack" + respawn_time = 30 SECONDS + pickup_message = "Health restored!" + pickup_sound = 'sound/magic/staff_healing.ogg' + /// How much the pickup heals when picked up + var/heal_amount = 50 + /// Does this pickup fully heal when picked up + var/full_heal = FALSE + /// If full heal, does this do an admin level heal? + var/admin_heal = FALSE + +/obj/effect/powerup/health/trigger(mob/living/target) + . = ..() + if(!.) + return + if(full_heal) + target.fully_heal(admin_heal) + else if(heal_amount) + target.heal_ordered_damage(heal_amount, list(BRUTE, BURN)) + +/obj/effect/powerup/health/full + name = "mega health pickup" + desc = "Now this is what I'm talking about." + icon_state = "duffel-med" + full_heal = TRUE + +/obj/effect/powerup/ammo + name = "ammo pickup" + desc = "You like revenge, right? Everybody likes revenge! Well, let's go get some!" + icon = 'icons/obj/storage.dmi' + icon_state = "ammobox" + respawn_time = 30 SECONDS + pickup_message = "Ammunition reloaded!" + pickup_sound = 'sound/weapons/gun/shotgun/rack.ogg' + +/obj/effect/powerup/ammo/trigger(mob/living/target) + . = ..() + if(!.) + return + for(var/obj/item/gun in target.GetAllContents()) + if(!isgun(gun) && !istype(gun, /obj/item/flamethrower)) + continue + SEND_SIGNAL(gun, COMSIG_ITEM_RECHARGED) + +/obj/effect/powerup/ammo/ctf + icon = 'icons/effects/effects.dmi' + icon_state = "at_shield1" + respawn_time = FALSE + lifetime = 30 SECONDS + +/obj/effect/powerup/speed + name = "Lightning Orb" + desc = "You feel faster just looking at it." + icon_state = "electricity2" + pickup_sound = 'sound/magic/lightningshock.ogg' + +/obj/effect/powerup/speed/trigger(mob/living/target) + . = ..() + if(!.) + return + target.apply_status_effect(STATUS_EFFECT_LIGHTNINGORB) + +/obj/effect/powerup/mayhem + name = "Orb of Mayhem" + desc = "You feel angry just looking at it." + icon_state = "impact_laser" + +/obj/effect/powerup/mayhem/trigger(mob/living/target) + . = ..() + if(!.) + return + target.apply_status_effect(STATUS_EFFECT_MAYHEM) diff --git a/code/game/objects/items/flamethrower.dm b/code/game/objects/items/flamethrower.dm index 6318e85b3ad..1d50421d7bd 100644 --- a/code/game/objects/items/flamethrower.dm +++ b/code/game/objects/items/flamethrower.dm @@ -236,6 +236,7 @@ if(create_with_tank) ptank = new /obj/item/tank/internals/plasma/full(src) update_icon() + RegisterSignal(src, COMSIG_ITEM_RECHARGED, .proc/instant_refill) /obj/item/flamethrower/full create_full = TRUE @@ -259,3 +260,11 @@ /obj/item/assembly/igniter/proc/ignite_turf(obj/item/flamethrower/F,turf/open/location,release_amount = 0.05) F.default_ignite(location,release_amount) + +/obj/item/flamethrower/proc/instant_refill() + if(ptank) + ptank.air_contents.assert_gas(/datum/gas/plasma) + ptank.air_contents.gases[/datum/gas/plasma][MOLES] = (10*ONE_ATMOSPHERE)*ptank.volume/(R_IDEAL_GAS_EQUATION*T20C) + else + ptank = new /obj/item/tank/internals/plasma/full(src) + update_icon() diff --git a/code/modules/admin/fun_balloon.dm b/code/modules/admin/fun_balloon.dm index 6a12116852c..5790c685681 100644 --- a/code/modules/admin/fun_balloon.dm +++ b/code/modules/admin/fun_balloon.dm @@ -170,11 +170,7 @@ var/mob/living/M = AM M.forceMove(get_turf(LA)) to_chat(M, "You're trapped in a deadly arena! To escape, you'll need to drag a severed head to the escape portals.", confidential = TRUE) - INVOKE_ASYNC(src, .proc/do_bloodbath, M) - -/obj/effect/forcefield/arena_shuttle_entrance/proc/do_bloodbath(mob/living/L) - var/obj/effect/mine/pickup/bloodbath/B = new (L) - B.mineEffect(L) + M.apply_status_effect(STATUS_EFFECT_MAYHEM) /area/shuttle_arena name = "arena" diff --git a/code/modules/awaymissions/capture_the_flag.dm b/code/modules/awaymissions/capture_the_flag.dm index d7e02b5a54d..89474732cdc 100644 --- a/code/modules/awaymissions/capture_the_flag.dm +++ b/code/modules/awaymissions/capture_the_flag.dm @@ -4,7 +4,6 @@ #define FLAG_RETURN_TIME 200 // 20 seconds #define INSTAGIB_RESPAWN 50 //5 seconds #define DEFAULT_RESPAWN 150 //15 seconds -#define AMMO_DROP_LIFETIME 300 #define CTF_REQUIRED_PLAYERS 4 /obj/item/ctf @@ -184,8 +183,7 @@ ///assoc list for classes. If there's only one, it'll just equip. Otherwise, it lets you pick which outfit! var/list/ctf_gear = list("white" = /datum/outfit/ctf) var/instagib_gear = /datum/outfit/ctf/instagib - var/ammo_type = /obj/effect/ctf/ammo - + var/ammo_type = /obj/effect/powerup/ammo/ctf // Fast paced gameplay, no real time for burn infections. var/player_traits = list(TRAIT_NEVER_WOUNDED) @@ -670,45 +668,6 @@ alpha = 100 resistance_flags = INDESTRUCTIBLE -/obj/effect/ctf/ammo - name = "ammo pickup" - desc = "You like revenge, right? Everybody likes revenge! Well, \ - let's go get some!" - icon = 'icons/effects/effects.dmi' - icon_state = "at_shield1" - layer = ABOVE_MOB_LAYER - alpha = 255 - invisibility = 0 - -/obj/effect/ctf/ammo/Initialize(mapload) - ..() - QDEL_IN(src, AMMO_DROP_LIFETIME) - -/obj/effect/ctf/ammo/Crossed(atom/movable/AM) - . = ..() - reload(AM) - -/obj/effect/ctf/ammo/Bump(atom/A) - reload(A) - -/obj/effect/ctf/ammo/Bumped(atom/movable/AM) - reload(AM) - -/obj/effect/ctf/ammo/proc/reload(mob/living/M) - if(!ishuman(M)) - return - for(var/obj/machinery/capture_the_flag/CTF in GLOB.machines) - if(M in CTF.spawned_mobs) - var/outfit = CTF.spawned_mobs[M] - var/datum/outfit/O = new outfit - for(var/obj/item/gun/G in M) - qdel(G) - O.equip(M) - to_chat(M, "Ammunition reloaded!") - playsound(get_turf(M), 'sound/weapons/gun/shotgun/rack.ogg', 50, TRUE, -1) - qdel(src) - break - /obj/effect/ctf/dead_barricade name = "dead barrier" desc = "It provided cover in fire fights. And now it's gone." @@ -774,5 +733,4 @@ #undef FLAG_RETURN_TIME #undef INSTAGIB_RESPAWN #undef DEFAULT_RESPAWN -#undef AMMO_DROP_LIFETIME #undef CTF_REQUIRED_PLAYERS diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm index 0d53a79dc20..9ac3f955ce8 100644 --- a/code/modules/mining/lavaland/necropolis_chests.dm +++ b/code/modules/mining/lavaland/necropolis_chests.dm @@ -1075,12 +1075,11 @@ /obj/item/mayhem/attack_self(mob/user) for(var/mob/living/carbon/human/H in range(7,user)) - var/obj/effect/mine/pickup/bloodbath/B = new(H) - INVOKE_ASYNC(B, /obj/effect/mine/pickup/bloodbath/.proc/mineEffect, H) + H.apply_status_effect(STATUS_EFFECT_MAYHEM) to_chat(user, "You shatter the bottle!") playsound(user.loc, 'sound/effects/glassbr1.ogg', 100, TRUE) message_admins("[ADMIN_LOOKUPFLW(user)] has activated a bottle of mayhem!") - log_combat(user, null, "activated a bottle of mayhem", src) + user.log_message("activated a bottle of mayhem", LOG_ATTACK) qdel(src) //Colossus diff --git a/code/modules/projectiles/guns/ballistic.dm b/code/modules/projectiles/guns/ballistic.dm index 352a40a1a54..df51f04f080 100644 --- a/code/modules/projectiles/guns/ballistic.dm +++ b/code/modules/projectiles/guns/ballistic.dm @@ -124,6 +124,7 @@ else chamber_round(replace_new_round = TRUE) update_icon() + RegisterSignal(src, COMSIG_ITEM_RECHARGED, .proc/instant_reload) /obj/item/gun/ballistic/vv_edit_var(vname, vval) . = ..() @@ -612,6 +613,15 @@ GLOBAL_LIST_INIT(gun_saw_types, typecacheof(list( process_fire(user, user, FALSE) . = TRUE +/obj/item/gun/ballistic/proc/instant_reload() + if(magazine) + magazine.top_off() + else + if(!mag_type) + return + magazine = new mag_type(src) + chamber_round() + update_icon() /obj/item/suppressor name = "suppressor" diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm index a9f92eeb6ad..5cae6c77ea0 100644 --- a/code/modules/projectiles/guns/energy.dm +++ b/code/modules/projectiles/guns/energy.dm @@ -44,6 +44,7 @@ if(selfcharge) START_PROCESSING(SSobj, src) update_icon() + RegisterSignal(src, COMSIG_ITEM_RECHARGED, .proc/instant_recharge) /obj/item/gun/energy/ComponentInitialize() . = ..() @@ -243,3 +244,10 @@ playsound(user, BB.hitsound, 50, TRUE) cell.use(E.e_cost) . = "[user] casually lights [A.loc == user ? "[user.p_their()] [A.name]" : A] with [src]. Damn." + +/obj/item/gun/energy/proc/instant_recharge() + if(!cell) + return + cell.charge = cell.maxcharge + recharge_newshot(no_cyborg_drain = TRUE) + update_icon() diff --git a/code/modules/projectiles/guns/magic.dm b/code/modules/projectiles/guns/magic.dm index 896876c118e..fdff86776af 100644 --- a/code/modules/projectiles/guns/magic.dm +++ b/code/modules/projectiles/guns/magic.dm @@ -54,6 +54,7 @@ chambered = new ammo_type(src) if(can_charge) START_PROCESSING(SSobj, src) + RegisterSignal(src, COMSIG_ITEM_RECHARGED, .proc/instant_recharge) /obj/item/gun/magic/Destroy() @@ -89,3 +90,8 @@ switch(var_name) if(NAMEOF(src, charges)) recharge_newshot() + +/obj/item/gun/magic/proc/instant_recharge() + charges = max_charges + recharge_newshot() + update_icon() diff --git a/icons/hud/screen_alert.dmi b/icons/hud/screen_alert.dmi index fb35edddf62..ca92a6c390c 100755 Binary files a/icons/hud/screen_alert.dmi and b/icons/hud/screen_alert.dmi differ diff --git a/tgstation.dme b/tgstation.dme index 042d46d3a6f..ddf88660cba 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -959,6 +959,7 @@ #include "code\game\objects\effects\overlays.dm" #include "code\game\objects\effects\phased_mob.dm" #include "code\game\objects\effects\portals.dm" +#include "code\game\objects\effects\powerup.dm" #include "code\game\objects\effects\proximity.dm" #include "code\game\objects\effects\spiders.dm" #include "code\game\objects\effects\step_triggers.dm"