diff --git a/code/datums/components/fantasy/suffixes.dm b/code/datums/components/fantasy/suffixes.dm
index 5a89a6125fe..2b25e442b23 100644
--- a/code/datums/components/fantasy/suffixes.dm
+++ b/code/datums/components/fantasy/suffixes.dm
@@ -148,20 +148,22 @@
/datum/fantasy_affix/shrapnel/apply(datum/component/fantasy/comp, newName)
. = ..()
// higher means more likely
- var/list/weighted_projectile_types = list(/obj/projectile/meteor = 1,
- /obj/projectile/energy/nuclear_particle = 1,
- /obj/projectile/beam/pulse = 1,
- /obj/projectile/bullet/honker = 15,
- /obj/projectile/temp = 15,
- /obj/projectile/ion = 15,
- /obj/projectile/magic/door = 15,
- /obj/projectile/magic/locker = 15,
- /obj/projectile/magic/fetch = 15,
- /obj/projectile/beam/emitter = 15,
- /obj/projectile/magic/flying = 15,
- /obj/projectile/bullet/incendiary/c9mm = 15,
- /obj/projectile/temp/hot = 15,
- /obj/projectile/beam/disabler = 15)
+ var/list/weighted_projectile_types = list(
+ /obj/projectile/beam/disabler = 15,
+ /obj/projectile/beam/emitter = 15,
+ /obj/projectile/bullet/honker = 15,
+ /obj/projectile/beam/pulse = 1,
+ /obj/projectile/bullet/incendiary/c9mm = 15,
+ /obj/projectile/energy/nuclear_particle = 1,
+ /obj/projectile/ion = 15,
+ /obj/projectile/magic/door = 15,
+ /obj/projectile/magic/fetch = 15,
+ /obj/projectile/magic/flying = 15,
+ /obj/projectile/magic/locker = 15,
+ /obj/projectile/meteor = 1,
+ /obj/projectile/temp = 15,
+ /obj/projectile/temp/hot = 15,
+ )
var/obj/projectile/picked_projectiletype = pick_weight(weighted_projectile_types)
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 446dc45ab66..6c56a42b65b 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -1896,7 +1896,7 @@
return null
/obj/item/animate_atom_living(mob/living/owner)
- new /mob/living/basic/mimic/copy(drop_location(), src, owner)
+ return new /mob/living/basic/mimic/copy(drop_location(), src, owner)
/**
* Used to update the weight class of the item in a way that other atoms can react to the change.
diff --git a/code/game/objects/structures.dm b/code/game/objects/structures.dm
index 9d4442238ac..84ca7cc046c 100644
--- a/code/game/objects/structures.dm
+++ b/code/game/objects/structures.dm
@@ -68,7 +68,7 @@
. = ..()
/obj/structure/animate_atom_living(mob/living/owner)
- new /mob/living/basic/mimic/copy(drop_location(), src, owner)
+ return new /mob/living/basic/mimic/copy(drop_location(), src, owner)
/// For when a mob comes flying through the window, smash it and damage the mob
/obj/structure/proc/smash_and_injure(mob/living/flying_mob, atom/oldloc, direction)
diff --git a/code/game/objects/structures/petrified_statue.dm b/code/game/objects/structures/petrified_statue.dm
index 73f3ac942f1..e6327a1a811 100644
--- a/code/game/objects/structures/petrified_statue.dm
+++ b/code/game/objects/structures/petrified_statue.dm
@@ -105,7 +105,7 @@
petrified_mob.mind?.transfer_to(new_statue)
to_chat(new_statue, span_userdanger("You are an animate statue. You cannot move when monitored, but are nearly invincible and deadly when unobserved! [owner ? "Do not harm [owner], your creator" : ""]."))
forceMove(new_statue)
-
+ return new_statue
/mob/proc/petrify(statue_timer)
return
diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm
index 277cadb5ab2..d998760b601 100644
--- a/code/modules/projectiles/gun.dm
+++ b/code/modules/projectiles/gun.dm
@@ -656,7 +656,7 @@
return TRUE
/obj/item/gun/animate_atom_living(mob/living/owner)
- new /mob/living/basic/mimic/copy/ranged(drop_location(), src, owner)
+ return new /mob/living/basic/mimic/copy/ranged(drop_location(), src, owner)
/obj/item/gun/proc/handle_suicide(mob/living/carbon/human/user, mob/living/carbon/human/target, params, bypass_timer)
if(!ishuman(user) || !ishuman(target))
diff --git a/code/modules/projectiles/guns/magic.dm b/code/modules/projectiles/guns/magic.dm
index 510d815d79d..b1dea590268 100644
--- a/code/modules/projectiles/guns/magic.dm
+++ b/code/modules/projectiles/guns/magic.dm
@@ -10,21 +10,27 @@
obj_flags = CONDUCTS_ELECTRICITY
w_class = WEIGHT_CLASS_HUGE
can_muzzle_flash = FALSE
- ///what kind of magic is this
- var/school = SCHOOL_EVOCATION
- var/antimagic_flags = MAGIC_RESISTANCE
- var/max_charges = 6
- var/charges = 0
- var/recharge_rate = 8
- var/charge_timer = 0
- /// Whether this wand/staff recharges on its own over time.
- /// (This is not related to the spell "Charge" whatsoever!)
- var/can_charge = TRUE
- var/ammo_type
- var/no_den_usage
- clumsy_check = 0
+ clumsy_check = FALSE
trigger_guard = TRIGGER_GUARD_ALLOW_ALL // Has no trigger at all, uses magic instead
pin = /obj/item/firing_pin/magic
+ /// What kind of magic is this
+ var/school = SCHOOL_EVOCATION
+ /// What kind of antimagic resists this
+ var/antimagic_flags = MAGIC_RESISTANCE
+ /// How many charges can we hold at most
+ var/max_charges = 6
+ /// How many charges do we currently have
+ var/charges = 0
+ /// How fast do we recharge charges? In seconds
+ var/recharge_rate = 8
+ /// How much have we currently recharged?
+ var/charge_timer = 0
+ /// Whether this wand/staff recharges on its own over time.
+ var/self_charging = TRUE
+ /// What kind of projectile do we fire?
+ var/ammo_type
+ /// If set to TRUE, wizards can't use this until they leave home
+ var/no_den_usage = FALSE
/obj/item/gun/magic/Initialize(mapload)
. = ..()
@@ -60,7 +66,7 @@
. = COMPONENT_ITEM_CHARGED
// Non-self charging staves and wands can potentially expire
- if(!can_charge && max_charges && prob(80))
+ if(!self_charging && max_charges && prob(80))
max_charges--
if(max_charges <= 0)
@@ -81,11 +87,11 @@
to_chat(user, span_warning("You know better than to violate the security of The Den, best wait until you leave to use [src]."))
return
else
- no_den_usage = 0
+ no_den_usage = FALSE // Well you're probably not going back
if(!user.can_cast_magic(antimagic_flags))
add_fingerprint(user)
return
- . = ..()
+ return ..()
/obj/item/gun/magic/can_shoot()
return charges
@@ -104,17 +110,15 @@
charges = max_charges
if(ammo_type)
chambered = new ammo_type(src)
- if(can_charge)
+ if(self_charging)
START_PROCESSING(SSobj, src)
RegisterSignal(src, COMSIG_ITEM_RECHARGED, PROC_REF(instant_recharge))
-
/obj/item/gun/magic/Destroy()
- if(can_charge)
+ if(self_charging)
STOP_PROCESSING(SSobj, src)
return ..()
-
/obj/item/gun/magic/process(seconds_per_tick)
if (charges >= max_charges)
charge_timer = 0
@@ -128,15 +132,26 @@
recharge_newshot()
return 1
-
/obj/item/gun/magic/shoot_with_empty_chamber(mob/living/user as mob|obj)
to_chat(user, span_warning("\The [src] whizzles quietly."))
/obj/item/gun/magic/suicide_act(mob/living/user)
user.visible_message(span_suicide("[user] is twisting [src] above [user.p_their()] head, releasing a magical blast! It looks like [user.p_theyre()] trying to commit suicide!"))
+ if (can_user_shoot(user))
+ charges--
+ return do_suicide(user)
+ user.visible_message(span_suicide("...but nothing happens."))
+ return SHAME
+
+/// Extend to do something funny
+/obj/item/gun/magic/proc/do_suicide(mob/living/user)
playsound(loc, fire_sound, 50, TRUE, -1)
return FIRELOSS
+/// Returns true if specified mob can fire this weapon
+/obj/item/gun/magic/proc/can_user_shoot(mob/living/user)
+ return can_shoot() && user.can_cast_magic(antimagic_flags)
+
/obj/item/gun/magic/vv_edit_var(var_name, var_value)
. = ..()
switch(var_name)
diff --git a/code/modules/projectiles/guns/magic/staff.dm b/code/modules/projectiles/guns/magic/staff.dm
index b1d664a6271..2a912988c05 100644
--- a/code/modules/projectiles/guns/magic/staff.dm
+++ b/code/modules/projectiles/guns/magic/staff.dm
@@ -31,6 +31,7 @@
/obj/item/gun/magic/staff/proc/on_intruder_use(mob/living/user, atom/target)
return TRUE
+/// Turns mobs into other mobs
/obj/item/gun/magic/staff/change
name = "staff of change"
desc = "An artefact that spits bolts of coruscating energy which cause the target's very form to reshape itself."
@@ -53,15 +54,27 @@
to_chat(user, span_hypnophrase("You don't feel strong enough to properly wield this staff!"))
balloon_alert(user, "you feel weak holding this staff")
-/obj/item/gun/magic/staff/change/on_intruder_use(mob/living/user, atom/target)
+/// Transforms the user
+/obj/item/gun/magic/staff/change/proc/transform_self(mob/living/user)
user.dropItemToGround(src, TRUE)
var/wabbajack_into = preset_wabbajack_type || pick(WABBAJACK_MONKEY, WABBAJACK_HUMAN, WABBAJACK_ANIMAL)
var/mob/living/new_body = user.wabbajack(wabbajack_into, preset_wabbajack_changeflag)
if(!new_body)
return
-
balloon_alert(new_body, "wabbajack, wabbajack!")
+ return new_body
+/obj/item/gun/magic/staff/change/on_intruder_use(mob/living/user, atom/target)
+ transform_self(user)
+
+/obj/item/gun/magic/staff/change/do_suicide(mob/living/user)
+ playsound(loc, fire_sound, 50, TRUE, -1)
+ var/mob/living/transformed = transform_self(user)
+ transformed.death()
+ transformed.set_suicide(TRUE)
+ return MANUAL_SUICIDE
+
+/// Brings objects to life
/obj/item/gun/magic/staff/animate
name = "staff of animation"
desc = "An artefact that spits bolts of life-force which causes objects which are hit by it to animate and come to life! This magic doesn't affect machines."
@@ -71,6 +84,36 @@
inhand_icon_state = "staffofanimation"
school = SCHOOL_EVOCATION
+/obj/item/gun/magic/staff/animate/do_suicide(mob/living/user)
+ user.Stun(20 SECONDS, ignore_canstun = TRUE)
+ var/list/my_shit = user.unequip_everything()
+ my_shit -= src
+ user.put_in_active_hand(src) // Keep this one for now
+ charges++ // We already subtracted one
+ user.Paralyze(2 SECONDS, ignore_canstun = TRUE) // We have at most 6 charges so this is slightly longer than necessary
+ while (length(my_shit) && charges > 0)
+ if(QDELETED(user) || user.stat == DEAD)
+ break
+ charges--
+ playsound(loc, fire_sound, 50, TRUE, -1)
+ var/obj/item/my_thing = pop(my_shit)
+ user.dropItemToGround(my_thing)
+ var/mob/living/angry_thing = my_thing.animate_atom_living()
+ angry_thing.ai_controller?.set_blackboard_key(BB_BASIC_MOB_CURRENT_TARGET, user)
+ angry_thing.ai_controller?.set_blackboard_key(BB_TARGET_MINIMUM_STAT, HARD_CRIT)
+ angry_thing.ai_controller?.ai_interact(user, combat_mode = TRUE)
+ user.apply_damage(35, BRUTE, forced = TRUE) // Mimics are not actually very strong so we pretend that it just bit us so we die faster, at least 3 charges & worn items should do it
+ sleep(0.25 SECONDS)
+
+ if (QDELETED(user))
+ return MANUAL_SUICIDE
+ if (user.stat == CONSCIOUS)
+ return SHAME
+ if (user.stat != DEAD)
+ user.death() // If you got put into crit by the mobs we'll finish you off
+ return MANUAL_SUICIDE
+
+/// Heals people and even raises the dead
/obj/item/gun/magic/staff/healing
name = "staff of healing"
desc = "An artefact that spits bolts of restoring magic which can remove ailments of all kinds and even raise the dead."
@@ -115,9 +158,18 @@
healing_beam.LoseTarget()
return ..()
-/obj/item/gun/magic/staff/healing/handle_suicide() //Stops people trying to commit suicide to heal themselves
- return
+/obj/item/gun/magic/staff/healing/handle_suicide(mob/living/carbon/human/user, mob/living/carbon/human/target, params, bypass_timer)
+ return //Stops people clicking on themselves for self-healing
+/obj/item/gun/magic/staff/healing/do_suicide(mob/living/user)
+ playsound(loc, fire_sound, 50, TRUE, -1)
+ if(user.mob_biotypes & MOB_UNDEAD)
+ user.dust(drop_items = TRUE)
+ return MANUAL_SUICIDE
+ user.visible_message(span_suicide("...but nothing happens."))
+ return SHAME
+
+/// Does random shit when fired
/obj/item/gun/magic/staff/chaos
name = "staff of chaos"
desc = "An artefact that spits bolts of chaotic magic that can potentially do anything."
@@ -127,7 +179,7 @@
inhand_icon_state = "staffofchaos"
max_charges = 10
recharge_rate = 2
- no_den_usage = 1
+ no_den_usage = TRUE
school = SCHOOL_FORBIDDEN //this staff is evil. okay? it just is. look at this projectile type list. this is wrong.
/// List of all projectiles we can fire from our staff.
@@ -173,6 +225,18 @@
process_fire(user, user, FALSE)
return FALSE
+/obj/item/gun/magic/staff/chaos/do_suicide(mob/living/user)
+ charges++ // We already subtracted one
+ for (var/i in 1 to 5)
+ if (!charges || user.stat == DEAD || QDELETED(user))
+ break
+ playsound(loc, fire_sound, 50, TRUE, -1)
+ process_fire(user, user, FALSE)
+ charges--
+ sleep(0.25 SECONDS)
+
+ return FIRELOSS
+
/**
* Staff of chaos given to the wizard upon completing a cheesy grand ritual. Is completely evil and if something
* breaks, it's completely intended. Fuck off.
@@ -212,6 +276,7 @@
/obj/projectile/plasma,
) //if you ever try to expand this list, avoid adding bullets/energy projectiles, this ain't supposed to be a gun... unless it's funny
+/// Creates and opens doors
/obj/item/gun/magic/staff/door
name = "staff of door creation"
desc = "An artefact that spits bolts of transformative magic that can create doors in walls."
@@ -221,9 +286,22 @@
inhand_icon_state = "staffofdoor"
max_charges = 10
recharge_rate = 2
- no_den_usage = 1
+ no_den_usage = TRUE
school = SCHOOL_TRANSMUTATION
+/obj/item/gun/magic/staff/door/do_suicide(mob/living/user)
+ . = ..()
+ var/obj/machinery/door/airlock/material/door = new(user.drop_location())
+ door.set_custom_materials(list(GET_MATERIAL_REF(/datum/material/meat) = SHEET_MATERIAL_AMOUNT))
+ door.update_appearance(updates = UPDATE_ICON)
+ door.name = user.real_name
+ addtimer(CALLBACK(door, TYPE_PROC_REF(/obj/machinery/door, open)), 1.5 SECONDS)
+ user.drop_everything()
+ user.ghostize()
+ qdel(user)
+ return MANUAL_SUICIDE
+
+/// Makes people slip really hard
/obj/item/gun/magic/staff/honk
name = "staff of the honkmother"
desc = "Honk."
@@ -235,6 +313,17 @@
recharge_rate = 8
school = SCHOOL_EVOCATION
+/obj/item/gun/magic/staff/honk/do_suicide(mob/living/user)
+ . = ..()
+ new /obj/effect/decal/cleanable/food/pie_smudge(user.drop_location())
+ user.AddComponent(\
+ /datum/component/face_decal/splat,\
+ icon_state = "creampie",\
+ layers = EXTERNAL_FRONT,\
+ )
+ return SHAME
+
+/// Dismembers people, and is a passable melee weapon
/obj/item/gun/magic/staff/spellblade
name = "spellblade"
desc = "A deadly combination of laziness and bloodlust, this blade allows the user to dismember their enemies without all the hard work of actually swinging the sword."
@@ -268,6 +357,18 @@
final_block_chance = 0 //Don't bring a sword to a gunfight, and also you aren't going to really block someone full body tackling you with a sword. Or a road roller, if one happened to hit you.
return ..()
+/obj/item/gun/magic/staff/spellblade/do_suicide(mob/living/user)
+ . = ..()
+ if (!iscarbon(user))
+ return BRUTELOSS
+ var/mob/living/carbon/suicider = user
+ for (var/obj/item/bodypart/limb in suicider.bodyparts)
+ limb.dismember(BRUTE, silent = FALSE, wounding_type = WOUND_SLASH)
+ sleep(0.25 SECONDS)
+
+ return BRUTELOSS
+
+/// Welds people into flying lockers
/obj/item/gun/magic/staff/locker
name = "staff of the locker"
desc = "An artefact that expels encapsulating bolts, for incapacitating thy enemy."
@@ -280,8 +381,15 @@
recharge_rate = 4
school = SCHOOL_TRANSMUTATION //in a way
-//yes, they don't have sounds. they're admin staves, and their projectiles will play the chaos bolt sound anyway so why bother?
+/obj/item/gun/magic/staff/locker/do_suicide(mob/living/user)
+ . = ..()
+ var/obj/structure/closet/decay/locker = new(user.drop_location())
+ locker.insert(user)
+ locker.welded = TRUE
+ locker.update_appearance(UPDATE_ICON_STATE)
+ return BRUTELOSS
+/// Makes targets "fly" by throwing them away
/obj/item/gun/magic/staff/flying
name = "staff of flying"
desc = "An artefact that spits bolts of graceful magic that can make something fly."
@@ -292,6 +400,13 @@
worn_icon_state = "flightstaff"
school = SCHOOL_EVOCATION
+/obj/item/gun/magic/staff/flying/do_suicide(mob/living/user)
+ . = ..()
+ var/atom/throw_target = get_edge_target_turf(user, pick(GLOB.alldirs))
+ user.throw_at(throw_target, 200, 4)
+ return BRUTELOSS
+
+/// Scrambles languages
/obj/item/gun/magic/staff/babel
name = "staff of babel"
desc = "An artefact that spits bolts of confusion magic that can make something depressed and incoherent."
@@ -302,6 +417,13 @@
worn_icon_state = "babelstaff"
school = SCHOOL_FORBIDDEN //evil
+/obj/item/gun/magic/staff/babel/do_suicide(mob/living/user)
+ . = ..()
+ process_fire(user, user, FALSE)
+ user.say("I wish I was dead.", forced = "failed babel staff suicide")
+ return SHAME
+
+/// Deals damage to the target and recharges their spells if they have any
/obj/item/gun/magic/staff/necropotence
name = "staff of necropotence"
desc = "An artefact that spits bolts of death magic that can repurpose the soul."
@@ -312,6 +434,15 @@
worn_icon_state = "necrostaff"
school = SCHOOL_NECROMANCY //REALLY evil
+/obj/item/gun/magic/staff/necropotence/do_suicide(mob/living/user)
+ . = ..()
+ user.unequip_everything()
+ var/obj/item/soulstone/anybody/stone = new(user.drop_location())
+ stone.capture_soul(user, user = null, forced = TRUE)
+ user.death()
+ return MANUAL_SUICIDE
+
+/// Asks a ghost to start playing as the poor victim
/obj/item/gun/magic/staff/wipe
name = "staff of possession"
desc = "An artefact that spits bolts of mind-unlocking magic that can let ghosts invade the victim's mind."
@@ -322,6 +453,12 @@
worn_icon_state = "wipestaff"
school = SCHOOL_FORBIDDEN //arguably the worst staff in the entire game effect wise
+/obj/item/gun/magic/staff/wipe/do_suicide(mob/living/user)
+ . = ..()
+ process_fire(user, user, FALSE)
+ return MANUAL_SUICIDE_NONLETHAL // Someone else is you now
+
+/// Makes the target really small
/obj/item/gun/magic/staff/shrink
name = "staff of shrinking"
desc = "An artefact that spits bolts of tiny magic that makes things small. It's easily mistaken for a wand."
@@ -335,3 +472,15 @@
school = SCHOOL_TRANSMUTATION
slot_flags = NONE //too small to wear on your back
w_class = WEIGHT_CLASS_NORMAL //but small enough for a bag
+
+/obj/item/gun/magic/staff/shrink/do_suicide(mob/living/user)
+ . = ..()
+ playsound(user, fire_sound, 50, TRUE)
+ user.unequip_everything()
+ user.visible_message(span_suicide("[user] shrinks into nothing!"), span_suicide("You shrink into nothing!"))
+ user.Stun(20 SECONDS, ignore_canstun = TRUE)
+ user.set_suicide(TRUE)
+ user.ghostize()
+ animate(user, transform = matrix() * 0, time = 1 SECONDS)
+ QDEL_IN(user, 1 SECONDS)
+ return MANUAL_SUICIDE
diff --git a/code/modules/projectiles/guns/magic/wand.dm b/code/modules/projectiles/guns/magic/wand.dm
index 6f59998ba61..f7ff0ddf2aa 100644
--- a/code/modules/projectiles/guns/magic/wand.dm
+++ b/code/modules/projectiles/guns/magic/wand.dm
@@ -9,16 +9,19 @@
righthand_file = 'icons/mob/inhands/items_righthand.dmi'
base_icon_state = "nothingwand"
w_class = WEIGHT_CLASS_SMALL
- can_charge = FALSE
+ self_charging = FALSE
max_charges = 100 //100, 50, 50, 34 (max charge distribution by 25%ths)
+ /// If true, we have a 25% chance of listed max charges, 50% chance of 1/2 max charges, 25% chance of 1/3 max charges
var/variable_charges = TRUE
/obj/item/gun/magic/wand/Initialize(mapload)
- if(prob(75) && variable_charges) //25% chance of listed max charges, 50% chance of 1/2 max charges, 25% chance of 1/3 max charges
- if(prob(33))
- max_charges = CEILING(max_charges / 3, 1)
- else
- max_charges = CEILING(max_charges / 2, 1)
+ if (!variable_charges || prob(25))
+ return ..()
+
+ if(prob(33)) // 33% of the remaining 75% so another 25%
+ max_charges = CEILING(max_charges / 3, 1)
+ else
+ max_charges = CEILING(max_charges / 2, 1)
return ..()
/obj/item/gun/magic/wand/examine(mob/user)
@@ -32,7 +35,7 @@
/obj/item/gun/magic/wand/attack(atom/target, mob/living/user)
if(target == user)
return
- ..()
+ return ..()
/obj/item/gun/magic/wand/try_fire_gun(atom/target, mob/living/user, params)
if(!charges)
@@ -52,16 +55,17 @@
update_appearance()
return .
-/obj/item/gun/magic/wand/proc/zap_self(mob/living/user)
+/// Called if we poke ourselves with the wand
+/obj/item/gun/magic/wand/proc/zap_self(mob/living/user, suicide = FALSE)
user.visible_message(span_danger("[user] zaps [user.p_them()]self with [src]."))
playsound(user, fire_sound, 50, TRUE)
user.log_message("zapped [user.p_them()]self with a [src]", LOG_ATTACK)
+/obj/item/gun/magic/wand/do_suicide(mob/living/user)
+ zap_self(user, suicide = TRUE)
+ return FIRELOSS
-/////////////////////////////////////
-//WAND OF DEATH
-/////////////////////////////////////
-
+/// Wand which kills people and heals skeletons
/obj/item/gun/magic/wand/death
name = "wand of death"
desc = "This deadly wand overwhelms the victim's body with pure energy, slaying them without fail."
@@ -72,34 +76,38 @@
base_icon_state = "deathwand"
max_charges = 3 //3, 2, 2, 1
-/obj/item/gun/magic/wand/death/zap_self(mob/living/user)
- ..()
+/obj/item/gun/magic/wand/death/zap_self(mob/living/user, suicide = FALSE)
+ . = ..()
charges--
if(user.can_block_magic())
user.visible_message(span_warning("[src] has no effect on [user]!"))
return
if(isliving(user))
- var/mob/living/L = user
- if(L.mob_biotypes & MOB_UNDEAD) //negative energy heals the undead
+ if(user.mob_biotypes & MOB_UNDEAD) //negative energy heals the undead
user.revive(ADMIN_HEAL_ALL, force_grab_ghost = TRUE) // This heals suicides
- to_chat(user, span_notice("You feel great!"))
+ if (!suicide)
+ to_chat(user, span_notice("You feel great!"))
return
to_chat(user, span_warning("You irradiate yourself with pure negative energy! \
[pick("Do not pass go. Do not collect 200 zorkmids.","You feel more confident in your spell casting skills.","You die...","Do you want your possessions identified?")]"))
user.death(FALSE)
+/obj/item/gun/magic/wand/death/do_suicide(mob/living/user)
+ . = ..()
+ if (user.stat == DEAD)
+ return MANUAL_SUICIDE
+ user.visible_message(span_suicide("...but if anything [user.p_they()] look healthier than before."))
+ return SHAME
+
/obj/item/gun/magic/wand/death/debug
desc = "In some obscure circles, this is known as the 'cloning tester's friend'."
max_charges = 500
variable_charges = FALSE
- can_charge = TRUE
+ self_charging = TRUE
recharge_rate = 1
-/////////////////////////////////////
-//WAND OF HEALING
-/////////////////////////////////////
-
+/// Wand which kills skeletons and heals people
/obj/item/gun/magic/wand/resurrection
name = "wand of healing"
desc = "This wand uses healing magics to heal and revive. They are rarely utilized within the Wizard Federation for some reason."
@@ -110,7 +118,7 @@
base_icon_state = "revivewand"
max_charges = 10 //10, 5, 5, 4
-/obj/item/gun/magic/wand/resurrection/zap_self(mob/living/user)
+/obj/item/gun/magic/wand/resurrection/zap_self(mob/living/user, suicide = FALSE)
..()
charges--
if(user.can_block_magic())
@@ -125,19 +133,24 @@
user.death(FALSE)
return
user.revive(ADMIN_HEAL_ALL, force_grab_ghost = TRUE) // This heals suicides
- to_chat(user, span_notice("You feel great!"))
+ if (!suicide)
+ to_chat(user, span_notice("You feel great!"))
+
+/obj/item/gun/magic/wand/resurrection/do_suicide(mob/living/user)
+ . = ..()
+ if (user.stat == DEAD)
+ return MANUAL_SUICIDE
+ user.visible_message(span_suicide("...but if anything [user.p_they()] look healthier than before."))
+ return SHAME
/obj/item/gun/magic/wand/resurrection/debug //for testing
desc = "Is it possible for something to be even more powerful than regular magic? This wand is."
max_charges = 500
variable_charges = FALSE
- can_charge = TRUE
+ self_charging = TRUE
recharge_rate = 1
-/////////////////////////////////////
-//WAND OF POLYMORPH
-/////////////////////////////////////
-
+/// Wand which turns mobs into other mobs
/obj/item/gun/magic/wand/polymorph
name = "wand of polymorph"
desc = "This wand is attuned to chaos and will radically alter the victim's form."
@@ -148,16 +161,27 @@
fire_sound = 'sound/effects/magic/staff_change.ogg'
max_charges = 10 //10, 5, 5, 4
-/obj/item/gun/magic/wand/polymorph/zap_self(mob/living/user)
+/obj/item/gun/magic/wand/polymorph/zap_self(mob/living/user, suicide = FALSE)
. = ..() //because the user mob ceases to exists by the time wabbajack fully resolves
-
user.wabbajack()
charges--
-/////////////////////////////////////
-//WAND OF TELEPORTATION
-/////////////////////////////////////
+/obj/item/gun/magic/wand/polymorph/do_suicide(mob/living/user)
+ var/static/list/corpse_types = list(
+ /obj/effect/decal/cleanable/insectguts,
+ /obj/item/food/deadmouse,
+ /obj/item/trash/bee,
+ )
+ playsound(loc, fire_sound, 50, TRUE, -1)
+ var/corpse_path = pick(corpse_types)
+ var/atom/corpse = new corpse_path(user.drop_location())
+ corpse.name = user.real_name
+ user.unequip_everything()
+ user.ghostize()
+ qdel(user)
+ return MANUAL_SUICIDE
+/// Wand of go somewhere else
/obj/item/gun/magic/wand/teleport
name = "wand of teleportation"
desc = "This wand will wrench targets through space and time to move them somewhere else."
@@ -169,14 +193,45 @@
max_charges = 10 //10, 5, 5, 4
no_den_usage = TRUE
-/obj/item/gun/magic/wand/teleport/zap_self(mob/living/user)
+/obj/item/gun/magic/wand/teleport/zap_self(mob/living/user, suicide = FALSE)
if(do_teleport(user, user, 10, channel = TELEPORT_CHANNEL_MAGIC))
var/datum/effect_system/fluid_spread/smoke/smoke = new
smoke.set_up(3, holder = src, location = user.loc)
smoke.start()
charges--
- ..()
+ return ..()
+/obj/item/gun/magic/wand/teleport/do_suicide(mob/living/user)
+ playsound(loc, fire_sound, 50, TRUE, -1)
+ var/datum/effect_system/fluid_spread/smoke/smoke = new
+ smoke.set_up(3, holder = src, location = user.loc)
+ smoke.start()
+ if (!iscarbon(user))
+ return SHAME
+
+ var/mob/living/carbon/suicider = user
+ var/obj/item/teleport_part = suicider.get_organ_slot(ORGAN_SLOT_BRAIN)
+ if (!teleport_part)
+ teleport_part = suicider.get_bodypart(BODY_ZONE_HEAD)
+ if (!teleport_part)
+ return SHAME
+
+ var/turf/destination = user.drop_location() // Grab this first in case moving the brain out dusts you or something
+
+ if (isorgan(teleport_part))
+ var/obj/item/organ/brain = teleport_part
+ brain.Remove(user, special = FALSE)
+ else
+ var/obj/item/bodypart/head = teleport_part
+ head.dismember(BRUTE)
+
+ teleport_part.forceMove(destination)
+ do_teleport(teleport_part, destination, 10, channel = TELEPORT_CHANNEL_MAGIC)
+ if (user.stat != DEAD)
+ return SHAME
+ return MANUAL_SUICIDE
+
+/// Wand of go somewhere else which is safe-ish
/obj/item/gun/magic/wand/safety
name = "wand of safety"
desc = "This wand will use the lightest of bluespace currents to gently place the target somewhere safe."
@@ -188,7 +243,7 @@
max_charges = 10 //10, 5, 5, 4
no_den_usage = FALSE
-/obj/item/gun/magic/wand/safety/zap_self(mob/living/user)
+/obj/item/gun/magic/wand/safety/zap_self(mob/living/user, suicide = FALSE)
var/turf/origin = get_turf(user)
var/turf/destination = find_safe_turf(extended_safety_checks = TRUE)
@@ -197,20 +252,21 @@
var/datum/effect_system/fluid_spread/smoke/smoke = new
smoke.set_up(0, holder = src, location = t)
smoke.start()
- ..()
+ return ..()
+
+/obj/item/gun/magic/wand/safety/do_suicide(mob/living/user)
+ . = ..()
+ return SHAME // It's a safety wand sorry
/obj/item/gun/magic/wand/safety/debug
desc = "This wand has 'find_safe_turf()' engraved into its blue wood. Perhaps it's a secret message?"
max_charges = 500
variable_charges = FALSE
- can_charge = TRUE
+ self_charging = TRUE
recharge_rate = 1
-/////////////////////////////////////
-//WAND OF DOOR CREATION
-/////////////////////////////////////
-
+/// Wand of making doors
/obj/item/gun/magic/wand/door
name = "wand of door creation"
desc = "This particular wand can create doors in any wall for the unscrupulous wizard who shuns teleportation magics."
@@ -220,17 +276,35 @@
base_icon_state = "doorwand"
fire_sound = 'sound/effects/magic/staff_door.ogg'
max_charges = 20 //20, 10, 10, 7
- no_den_usage = 1
+ no_den_usage = TRUE
-/obj/item/gun/magic/wand/door/zap_self(mob/living/user)
+/obj/item/gun/magic/wand/door/zap_self(mob/living/user, suicide = FALSE)
to_chat(user, span_notice("You feel vaguely more open with your feelings."))
charges--
- ..()
+ return ..()
-/////////////////////////////////////
-//WAND OF FIREBALL
-/////////////////////////////////////
+/obj/item/gun/magic/wand/door/do_suicide(mob/living/user)
+ if (!iscarbon(user))
+ . = ..()
+ var/static/list/shared_feelings = list(
+ "I can't take it any more!!",
+ "I can't do this any more!!",
+ "I don't want to live in this world!!",
+ "I wish I was dead!!",
+ "Nothing matters to me any more!!",
+ "Someone please kill me!!",
+ "The pain is unbearable!!",
+ )
+ user.say(pick(shared_feelings), forced = "failed wand suicide")
+ return SHAME
+ playsound(loc, fire_sound, 50, TRUE, -1)
+ var/mob/living/carbon/suicider = user
+ var/obj/item/bodypart/chest = suicider.get_bodypart(BODY_ZONE_CHEST) // I think it's impossible not to have a chest so we'll just assume they have one
+ user.visible_message(span_suicide("[user]'s chest swings open like a door!"))
+ chest.dismember(BRUTE, silent = FALSE, wounding_type = WOUND_SLASH)
+ return BRUTELOSS
+/// Wand of blowing shit up
/obj/item/gun/magic/wand/fireball
name = "wand of fireball"
desc = "This wand shoots scorching balls of fire that explode into destructive flames."
@@ -241,25 +315,22 @@
base_icon_state = "firewand"
max_charges = 8 //8, 4, 4, 3
-/obj/item/gun/magic/wand/fireball/zap_self(mob/living/user)
+/obj/item/gun/magic/wand/fireball/zap_self(mob/living/user, suicide = FALSE)
..()
explosion(user, devastation_range = -1, light_impact_range = 2, flame_range = 2, flash_range = 3, adminlog = FALSE, explosion_cause = src)
charges--
-/////////////////////////////////////
-//WAND OF NOTHING
-/////////////////////////////////////
-
+/// Wand of doing fuck all
/obj/item/gun/magic/wand/nothing
name = "wand of nothing"
desc = "It's not just a stick, it's a MAGIC stick?"
ammo_type = /obj/item/ammo_casing/magic/nothing
+/obj/item/gun/magic/wand/nothing/do_suicide(mob/living/user)
+ . = ..()
+ return SHAME
-/////////////////////////////////////
-//WAND OF SHRINKING
-/////////////////////////////////////
-
+/// Wand of making things small
/obj/item/gun/magic/wand/shrink
name = "wand of shrinking"
desc = "Feel the tiny eldritch terror of an itty... bitty... head!"
@@ -271,13 +342,24 @@
no_den_usage = TRUE
w_class = WEIGHT_CLASS_TINY
-/obj/item/gun/magic/wand/shrink/zap_self(mob/living/user)
+/obj/item/gun/magic/wand/shrink/zap_self(mob/living/user, suicide = FALSE)
to_chat(user, span_notice("The world grows large..."))
charges--
user.AddComponent(/datum/component/shrink, -1) // small forever
return ..()
-// Wand of debugging
+/obj/item/gun/magic/wand/shrink/do_suicide(mob/living/user)
+ playsound(user, fire_sound, 50, TRUE)
+ user.unequip_everything()
+ user.visible_message(span_suicide("[user] shrinks into nothing!"), span_suicide("You shrink into nothing!"))
+ user.Stun(20 SECONDS, ignore_canstun = TRUE)
+ user.set_suicide(TRUE)
+ user.ghostize()
+ animate(user, transform = matrix() * 0, time = 1 SECONDS)
+ QDEL_IN(user, 1 SECONDS)
+ return MANUAL_SUICIDE
+
+// Wands of debugging
#ifdef TESTING
@@ -291,7 +373,7 @@
color = COLOR_ADMIN_PINK
max_charges = 99999
-/obj/item/gun/magic/wand/antag/zap_self(mob/living/user)
+/obj/item/gun/magic/wand/antag/zap_self(mob/living/user, suicide = FALSE)
. = ..()
var/obj/item/ammo_casing/magic/antag/casing = new ammo_type()
var/obj/projectile/magic/magic_proj = casing.projectile_type
diff --git a/code/modules/projectiles/guns/special/hand_of_midas.dm b/code/modules/projectiles/guns/special/hand_of_midas.dm
index 80aa94d31a5..863b791672d 100644
--- a/code/modules/projectiles/guns/special/hand_of_midas.dm
+++ b/code/modules/projectiles/guns/special/hand_of_midas.dm
@@ -12,7 +12,7 @@
fire_sound = 'sound/items/weapons/gun/rifle/shot.ogg'
pinless = TRUE
max_charges = 1
- can_charge = FALSE
+ self_charging = FALSE
item_flags = NEEDS_PERMIT
w_class = WEIGHT_CLASS_BULKY // Should fit on a belt.
force = 3
@@ -100,10 +100,27 @@
/obj/item/gun/magic/midas_hand/proc/check_gold_range(mob/living/user, mob/living/victim)
return IN_GIVEN_RANGE(user, victim, gold_suck_range*2)
+/obj/item/gun/magic/midas_hand/suicide_act(mob/living/user)
+ if(!ishuman(user))
+ return
+
+ var/mob/living/carbon/human/victim = user
+ victim.visible_message(span_suicide("[victim] holds the barrel of [src] to [victim.p_their()] head, lighting the fuse. It looks like [user.p_theyre()] trying to commit suicide!"))
+ if(!do_after(victim, 1.5 SECONDS))
+ return SHAME
+ playsound(src, 'sound/items/weapons/gun/rifle/shot.ogg', 75, TRUE)
+ to_chat(victim, span_danger("You don't even have the time to register the gunshot by the time your body has completely converted into a golden statue."))
+ var/newcolors = list(rgb(206, 164, 50), rgb(146, 146, 139), rgb(28,28,28), rgb(0,0,0))
+ victim.petrify(statue_timer = INFINITY, save_brain = FALSE, colorlist = newcolors)
+ playsound(victim, 'sound/effects/coin2.ogg', 75, TRUE)
+ charges = 0
+ gold_timer = 0
+ return OXYLOSS
+
/obj/item/ammo_casing/magic/midas_round
projectile_type = /obj/projectile/magic/midas_round
-
+/// Turns people into gold
/obj/projectile/magic/midas_round
name = "gold pellet"
desc = "A typical flintlock ball, save for the fact it's made of cursed Egyptian gold."
@@ -117,37 +134,18 @@
/// The gold charge in this pellet
var/gold_charge = 0
-
/obj/projectile/magic/midas_round/fire(setAngle)
/// Transfer the gold energy to our bullet
var/obj/item/gun/magic/midas_hand/my_gun = fired_from
gold_charge = my_gun.gold_timer
my_gun.gold_timer = 0
- ..()
+ return ..()
// Gives human targets Midas Blight.
/obj/projectile/magic/midas_round/on_hit(atom/target, blocked = 0, pierce_hit)
. = ..()
- if(ishuman(target))
- var/mob/living/carbon/human/my_guy = target
- if(isskeleton(my_guy)) // No cheap farming
- return
+ if(!ishuman(target))
+ return
+ var/mob/living/carbon/human/my_guy = target
+ if(!isskeleton(my_guy)) // No cheap farming
my_guy.apply_status_effect(/datum/status_effect/midas_blight, min(30 SECONDS, round(gold_charge, 0.2))) // 100u gives 10 seconds
- return
-
-/obj/item/gun/magic/midas_hand/suicide_act(mob/living/user)
- if(!ishuman(user))
- return
-
- var/mob/living/carbon/human/victim = user
- victim.visible_message(span_suicide("[victim] holds the barrel of [src] to [victim.p_their()] head, lighting the fuse. It looks like [user.p_theyre()] trying to commit suicide!"))
- if(!do_after(victim, 1.5 SECONDS))
- return
- playsound(src, 'sound/items/weapons/gun/rifle/shot.ogg', 75, TRUE)
- to_chat(victim, span_danger("You don't even have the time to register the gunshot by the time your body has completely converted into a golden statue."))
- var/newcolors = list(rgb(206, 164, 50), rgb(146, 146, 139), rgb(28,28,28), rgb(0,0,0))
- victim.petrify(statue_timer = INFINITY, save_brain = FALSE, colorlist = newcolors)
- playsound(victim, 'sound/effects/coin2.ogg', 75, TRUE)
- charges = 0
- gold_timer = 0
- return OXYLOSS
diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm
index 54791311f9d..33d8e98b373 100644
--- a/code/modules/projectiles/projectile/magic.dm
+++ b/code/modules/projectiles/projectile/magic.dm
@@ -27,6 +27,7 @@
visible_message(span_warning("[src] fizzles on contact with [plant_tray]!"))
return PROJECTILE_DELETE_WITHOUT_HITTING
+/// Straight up kills you, unless you're undead
/obj/projectile/magic/death
name = "bolt of death"
icon_state = "pulse1_bl"
@@ -53,6 +54,7 @@
plant_tray.set_weedlevel(0) // even the weeds perish
plant_tray.plantdies()
+/// Brings you back from the dead or makes you back into the dead if you're undead
/obj/projectile/magic/resurrection
name = "bolt of resurrection"
icon_state = "ion"
@@ -79,6 +81,7 @@
return
plant_tray.set_plant_health(plant_tray.myseed.endurance, forced = TRUE)
+/// Teleports you somewhere randomly within range
/obj/projectile/magic/teleport
name = "bolt of teleportation"
icon_state = "bluespace"
@@ -100,6 +103,7 @@
smoke.set_up(smoke_range, holder = src, location = stuff.loc) //Smoke drops off if a lot of stuff is moved for the sake of sanity
smoke.start()
+/// Teleports you somewhere on the station where the local conditions won't kill you
/obj/projectile/magic/safety
name = "bolt of safety"
icon_state = "bluespace"
@@ -118,6 +122,7 @@
smoke.set_up(0, holder = src, location = t)
smoke.start()
+/// Turns walls into doors, or opens doors
/obj/projectile/magic/door
name = "bolt of door creation"
icon_state = "energy"
@@ -144,6 +149,7 @@
A.unlock()
D.open()
+/// Turns mobs into other mobs, or plants into other plants
/obj/projectile/magic/change
name = "bolt of change"
icon_state = "ice_1"
@@ -166,6 +172,7 @@
return
plant_tray.polymorph()
+/// Makes objects come to life
/obj/projectile/magic/animate
name = "bolt of animation"
icon_state = "red_1"
@@ -176,10 +183,11 @@
if(!is_type_in_typecache(target, GLOB.animatable_blacklist))
target.animate_atom_living(firer)
-///proc to animate the target into a living creature
+///proc to animate the target into a living creature, should return the mob if possible
/atom/proc/animate_atom_living(mob/living/owner)
return
+/// Slices you
/obj/projectile/magic/spellblade
name = "blade energy"
icon_state = "lavastaff"
@@ -187,6 +195,7 @@
damage_type = BURN
dismemberment = 50
+/// Generic magic bullet
/obj/projectile/magic/arcane_barrage
name = "arcane bolt"
icon_state = "arcane_barrage"
@@ -194,6 +203,7 @@
damage_type = BURN
hitsound = 'sound/items/weapons/barragespellhit.ogg'
+/// Welds targets inside lockers, and throws the locker
/obj/projectile/magic/locker
name = "locker bolt"
icon_state = "locker"
@@ -244,8 +254,9 @@
AM.forceMove(get_turf(src))
. = ..()
+/// Magic locker which breaks itself open after a while
/obj/structure/closet/decay
- breakout_time = 600
+ breakout_time = 1 MINUTES
icon_welded = null
icon_state = "cursed"
paint_jobs = null
@@ -281,6 +292,7 @@
dump_contents()
qdel(src)
+/// Throws the target far away
/obj/projectile/magic/flying
name = "bolt of flying"
icon_state = "flight"
@@ -291,6 +303,7 @@
var/atom/throw_target = get_edge_target_turf(target, angle2dir(angle))
target.throw_at(throw_target, 200, 4)
+/// Marks you for death, rewards the caster if they kill you
/obj/projectile/magic/bounty
name = "bolt of bounty"
icon_state = "bounty"
@@ -300,6 +313,7 @@
if(isliving(target))
target.apply_status_effect(/datum/status_effect/bounty, firer)
+/// Makes whatever it hits immune to magic, except for the magic that makes them immune to magic
/obj/projectile/magic/antimagic
name = "bolt of antimagic"
icon_state = "antimagic"
@@ -309,6 +323,7 @@
if(istype(target))
target.apply_status_effect(/datum/status_effect/song/antimagic)
+/// Throws the target at the caster
/obj/projectile/magic/fetch
name = "bolt of fetching"
icon_state = "fetch"
@@ -319,6 +334,7 @@
var/atom/throw_target = get_edge_target_turf(target, get_dir(target, firer))
target.throw_at(throw_target, 200, 4)
+/// Scrambles the languages of the target
/obj/projectile/magic/babel
name = "bolt of babel"
icon_state = "babel"
@@ -329,6 +345,7 @@
if(curse_of_babel(target))
target.add_mood_event("curse_of_babel", /datum/mood_event/tower_of_babel)
+/// Hurts the target and uses their life energy to recharge the spells they probably don't have
/obj/projectile/magic/necropotence
name = "bolt of necropotence"
icon_state = "necropotence"
@@ -346,6 +363,7 @@
qdel(tap)
+/// Puts someone else in control of the target
/obj/projectile/magic/wipe
name = "bolt of possession"
icon_state = "wipe"
@@ -435,6 +453,7 @@
QDEL_IN(trail_effect, trail_lifespan)
COOLDOWN_START(src, trail_cooldown, trail_lifespan)
+/// Arcs a chain of lightning from hit targets
/obj/projectile/magic/aoe/lightning
name = "lightning bolt"
icon_state = "tesla_projectile" //Better sprites are REALLY needed and appreciated!~
@@ -469,11 +488,12 @@
zap_range = 4
zap_flags = ZAP_MOB_DAMAGE | ZAP_OBJ_DAMAGE | ZAP_LOW_POWER_GEN
+/// Classic exploding fireball
/obj/projectile/magic/fireball
name = "bolt of fireball"
icon_state = "fireball"
damage = 10
- damage_type = BRUTE
+ damage_type = BURN
/// Heavy explosion range of the fireball
var/exp_heavy = 0
@@ -505,6 +525,7 @@
explosion_cause = src,
)
+/// Slow moving, homing, stunning projectile
/obj/projectile/magic/aoe/magic_missile
name = "magic missile"
icon_state = "magicm"
@@ -523,6 +544,7 @@
color = "red" //Looks more culty this way
range = 10
+/// Delivers a powerful slap and converts turfs to cult turfs
/obj/projectile/magic/aoe/juggernaut
name = "Gauntlet Echo"
icon_state = "cultfist"
@@ -551,7 +573,7 @@
new /obj/effect/temp_visual/cult/turf/floor(get_turf(adjacent_object))
//still magic related, but a different path
-
+/// Makes you cold
/obj/projectile/temp/chill
name = "bolt of chills"
icon_state = "ice_2"
@@ -559,9 +581,11 @@
armour_penetration = 100
temperature = -200 // Cools you down greatly per hit
+/// Doesn't do anything
/obj/projectile/magic/nothing
name = "bolt of nothing"
+/// Homing projectile
/obj/projectile/magic/spellcard
name = "enchanted card"
desc = "A piece of paper enchanted to give it extreme durability and stiffness, along with a very hot burn to anyone unfortunate enough to get hit by a charged one."
@@ -570,7 +594,7 @@
damage = 2
antimagic_charge_cost = 0 // since the cards gets spammed like a shotgun
-//a shrink ray that shrinks stuff, which grows back after a short while.
+/// a shrink ray that shrinks stuff, which grows back after a short while.
/obj/projectile/magic/shrink
name = "shrink ray"
icon_state = "blue_laser"