diff --git a/baystation12.dme b/baystation12.dme index 48b8f0f5092..f119f0486fc 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -58,6 +58,7 @@ #include "code\__defines\lighting.dm" #include "code\__defines\lists.dm" #include "code\__defines\machinery.dm" +#include "code\__defines\magic.dm" #include "code\__defines\mapping.dm" #include "code\__defines\materials.dm" #include "code\__defines\math_physics.dm" diff --git a/code/__defines/dcs/signals.dm b/code/__defines/dcs/signals.dm index fc0ee04b548..17620fc05c0 100644 --- a/code/__defines/dcs/signals.dm +++ b/code/__defines/dcs/signals.dm @@ -34,8 +34,10 @@ // /atom signals // /atom/movable signals -/// When an atom's Dispell() proc is called +/// When an atom's Dispell() proc is called; Passes dispell strength as argument. #define COMSIG_ATOM_MOVABLE_DISPELL "atom_dispell" +// Return value of a signal handler if dispell should be blocked +#define COMPONENT_DISPELL_BLOCKED (1 << 0) // /area signals diff --git a/code/__defines/magic.dm b/code/__defines/magic.dm new file mode 100644 index 00000000000..4f0d6971f4d --- /dev/null +++ b/code/__defines/magic.dm @@ -0,0 +1,5 @@ +// Defines for dispell strengths +#define DISPELL_WEAK 1 +#define DISPELL_MEDIUM 2 +#define DISPELL_STRONG 3 +#define DISPELL_UNSTOPPABLE 4 diff --git a/code/game/antagonist/outsider/wizard.dm b/code/game/antagonist/outsider/wizard.dm index 0bf44029cbe..96f28259567 100644 --- a/code/game/antagonist/outsider/wizard.dm +++ b/code/game/antagonist/outsider/wizard.dm @@ -18,28 +18,28 @@ GLOBAL_DATUM_INIT(wizards, /datum/antagonist/wizard, new) faction = "wizard" base_to_load = /datum/map_template/ruin/antag_spawn/wizard -/datum/antagonist/wizard/create_objectives(var/datum/mind/wizard) +/datum/antagonist/wizard/create_objectives(datum/mind/wizard) if(!..()) return - var/kill - var/escape - var/steal - var/hijack + var/kill = FALSE + var/escape = FALSE + var/steal = FALSE + var/hijack = FALSE switch(rand(1,100)) if(1 to 30) - escape = 1 - kill = 1 + escape = TRUE + kill = TRUE if(31 to 60) - escape = 1 - steal = 1 + escape = TRUE + steal = TRUE if(61 to 99) - kill = 1 - steal = 1 + kill = TRUE + steal = TRUE else - hijack = 1 + hijack = TRUE if(kill) var/datum/objective/assassinate/kill_objective = new @@ -61,16 +61,16 @@ GLOBAL_DATUM_INIT(wizards, /datum/antagonist/wizard, new) wizard.objectives |= hijack_objective return -/datum/antagonist/wizard/update_antag_mob(var/datum/mind/wizard) +/datum/antagonist/wizard/update_antag_mob(datum/mind/wizard) ..() wizard.StoreMemory("Remember: do not forget to prepare your spells.", /decl/memory_options/system) wizard.current.real_name = "[pick(GLOB.wizard_first)] [pick(GLOB.wizard_second)]" wizard.current.SetName(wizard.current.real_name) -/datum/antagonist/wizard/equip(var/mob/living/carbon/human/wizard_mob) +/datum/antagonist/wizard/equip(mob/living/carbon/human/wizard_mob) if(!..()) - return 0 + return FALSE var/outfit_type = pick(subtypesof(/decl/hierarchy/outfit/wizard)) var/decl/hierarchy/outfit/wizard_outfit = outfit_by_type(outfit_type) @@ -82,7 +82,7 @@ GLOBAL_DATUM_INIT(wizards, /datum/antagonist/wizard, new) wizard_mob.mind.mana.mana_recharge_speed = 2 wizard_mob.mind.mana.spell_points = 15 // Should allow wizard to buy 2-3 dangerous spells, or a bunch of small stuff - return 1 + return TRUE /datum/antagonist/wizard/print_player_summary() ..() @@ -107,28 +107,24 @@ GLOBAL_DATUM_INIT(wizards, /datum/antagonist/wizard, new) for(var/datum/spell/spell_to_remove in mind.learned_spells) remove_spell(spell_to_remove) -obj/item/clothing +/obj/item/clothing var/wizard_garb = FALSE -// Does this clothing slot count as wizard garb? (Combines a few checks) -/proc/is_wiz_garb(var/obj/item/clothing/C) +// Does this clothing slot count as wizard garb? +/proc/is_wiz_garb(obj/item/clothing/C) return istype(C) && C.wizard_garb -/*Checks if the wizard is wearing the proper attire. -Made a proc so this is not repeated 14 (or more) times.*/ +// Checks if the wizard is wearing the proper attire. +// Made a proc so this is not repeated 14 (or more) times. /mob/proc/wearing_wiz_garb() to_chat(src, "Silly creature, you're not a human. Only humans can cast this spell.") - return 0 + return FALSE -// Humans can wear clothes. /mob/living/carbon/human/wearing_wiz_garb() - if(!is_wiz_garb(src.wear_suit) && (!src.species.hud || (slot_wear_suit in src.species.hud.equip_slots))) - to_chat(src, "I don't feel strong enough without my robe.") - return 0 - if(!is_wiz_garb(src.shoes) && (!species.hud || (slot_shoes in src.species.hud.equip_slots))) - to_chat(src, "I don't feel strong enough without my sandals.") - return 0 - if(!is_wiz_garb(src.head) && (!species.hud || (slot_head in src.species.hud.equip_slots))) - to_chat(src, "I don't feel strong enough without my hat.") - return 0 - return 1 \ No newline at end of file + if(!is_wiz_garb(wear_suit) && (!species.hud || (slot_wear_suit in species.hud.equip_slots))) + to_chat(src, SPAN_WARNING("I don't feel strong enough without my robe.")) + return FALSE + if(!is_wiz_garb(head) && (!species.hud || (slot_head in species.hud.equip_slots))) + to_chat(src, SPAN_WARNING("I don't feel strong enough without my hat.")) + return FALSE + return TRUE diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index a623c78115e..5c831fbc8ed 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -350,6 +350,7 @@ return /// The effect of being affected by dispells, either a projectile or AOE effects -/atom/movable/proc/Dispell() - SEND_SIGNAL(src, COMSIG_ATOM_MOVABLE_DISPELL) - return +/atom/movable/proc/Dispell(dispell_strength = DISPELL_WEAK) + if(SEND_SIGNAL(src, COMSIG_ATOM_MOVABLE_DISPELL, dispell_strength) & COMPONENT_DISPELL_BLOCKED) + return FALSE + return TRUE diff --git a/code/modules/mana/mana.dm b/code/modules/mana/mana.dm index 7a144f65e7a..72db7ccd368 100644 --- a/code/modules/mana/mana.dm +++ b/code/modules/mana/mana.dm @@ -1,4 +1,4 @@ -// Stores a lot of things related to magic, not just mana +// Stores mana-related things and spell points /datum/mana var/mana_level = 10 var/mana_level_max = 10 @@ -18,6 +18,10 @@ StartRecharge() return TRUE +/datum/mana/proc/AddMana(amount = 0) + mana_level = clamp(mana_level + amount, 0, mana_level_max) + return TRUE + // Starts a "process" of recharging if we should and can /datum/mana/proc/StartRecharge() if(recharging) @@ -34,6 +38,6 @@ if(mana_level >= mana_level_max) recharging = FALSE return FALSE - mana_level = clamp(mana_level + mana_recharge_speed * 0.5, 0, mana_level_max) + AddMana(mana_recharge_speed * 0.5) addtimer(CALLBACK(src, .proc/RechargeMana), (0.5 SECONDS)) return TRUE diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 74006e3b125..62a132a326f 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -934,3 +934,28 @@ default behaviour is: /mob/living/proc/jump_layer_shift_end() jumping = FALSE reset_layer() + +// If mob has an aimed spell prepared to cast - deactivates it. +// Additionally, puts random spells on cooldown. +/mob/living/Dispell(dispell_strength = DISPELL_WEAK) + . = ..() + if(!.) + return + if(!mind || !LAZYLEN(mind.learned_spells)) + return + var/play_sound = FALSE + // It could also be non-aimed, but we should add the deactivation part to other spells then + if(istype(ranged_ability, /datum/spell/aimed)) + var/datum/spell/aimed/AS = ranged_ability + AS.remove_ranged_ability(SPAN_DANGER("[ranged_ability] has been dispelled!")) + AS.on_deactivation(src) + play_sound = TRUE + for(var/datum/spell/S in mind.learned_spells) + if(!prob(dispell_strength * 25)) + continue + S.charge_counter = S.charge_max * (rand(3, 10) * 0.1) + S.process() + to_chat(src, SPAN_WARNING("[S] has been dispelled and put on cooldown!")) + play_sound = TRUE + if(play_sound) + playsound(get_turf(src), 'sound/magic/blind.ogg', 50, TRUE) diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Other.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Other.dm index 7df464f8405..e6fa25aa7fe 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Other.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Other.dm @@ -805,3 +805,18 @@ /datum/reagent/vaccine/mix_data(list/newdata, newamount) if(istype(newdata)) src.data |= newdata.Copy() + +/datum/reagent/concentrated_mana + name = "Concentrated Mana" + description = "A mysterious liquid used by magic-fluent people to restore their internal mana reserves. \ + Can also be used in certain tools that utilize magic phenomenon." + taste_description = "cool air" + reagent_state = LIQUID + color = "#47f0ff" + +/datum/reagent/concentrated_mana/affect_blood(mob/living/carbon/human/H, alien, removed) + if(!ishuman(H)) + return + if(!H.mind || !H.mind?.mana) + return + H.mind.mana.AddMana(2) diff --git a/code/modules/research/part_replacer.dm b/code/modules/research/part_replacer.dm index 6fc0242e44b..9bb723862ad 100644 --- a/code/modules/research/part_replacer.dm +++ b/code/modules/research/part_replacer.dm @@ -29,7 +29,7 @@ if(istype(target, /obj/machinery)) var/obj/machinery/machine = target if(machine.component_attackby(src, user)) - user.Beam(machine, icon_state = "rped_upgrade", icon = 'icons/effects/effects.dmi', time = 5) + user.Beam(machine, icon_state = "rped_upgrade", time = 5) /obj/item/storage/part_replacer/bluespace name = "bluespace rapid part exchange device" diff --git a/code/modules/spellbook/_spellbook.dm b/code/modules/spellbook/_spellbook.dm index c70142fef9d..f74b07eebe0 100644 --- a/code/modules/spellbook/_spellbook.dm +++ b/code/modules/spellbook/_spellbook.dm @@ -24,6 +24,8 @@ GLOBAL_LIST_EMPTY(spells_by_categories) var/list/allowed_spells = list() /// Currently applied spell categories that will be shown; If none - all spells are shown. var/list/spell_categories = list() + /// Defines how strong the dispell must be to successfuly remove the restrictions. + var/dispell_resistance = 0 /obj/item/spellbook/Initialize() . = ..() @@ -152,10 +154,13 @@ GLOBAL_LIST_EMPTY(spells_by_categories) interact(user) // Being hit with any source of dispell releases any locks -/obj/item/spellbook/Dispell() +/obj/item/spellbook/Dispell(dispell_strength = DISPELL_WEAK) . = ..() if(!istype(owner) && !(book_flags & WIZARD_ONLY) && !(book_flags & APPRENTICE_ONLY)) return + if(dispell_resistance > dispell_strength) + visible_message(SPAN_WARNING("\The [src] repels the surrounding dispelling magic!")) + return visible_message(SPAN_NOTICE("\The [src] fizzles and sparks!")) RemoveOwner() owner = null diff --git a/code/modules/spells/_spell.dm b/code/modules/spells/_spell.dm index 02e59ae2318..b215be80c89 100644 --- a/code/modules/spells/_spell.dm +++ b/code/modules/spells/_spell.dm @@ -155,7 +155,7 @@ GLOBAL_LIST_INIT(spell_categories, list( /datum/spell/proc/Click(mob/user = usr, skipcharge = 0) // When action button is pressed if(cast_check(skipcharge, user)) choose_targets(user) - return 1 + return TRUE /datum/spell/proc/choose_targets(mob/user = usr) //depends on subtype - see targeted.dm, aoe_turf.dm, dumbfire.dm, or code in general folder return @@ -334,12 +334,12 @@ GLOBAL_LIST_INIT(spell_categories, list( if(SPELL_RECHARGE) if(charge_counter < charge_max) to_chat(user, still_recharging_msg) - return 0 + return FALSE if(SPELL_CHARGES) if(!charge_counter) to_chat(user, "[name] has no charges left.") - return 0 - return 1 + return FALSE + return TRUE /datum/spell/proc/take_charge(mob/user = user, var/skipcharge) if(!skipcharge) @@ -347,15 +347,15 @@ GLOBAL_LIST_INIT(spell_categories, list( if(SPELL_RECHARGE) charge_counter = 0 //doesn't start recharging until the targets selecting ends src.process() - return 1 + return TRUE if(SPELL_CHARGES) charge_counter-- //returns the charge if the targets selecting fails - return 1 + return TRUE if(SPELL_HOLDVAR) adjust_var(user, holder_var_type, holder_var_amount) - return 1 - return 0 - return 1 + return TRUE + return FALSE + return TRUE /datum/spell/proc/TakeMana(mob/user = user) if(!user.mind) @@ -386,25 +386,25 @@ GLOBAL_LIST_INIT(spell_categories, list( /datum/spell/proc/can_improve(upgrade_type) if(level_max[UPGRADE_TOTAL] <= ( spell_levels[UPGRADE_SPEED] + spell_levels[UPGRADE_POWER] )) //too many levels, can't do it - return 0 + return FALSE //if(upgrade_type && spell_levels[upgrade_type] && level_max[upgrade_type]) if(upgrade_type && spell_levels[upgrade_type] >= level_max[upgrade_type]) - return 0 + return FALSE - return 1 + return TRUE /datum/spell/proc/empower_spell() if(!can_improve(UPGRADE_POWER)) - return 0 + return FALSE spell_levels[UPGRADE_POWER]++ - return 1 + return TRUE /datum/spell/proc/quicken_spell() if(!can_improve(UPGRADE_SPEED)) - return 0 + return FALSE spell_levels[UPGRADE_SPEED]++ @@ -441,7 +441,7 @@ GLOBAL_LIST_INIT(spell_categories, list( /datum/spell/proc/spell_do_after(var/mob/user as mob, delay as num, var/numticks = 5) if(!user || isnull(user)) - return 0 + return FALSE var/incap_flags = INCAPACITATION_STUNNED|INCAPACITATION_RESTRAINED|INCAPACITATION_BUCKLED_FULLY|INCAPACITATION_FORCELYING if(!(spell_flags & (GHOSTCAST))) diff --git a/code/modules/spells/_spell_procs.dm b/code/modules/spells/_spell_procs.dm index 8a15f67ee6f..01054176993 100644 --- a/code/modules/spells/_spell_procs.dm +++ b/code/modules/spells/_spell_procs.dm @@ -61,8 +61,8 @@ ability_master.remove_ability(ability_master.get_ability_by_spell(spell_to_remove)) return 1 -/mob/proc/silence_spells(var/amount = 0) - if(amount < 0) +/mob/proc/silence_spells(amount = 0) + if(!amount) return if(!ability_master) diff --git a/code/modules/spells/aimed/dispell.dm b/code/modules/spells/aimed/dispell.dm index 72205068b72..13d38e54b80 100644 --- a/code/modules/spells/aimed/dispell.dm +++ b/code/modules/spells/aimed/dispell.dm @@ -9,7 +9,6 @@ level_max = list(UPGRADE_TOTAL = 2, UPGRADE_SPEED = 0, UPGRADE_POWER = 2) duration = 15 projectile_type = /obj/item/projectile/spell_projectile/dispell - var/amt_range = 0 active_msg = "You prepare to cast the bolt of dispell!" deactive_msg = "You decide against using the bolt of dispell." @@ -21,6 +20,9 @@ spell_cost = 2 mana_cost = 15 + var/amt_range = 0 + var/strength = DISPELL_WEAK + /datum/spell/aimed/dispell_projectile/prox_cast(list/targets, atom/spell_holder) var/atom/movable/A = targets[1] if(amt_range > 0) diff --git a/code/modules/spells/aimed/flamethrower.dm b/code/modules/spells/aimed/flamethrower.dm index 63b76d24d7d..7a3e546cbaa 100644 --- a/code/modules/spells/aimed/flamethrower.dm +++ b/code/modules/spells/aimed/flamethrower.dm @@ -56,4 +56,4 @@ flame_power += 20 flame_color = flame_power >= 60 ? COLOR_PURPLE : COLOR_RED - return "The [src] spell is now much more powerful." + return "The [src] spell is now [flame_power >= 60 ? "much " : ""]more powerful." diff --git a/code/modules/spells/aimed/spark_bolt.dm b/code/modules/spells/aimed/spark_bolt.dm index 79a9ea4d3ee..f25aa70f9f3 100644 --- a/code/modules/spells/aimed/spark_bolt.dm +++ b/code/modules/spells/aimed/spark_bolt.dm @@ -14,17 +14,27 @@ active_msg = "You prepare to cast spark bolt!" deactive_msg = "You dissipate the spark bolt." - level_max = list(UPGRADE_TOTAL = 2, UPGRADE_SPEED = 2, UPGRADE_POWER = 0) + level_max = list(UPGRADE_TOTAL = 4, UPGRADE_SPEED = 2, UPGRADE_POWER = 2) categories = list() spell_cost = 2 mana_cost = 0.5 // Per projectile, mind you +/datum/spell/aimed/spark_bolt/empower_spell() + if(!..()) + return FALSE + + projectile_amount += 3 + + return "The spell [src] now has more projectiles stored per cast." + /datum/spell/aimed/spark_bolt/quicken_spell() if(!..()) return FALSE - return "The spell [src] now has lower cooldown." + ranged_clickcd = max(0.5, ranged_clickcd - 1.5) + + return "The spell [src] now has lower cooldown and attack delay." // Projectile /obj/item/projectile/spark_bolt diff --git a/code/modules/spells/hand/sunwrath.dm b/code/modules/spells/hand/sunwrath.dm index e9f7b55731f..6d0e5e08e6e 100644 --- a/code/modules/spells/hand/sunwrath.dm +++ b/code/modules/spells/hand/sunwrath.dm @@ -10,6 +10,8 @@ spell_delay = 30 range = 4 + categories = list(SPELL_CATEGORY_FIRE) + hud_state = "wiz_immolate" spell_cost = 5 @@ -26,10 +28,10 @@ return 1 /obj/effect/fake_fire/sunwrath - firelevel = 2 + firelevel = 5 last_temperature = 0 - pressure = 3000 + pressure = 5000 /obj/effect/fake_fire/sunwrath/Process() //Override, so we burn mobs only for(var/mob/living/L in loc) - L.FireBurn(firelevel,last_temperature,pressure) + L.FireBurn(firelevel, last_temperature, pressure) diff --git a/icons/effects/beam.dmi b/icons/effects/beam.dmi index 264205694a8..2362c6743ea 100644 Binary files a/icons/effects/beam.dmi and b/icons/effects/beam.dmi differ diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi index dd4d1336d1a..74e8848f0e2 100644 Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ diff --git a/test/check-paths.sh b/test/check-paths.sh index 7b4e60b1a41..e3101af5dd1 100755 --- a/test/check-paths.sh +++ b/test/check-paths.sh @@ -34,7 +34,7 @@ exactly 117 "to_world uses" '\sto_world\(' exactly 60 "to_world_log uses" '\sto_world_log\(' exactly 0 "world<< uses" 'world<<|world[[:space:]]<<' exactly 0 "world.log<< uses" 'world.log<<|world.log[[:space:]]<<' -exactly 143 "<< uses" '(?