diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index eead73d666b..c6430d4654f 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -152,6 +152,7 @@
#define CLICK_CD_MELEE 8
#define CLICK_CD_RANGE 4
+#define CLICK_CD_CLICK_ABILITY 6
#define CLICK_CD_BREAKOUT 100
#define CLICK_CD_HANDCUFFED 10
#define CLICK_CD_RESIST 20
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index e53f4a1f432..c4e2e6eb515 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -1180,7 +1180,7 @@
special_role = null
current << "Your infernal link has been severed! You are no longer a devil!"
RemoveSpell(/obj/effect/proc_holder/spell/targeted/infernal_jaunt)
- RemoveSpell(/obj/effect/proc_holder/spell/dumbfire/fireball/hellish)
+ RemoveSpell(/obj/effect/proc_holder/spell/fireball/hellish)
RemoveSpell(/obj/effect/proc_holder/spell/targeted/summon_contract)
RemoveSpell(/obj/effect/proc_holder/spell/targeted/summon_pitchfork)
message_admins("[key_name_admin(usr)] has de-devil'ed [current].")
diff --git a/code/game/gamemodes/antag_spawner.dm b/code/game/gamemodes/antag_spawner.dm
index d4a54fb86b3..cbc03db8e52 100644
--- a/code/game/gamemodes/antag_spawner.dm
+++ b/code/game/gamemodes/antag_spawner.dm
@@ -75,7 +75,7 @@
switch(type)
if("destruction")
M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/projectile/magic_missile(null))
- M.mind.AddSpell(new /obj/effect/proc_holder/spell/dumbfire/fireball(null))
+ M.mind.AddSpell(new /obj/effect/proc_holder/spell/fireball(null))
M << "Your service has not gone unrewarded, however. Studying under [usr.real_name], you have learned powerful, destructive spells. You are able to cast magic missile and fireball."
if("bluespace")
M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/area_teleport/teleport(null))
diff --git a/code/game/gamemodes/changeling/powers/augmented_eyesight.dm b/code/game/gamemodes/changeling/powers/augmented_eyesight.dm
index f5b496cf6a7..ca45e620da4 100644
--- a/code/game/gamemodes/changeling/powers/augmented_eyesight.dm
+++ b/code/game/gamemodes/changeling/powers/augmented_eyesight.dm
@@ -7,7 +7,7 @@
helptext = "Grants us thermal vision or flash protection. We will become a lot more vulnerable to flash-based devices while thermal vision is active."
chemical_cost = 0
dna_cost = 2 //Would be 1 without thermal vision
- var/active = 0 //Whether or not vision is enhanced
+ active = 0 //Whether or not vision is enhanced
/obj/effect/proc_holder/changeling/augmented_eyesight/sting_action(mob/living/carbon/human/user)
if(!istype(user))
diff --git a/code/game/gamemodes/changeling/powers/strained_muscles.dm b/code/game/gamemodes/changeling/powers/strained_muscles.dm
index 94c96ad30bc..f2d4d98fccd 100644
--- a/code/game/gamemodes/changeling/powers/strained_muscles.dm
+++ b/code/game/gamemodes/changeling/powers/strained_muscles.dm
@@ -9,7 +9,7 @@
dna_cost = 1
req_human = 1
var/stacks = 0 //Increments every 5 seconds; damage increases over time
- var/active = 0 //Whether or not you are a hedgehog
+ active = 0 //Whether or not you are a hedgehog
/obj/effect/proc_holder/changeling/strained_muscles/sting_action(mob/living/carbon/user)
active = !active
diff --git a/code/game/gamemodes/devil/devilinfo.dm b/code/game/gamemodes/devil/devilinfo.dm
index d0d0429d433..b512422ef5c 100644
--- a/code/game/gamemodes/devil/devilinfo.dm
+++ b/code/game/gamemodes/devil/devilinfo.dm
@@ -297,7 +297,7 @@ var/global/list/lawlorify = list (
/datum/devilinfo/proc/give_base_spells(give_summon_contract = 0)
remove_spells()
- owner.AddSpell(new /obj/effect/proc_holder/spell/dumbfire/fireball/hellish(null))
+ owner.AddSpell(new /obj/effect/proc_holder/spell/fireball/hellish(null))
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/summon_pitchfork(null))
if(give_summon_contract)
give_summon_contract()
@@ -305,13 +305,13 @@ var/global/list/lawlorify = list (
/datum/devilinfo/proc/give_lizard_spells()
remove_spells()
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/summon_pitchfork(null))
- owner.AddSpell(new /obj/effect/proc_holder/spell/dumbfire/fireball/hellish(null))
+ owner.AddSpell(new /obj/effect/proc_holder/spell/fireball/hellish(null))
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/infernal_jaunt(null))
/datum/devilinfo/proc/give_true_spells()
remove_spells()
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/summon_pitchfork/greater(null))
- owner.AddSpell(new /obj/effect/proc_holder/spell/dumbfire/fireball/hellish(null))
+ owner.AddSpell(new /obj/effect/proc_holder/spell/fireball/hellish(null))
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/infernal_jaunt(null))
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/sintouch(null))
diff --git a/code/game/gamemodes/wizard/spellbook.dm b/code/game/gamemodes/wizard/spellbook.dm
index ee3965287d1..2c370f47da9 100644
--- a/code/game/gamemodes/wizard/spellbook.dm
+++ b/code/game/gamemodes/wizard/spellbook.dm
@@ -95,7 +95,7 @@
/datum/spellbook_entry/fireball
name = "Fireball"
- spell_type = /obj/effect/proc_holder/spell/dumbfire/fireball
+ spell_type = /obj/effect/proc_holder/spell/fireball
log_name = "FB"
/datum/spellbook_entry/magicm
@@ -738,7 +738,7 @@
return
/obj/item/weapon/spellbook/oneuse/fireball
- spell = /obj/effect/proc_holder/spell/dumbfire/fireball
+ spell = /obj/effect/proc_holder/spell/fireball
spellname = "fireball"
icon_state ="bookfireball"
desc = "This book feels warm to the touch."
diff --git a/code/modules/awaymissions/mission_code/Academy.dm b/code/modules/awaymissions/mission_code/Academy.dm
index 0c4ab1dd76a..b4b537285f7 100644
--- a/code/modules/awaymissions/mission_code/Academy.dm
+++ b/code/modules/awaymissions/mission_code/Academy.dm
@@ -121,7 +121,7 @@
wizmind.AddSpell(new /obj/effect/proc_holder/spell/targeted/ethereal_jaunt)
wizmind.AddSpell(new /obj/effect/proc_holder/spell/targeted/projectile/magic_missile)
- wizmind.AddSpell(new /obj/effect/proc_holder/spell/dumbfire/fireball)
+ wizmind.AddSpell(new /obj/effect/proc_holder/spell/fireball)
current_wizard = wizbody
diff --git a/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm b/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm
index 7b151fbc73c..5f4d11a7112 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm
@@ -11,7 +11,6 @@ Doesn't work on other aliens/AI.*/
panel = "Alien"
var/plasma_cost = 0
var/check_turf = 0
-
var/has_action = 1
var/datum/action/spell_action/alien/action = null
var/action_icon = 'icons/mob/actions.dmi'
@@ -191,31 +190,29 @@ Doesn't work on other aliens/AI.*/
name = "Spit Neurotoxin"
desc = "Spits neurotoxin at someone, paralyzing them for a short time."
action_icon_state = "alien_neurotoxin_0"
- var/active = 0
+ active = FALSE
/obj/effect/proc_holder/alien/neurotoxin/fire(mob/living/carbon/user)
+ var/message
if(active)
- user.ranged_ability = null
- user << "You empty your neurotoxin gland."
- active = 0
- else if(user.ranged_ability && user.ranged_ability != src)
- user << "You already have another aimed ability readied! Cancel it first."
- return
+ message = "You empty your neurotoxin gland."
+ remove_ranged_ability(user, message)
else
- user.ranged_ability = src
- active = 1
- user << "You prepare your neurotoxin gland. Left-click to fire at a target!"
+ message = "You prepare your neurotoxin gland. Left-click to fire at a target!"
+ add_ranged_ability(user, message)
- user.client.click_intercept = user.ranged_ability
+/obj/effect/proc_holder/alien/neurotoxin/update_icon()
action.button_icon_state = "alien_neurotoxin_[active]"
action.UpdateButtonIcon()
/obj/effect/proc_holder/alien/neurotoxin/InterceptClickOn(mob/living/carbon/user, params, atom/target)
+ if(..())
+ return
var/p_cost = 50
if(!iscarbon(user) || user.lying || user.stat)
+ remove_ranged_ability(user)
return
- user.next_click = world.time + 6
- user.face_atom(target)
+
if(user.getPlasma() < p_cost)
user << "You need at least [p_cost] plasma to spit."
return
@@ -223,7 +220,7 @@ Doesn't work on other aliens/AI.*/
var/turf/T = user.loc
var/turf/U = get_step(user, user.dir) // Get the tile infront of the move, based on their direction
if(!isturf(U) || !isturf(T))
- return 0
+ return FALSE
user.visible_message("[user] spits neurotoxin!", "You spit neurotoxin.")
var/obj/item/projectile/bullet/neurotoxin/A = new /obj/item/projectile/bullet/neurotoxin(user.loc)
@@ -233,7 +230,7 @@ Doesn't work on other aliens/AI.*/
user.newtonian_move(get_dir(U, T))
user.adjustPlasma(-p_cost)
- return 1
+ return TRUE
/obj/effect/proc_holder/alien/neurotoxin/on_lose(mob/living/carbon/user)
if(user.ranged_ability == src)
@@ -308,7 +305,7 @@ Doesn't work on other aliens/AI.*/
/obj/effect/proc_holder/alien/sneak
name = "Sneak"
desc = "Blend into the shadows to stalk your prey."
- var/active = 0
+ active = 0
action_icon_state = "alien_sneak"
diff --git a/code/modules/mob/living/simple_animal/hostile/wizard.dm b/code/modules/mob/living/simple_animal/hostile/wizard.dm
index df6a4be30be..bf5c614d637 100644
--- a/code/modules/mob/living/simple_animal/hostile/wizard.dm
+++ b/code/modules/mob/living/simple_animal/hostile/wizard.dm
@@ -29,7 +29,7 @@
loot = list(/obj/effect/mob_spawn/human/corpse/wizard,
/obj/item/weapon/staff)
- var/obj/effect/proc_holder/spell/dumbfire/fireball/fireball = null
+ var/obj/effect/proc_holder/spell/fireball/fireball = null
var/obj/effect/proc_holder/spell/targeted/turf_teleport/blink/blink = null
var/obj/effect/proc_holder/spell/targeted/projectile/magic_missile/mm = null
@@ -38,7 +38,7 @@
/mob/living/simple_animal/hostile/wizard/New()
..()
- fireball = new /obj/effect/proc_holder/spell/dumbfire/fireball
+ fireball = new /obj/effect/proc_holder/spell/fireball
fireball.clothes_req = 0
fireball.human_req = 0
fireball.player_lock = 0
@@ -62,7 +62,7 @@
if(target && next_cast < world.time)
if((get_dir(src,target) in list(SOUTH,EAST,WEST,NORTH)) && fireball.cast_check(0,src)) //Lined up for fireball
src.setDir(get_dir(src,target))
- fireball.choose_targets(src)
+ fireball.perform(list(target), user = src)
next_cast = world.time + 10 //One spell per second
return .
if(mm.cast_check(0,src))
diff --git a/code/modules/paperwork/contract.dm b/code/modules/paperwork/contract.dm
index b45217d6970..df21427279d 100644
--- a/code/modules/paperwork/contract.dm
+++ b/code/modules/paperwork/contract.dm
@@ -251,7 +251,7 @@
/obj/item/weapon/paper/contract/infernal/magic/FulfillContract(mob/living/carbon/human/user = target.current)
if(!istype(user) || !user.mind)
return -1
- user.mind.AddSpell(new /obj/effect/proc_holder/spell/dumbfire/fireball(null))
+ user.mind.AddSpell(new /obj/effect/proc_holder/spell/fireball(null))
user.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/knock(null))
return ..()
diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm
index 638b38d4faf..a94abf7243c 100644
--- a/code/modules/projectiles/projectile/magic.dm
+++ b/code/modules/projectiles/projectile/magic.dm
@@ -24,27 +24,46 @@
damage_type = BRUTE
nodamage = 0
+ //explosion values
+ var/exp_heavy = 0
+ var/exp_light = 2
+ var/exp_flash = 3
+ var/exp_fire = 2
+
/obj/item/projectile/magic/fireball/Range()
var/turf/T1 = get_step(src,turn(dir, -45))
var/turf/T2 = get_step(src,turn(dir, 45))
+ var/turf/T3 = get_step(src,dir)
var/mob/living/L = locate(/mob/living) in T1 //if there's a mob alive in our front right diagonal, we hit it.
if(L && L.stat != DEAD)
- Bump(L) //Magic Bullet #teachthecontroversy
+ Bump(L,1) //Magic Bullet #teachthecontroversy
return
L = locate(/mob/living) in T2
if(L && L.stat != DEAD)
- Bump(L)
+ Bump(L,1)
+ return
+ L = locate(/mob/living) in T3
+ if(L && L.stat != DEAD)
+ Bump(L,1)
return
..()
/obj/item/projectile/magic/fireball/on_hit(target)
. = ..()
var/turf/T = get_turf(target)
- explosion(T, -1, 0, 2, 3, 0, flame_range = 2)
+ explosion(T, -1, exp_heavy, exp_light, exp_flash, 0, flame_range = exp_fire)
if(ismob(target)) //multiple flavors of pain
var/mob/living/M = target
M.take_overall_damage(0,10) //between this 10 burn, the 10 brute, the explosion brute, and the onfire burn, your at about 65 damage if you stop drop and roll immediately
+/obj/item/projectile/magic/fireball/infernal
+ name = "infernal fireball"
+ exp_heavy = -1
+ exp_light = -1
+ exp_flash = 4
+ exp_fire= 5
+
+
/obj/item/projectile/magic/resurrection
name = "bolt of resurrection"
icon_state = "ion"
diff --git a/code/modules/spells/spell.dm b/code/modules/spells/spell.dm
index e5b58e577a4..ce77ac1c1ef 100644
--- a/code/modules/spells/spell.dm
+++ b/code/modules/spells/spell.dm
@@ -1,14 +1,44 @@
#define TARGET_CLOSEST 1
#define TARGET_RANDOM 2
+
/obj/effect/proc_holder
var/panel = "Debug"//What panel the proc holder needs to go on.
+ var/active = FALSE //Used by toggle based abilities.
var/list/spells = typesof(/obj/effect/proc_holder/spell) //needed for the badmin verb for now
-/obj/effect/proc_holder/proc/InterceptClickOn(mob/user, params, atom/A)
- return
+/obj/effect/proc_holder/proc/InterceptClickOn(mob/living/user, params, atom/A)
+ if(user.ranged_ability && user.ranged_ability != src)
+ user << "[user.ranged_ability.name] has been disabled."
+ user.ranged_ability.remove_ranged_ability(user)
+ return TRUE //TRUE for failed, FALSE for passed.
+ user.next_click = world.time + CLICK_CD_CLICK_ABILITY
+ user.face_atom(A)
+ return FALSE
+/obj/effect/proc_holder/proc/add_ranged_ability(mob/living/user, var/msg)
+ if(!user || !user.client)
+ return
+ if(user.ranged_ability && user.ranged_ability != src)
+ user << "[user.ranged_ability.name] has been replaced by [name]."
+ user.ranged_ability.remove_ranged_ability(user)
+ user.ranged_ability = src
+ user.client.click_intercept = user.ranged_ability
+ active = TRUE
+ if(msg)
+ user << msg
+ update_icon()
+
+/obj/effect/proc_holder/proc/remove_ranged_ability(mob/living/user, var/msg)
+ if(!user || !user.client ||user.ranged_ability != src) //To avoid removing the wrong ability
+ return
+ user.ranged_ability = null
+ user.client.click_intercept = null
+ active = FALSE
+ if(msg)
+ user << msg
+ update_icon()
/obj/effect/proc_holder/spell
name = "Spell"
@@ -61,10 +91,10 @@ var/list/spells = typesof(/obj/effect/proc_holder/spell) //needed for the badmin
var/critfailchance = 0
var/centcom_cancast = 1 //Whether or not the spell should be allowed on z2
- var/datum/action/spell_action/action = null
var/action_icon = 'icons/mob/actions.dmi'
var/action_icon_state = "spell_default"
var/action_background_icon_state = "bg_spell"
+ var/datum/action/spell_action/action
/obj/effect/proc_holder/spell/proc/cast_check(skipcharge = 0,mob/user = usr) //checks if the spell can be cast based on its settings; skipcharge is used when an additional cast_check is called inside the spell
diff --git a/code/modules/spells/spell_types/devil.dm b/code/modules/spells/spell_types/devil.dm
index 2622770da09..90de8e124df 100644
--- a/code/modules/spells/spell_types/devil.dm
+++ b/code/modules/spells/spell_types/devil.dm
@@ -75,7 +75,7 @@
user << "[C] seems to not be sentient. You cannot summon a contract for them."
-/obj/effect/proc_holder/spell/dumbfire/fireball/hellish
+/obj/effect/proc_holder/spell/fireball/hellish
name = "Hellfire"
desc = "This spell launches hellfire at the target."
@@ -86,18 +86,10 @@
invocation_type = "shout"
range = 2
- proj_icon_state = "fireball"
- proj_name = "a fireball"
- proj_type = /obj/effect/proc_holder/spell/turf/fireball/infernal
-
- proj_lifespan = 200
- proj_step_delay = 1
+ fireball_type = /obj/item/projectile/magic/fireball/infernal
action_background_icon_state = "bg_demon"
-/obj/effect/proc_holder/spell/turf/fireball/infernal/cast(turf/T,mob/user = usr)
- explosion(T, -1, -1, 1, 4, 0, flame_range = 5)
-
/obj/effect/proc_holder/spell/targeted/infernal_jaunt
name = "Infernal Jaunt"
desc = "Use hellfire to phase out of existence."
diff --git a/code/modules/spells/spell_types/wizard.dm b/code/modules/spells/spell_types/wizard.dm
index c24d6b52909..ad4ffe90678 100644
--- a/code/modules/spells/spell_types/wizard.dm
+++ b/code/modules/spells/spell_types/wizard.dm
@@ -250,7 +250,7 @@
duration = 300
sound="sound/magic/Blind.ogg"
-/obj/effect/proc_holder/spell/dumbfire/fireball
+/obj/effect/proc_holder/spell/fireball
name = "Fireball"
desc = "This spell fires a fireball at a target and does not require wizard garb."
@@ -261,30 +261,55 @@
invocation_type = "shout"
range = 20
cooldown_min = 20 //10 deciseconds reduction per rank
-
- proj_icon_state = "fireball"
- proj_name = "a fireball"
- proj_type = "/obj/effect/proc_holder/spell/turf/fireball"
-
- proj_lifespan = 200
- proj_step_delay = 1
-
- action_icon_state = "fireball"
+ var/fireball_type = /obj/item/projectile/magic/fireball
+ action_icon_state = "fireball0"
sound = "sound/magic/Fireball.ogg"
-/obj/effect/proc_holder/spell/turf/fireball/cast(turf/T,mob/user = usr)
- explosion(T, -1, 0, 2, 3, 0, flame_range = 2)
+ active = FALSE
-/obj/effect/proc_holder/spell/targeted/inflict_handler/fireball
- amt_dam_brute = 20
- amt_dam_fire = 25
+/obj/effect/proc_holder/spell/fireball/Click()
+ var/mob/living/user = usr
+ if(!istype(user) || !can_cast(user))
+ return
-/obj/effect/proc_holder/spell/targeted/explosion/fireball
- ex_severe = -1
- ex_heavy = -1
- ex_light = 2
- ex_flash = 5
+ var/msg
+ if(active)
+ msg = "You extinguish your fireball...for now."
+ remove_ranged_ability(user, msg)
+ else
+ msg = "Your prepare to cast your fireball spell! Left-click to cast at a target!"
+ add_ranged_ability(user, msg)
+
+/obj/effect/proc_holder/spell/fireball/update_icon()
+ action.button_icon_state = "fireball[active]"
+ action.UpdateButtonIcon()
+
+/obj/effect/proc_holder/spell/fireball/InterceptClickOn(mob/living/user, params, atom/target)
+ if(..())
+ return
+
+ if(!cast_check(0, user))
+ remove_ranged_ability(user)
+ return
+
+ var/list/targets = list(target)
+ perform(targets,user = user)
+
+/obj/effect/proc_holder/spell/fireball/cast(list/targets, mob/living/user)
+ var/target = targets[1] //There is only ever one target for fireball
+ var/turf/T = user.loc
+ var/turf/U = get_step(user, user.dir) // Get the tile infront of the move, based on their direction
+ if(!isturf(U) || !isturf(T))
+ return 0
+
+ var/obj/item/projectile/magic/fireball/FB = new fireball_type(user.loc)
+ FB.current = get_turf(user)
+ FB.preparePixelProjectile(target, get_turf(target), user)
+ FB.fire()
+ user.newtonian_move(get_dir(U, T))
+
+ return 1
/obj/effect/proc_holder/spell/aoe_turf/repulse
name = "Repulse"
@@ -315,7 +340,7 @@
if(AM == user || AM.anchored) continue
// created sparkles will disappear on their own
- PoolOrNew(sparkle_path, AM)
+ PoolOrNew(sparkle_path, AM)
throwtarget = get_edge_target_turf(user, get_dir(user, get_step_away(AM, user)))
distfromcaster = get_dist(user, AM)
if(distfromcaster == 0)
diff --git a/icons/mob/actions.dmi b/icons/mob/actions.dmi
index d41fc220901..18a190d88d3 100644
Binary files a/icons/mob/actions.dmi and b/icons/mob/actions.dmi differ