Adds 9 wizard perks (#83262)

## About The Pull Request

Add new spells category for wizards: Perks. perks are not really spells,
but useful (and not so useful) improvements for your wizard which
provide more variety for builds.
https://youtu.be/eeVvUkVE3xQ
All perks cost 2 points, they work without wizard’s uniform, cannot
refund, effect start only at the station (perks will not work at the
wizard’s base). Perk can only be purchased once.

9 added perks:
1. Four Hands - gives you 2 extra hands.
2. Worm Born - on death, wizard turns into a large worm and can no
longer return to his previous form.
![Снимок экрана 2024-06-02
223645](https://github.com/tgstation/tgstation/assets/120736708/2dfac647-4c3c-4824-8320-73fc98cc61fd)
3. Dejavu - every 60 seconds returns wizard to where he was 60 seconds
ago and restores his health to the amount he had 60 seconds ago.
4. Sale Off - When buying something from a book of spells, wizard has a
chance not to spend points for the purchase, depending on the purchase
price. 1/2/3/4 price chance 50/25/15/10%. You can no longer refund
purchases.
5. Gamble - Give wizard 2 random perks.
6. Heart Eater - By eating someone's heart, the wizard has a chance to
either increase his maximum HP and stamina by 25 or lose 10 percent of
his maximum HP but get a random mutation.
7. Slime Friends - Slimes is your friends now. Every 20 Seconds you
spend 50 nutriments to spawn random big angry slime.
8. Transparence - wizard becomes half transparent, any projectiles pass
through, but you loses 25% of max HP and you get a stalker who will
follow you to the station to kill you.
9. Magnetism - Wizard gain gravitational anomaly that orbit around him,
which attracts objects and people.
https://youtu.be/gp6ZtTrZu7I

## Why It's Good For The Game

Gives the wizard more options to create a fun and interesting builds

## Changelog

🆑
add: new wizard spells category - perks.
add: adds 9 wizard perks.
/🆑

---------

Co-authored-by: Jacquerel <hnevard@gmail.com>
This commit is contained in:
Xackii
2024-07-15 16:28:41 +01:00
committed by GitHub
co-authored by Jacquerel
parent 0f76cf52b8
commit 2165300a01
19 changed files with 496 additions and 6 deletions
@@ -277,6 +277,9 @@
#define COMSIG_LIVING_GRAB "living_grab"
// Return COMPONENT_CANCEL_ATTACK_CHAIN / COMPONENT_SKIP_ATTACK_CHAIN to stop the grab
///Called when living finish eat (/datum/component/edible/proc/On_Consume)
#define COMSIG_LIVING_FINISH_EAT "living_finish_eat"
/// From /datum/element/basic_eating/try_eating()
#define COMSIG_MOB_PRE_EAT "mob_pre_eat"
///cancel eating attempt
+5
View File
@@ -1173,6 +1173,11 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
/// Trait given to anything linked to, not necessarily allied to, the mansus
#define TRAIT_MANSUS_TOUCHED "mansus_touched"
/// Appiled when wizard buy (/datum/spellbook_entry/perks/spalls_lottery) perk.
/// Give 50/25% chance not spend a spellbook charge on 1/2 cost spell.
/// Appiled it wizard can't refund any spells.
#define TRAIT_SPELLS_LOTTERY "spell_for_sale"
/// Trait given to mobs wearing the clown mask
#define TRAIT_PERCEIVED_AS_CLOWN "perceived_as_clown"
/// Does this item bypass ranged armor checks?
+1
View File
@@ -452,6 +452,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_SPARRING" = TRAIT_SPARRING,
"TRAIT_SPEAKS_CLEARLY" = TRAIT_SPEAKS_CLEARLY,
"TRAIT_SPECIAL_TRAUMA_BOOST" = TRAIT_SPECIAL_TRAUMA_BOOST,
"TRAIT_SPELLS_LOTTERY" = TRAIT_SPELLS_LOTTERY,
"TRAIT_SPIDER_CONSUMED" = TRAIT_SPIDER_CONSUMED,
"TRAIT_SPIRITUAL" = TRAIT_SPIRITUAL,
"TRAIT_SPRAY_PAINTABLE" = TRAIT_SPRAY_PAINTABLE,
+1 -1
View File
@@ -85,7 +85,7 @@
master.forceMove(starting_turf)
rewinds_remaining --
if(rewinds_remaining)
if(rewinds_remaining || rewinds_remaining < 0)
addtimer(CALLBACK(src, rewind_type), rewind_interval)
else
to_chat(parent, span_notice(no_rewinds_message))
+1
View File
@@ -641,6 +641,7 @@ Behavior that's still missing from this component that original food items had t
///Delete the item when it is fully eaten
/datum/component/edible/proc/On_Consume(mob/living/eater, mob/living/feeder)
SEND_SIGNAL(parent, COMSIG_FOOD_CONSUMED, eater, feeder)
SEND_SIGNAL(eater, COMSIG_LIVING_FINISH_EAT, parent, feeder)
on_consume?.Invoke(eater, feeder)
if (QDELETED(parent)) // might be destroyed by the callback
+118
View File
@@ -0,0 +1,118 @@
/datum/component/heart_eater
/// Check if we fully ate whole heart and reset when we start eat new one.
var/bites_taken = 0
/// Remember the number of species damage_modifier.
var/remember_modifier = 0
/// Remember last heart we ate and reset bites_taken counter if we start eat new one
var/datum/weakref/last_heart_we_ate
/// List of all mutations allowed to get.
var/static/list/datum/mutation/human/mutations_list = list(
/datum/mutation/human/adaptation/cold,
/datum/mutation/human/adaptation/heat,
/datum/mutation/human/adaptation/pressure,
/datum/mutation/human/adaptation/thermal,
/datum/mutation/human/chameleon,
/datum/mutation/human/cryokinesis,
/datum/mutation/human/cryokinesis/pyrokinesis,
/datum/mutation/human/dwarfism,
/datum/mutation/human/geladikinesis/ash,
/datum/mutation/human/insulated,
/datum/mutation/human/telekinesis,
/datum/mutation/human/telepathy,
/datum/mutation/human/thermal,
/datum/mutation/human/tongue_spike,
/datum/mutation/human/webbing,
/datum/mutation/human/xray,
)
/datum/component/heart_eater/Initialize(...)
. = ..()
if(!ishuman(parent))
return COMPONENT_INCOMPATIBLE
prepare_species(parent)
/datum/component/heart_eater/RegisterWithParent()
. = ..()
RegisterSignal(parent, COMSIG_SPECIES_GAIN, PROC_REF(on_species_change))
RegisterSignal(parent, COMSIG_LIVING_FINISH_EAT, PROC_REF(eat_eat_eat))
/datum/component/heart_eater/UnregisterFromParent()
. = ..()
UnregisterSignal(parent, COMSIG_LIVING_FINISH_EAT)
UnregisterSignal(parent, COMSIG_SPECIES_GAIN)
/datum/component/heart_eater/proc/prepare_species(mob/living/carbon/human/eater)
if(eater.get_liked_foodtypes() & GORE)
return
var/obj/item/organ/internal/tongue/eater_tongue = eater.get_organ_slot(ORGAN_SLOT_TONGUE)
if(!eater_tongue)
return
eater_tongue.disliked_foodtypes &= ~GORE
eater_tongue.liked_foodtypes |= GORE
/datum/component/heart_eater/proc/on_species_change(mob/living/carbon/human/eater, datum/species/new_species, datum/species/old_species)
SIGNAL_HANDLER
eater.dna?.species?.damage_modifier += remember_modifier
prepare_species(eater)
/// Proc called when we finish eat somthing.
/datum/component/heart_eater/proc/eat_eat_eat(mob/living/carbon/human/eater, datum/what_we_ate)
SIGNAL_HANDLER
if(get_area(eater) == GLOB.areas_by_type[/area/centcom/wizard_station])
return
if(!istype(what_we_ate, /obj/item/organ/internal/heart))
return
var/obj/item/organ/internal/heart/we_ate_heart = what_we_ate
var/obj/item/organ/internal/heart/previous_heart = last_heart_we_ate?.resolve()
if(we_ate_heart == previous_heart)
return
bites_taken = 0
last_heart_we_ate = WEAKREF(we_ate_heart)
bites_taken++
if(bites_taken < (we_ate_heart.reagents.total_volume/2))
return
if(prob(50))
perfect_heart(eater)
return
not_perfect_heart(eater)
///Perfect heart give our +10 damage modifier(Max. 80).
/datum/component/heart_eater/proc/perfect_heart(mob/living/carbon/human/eater)
if(eater.dna?.species?.damage_modifier >= 80)
healing_heart(eater)
return
eater.dna?.species?.damage_modifier += 10
remember_modifier += 10
healing_heart(eater)
to_chat(eater, span_warning("This heart is perfect. You feel a surge of vital energy."))
///Not Perfect heart give random mutation.
/datum/component/heart_eater/proc/not_perfect_heart(mob/living/carbon/human/eater)
var/datum/mutation/human/new_mutation
var/list/datum/mutation/human/shuffle_mutation_list = shuffle(mutations_list)
for(var/mutation_in_list in shuffle_mutation_list)
if(is_type_in_list(mutation_in_list, eater.dna.mutations))
continue
new_mutation = mutation_in_list
break
if(isnull(new_mutation))
healing_heart(eater)
return
eater.dna.add_mutation(new_mutation)
healing_heart(eater)
to_chat(eater, span_warning("This heart is not right for you. You now have [new_mutation.name] mutation."))
///Heart eater give also strong healing from hearts.
/datum/component/heart_eater/proc/healing_heart(mob/living/carbon/human/eater)
for(var/heal_organ in eater.organs)
eater.adjustOrganLoss(heal_organ, -50)
for(var/datum/wound/heal_wound in eater.all_wounds)
heal_wound.remove_wound()
eater.adjustBruteLoss(-50)
eater.adjustFireLoss(-50)
eater.adjustToxLoss(-50)
eater.adjustOxyLoss(-50)
eater.adjustStaminaLoss(-50)
+61
View File
@@ -0,0 +1,61 @@
/datum/component/slime_friends
/// Slime maker timer.
var/timer
/// List to pick from when we need slime colour.
var/static/colours = list(
/datum/slime_type/adamantine,
/datum/slime_type/black,
/datum/slime_type/blue,
/datum/slime_type/bluespace,
/datum/slime_type/cerulean,
/datum/slime_type/darkblue,
/datum/slime_type/darkpurple,
/datum/slime_type/gold,
/datum/slime_type/green,
/datum/slime_type/grey,
/datum/slime_type/lightpink,
/datum/slime_type/metal,
/datum/slime_type/oil,
/datum/slime_type/orange,
/datum/slime_type/pink,
/datum/slime_type/purple,
/datum/slime_type/pyrite,
/datum/slime_type/rainbow,
/datum/slime_type/red,
/datum/slime_type/sepia,
/datum/slime_type/silver,
/datum/slime_type/yellow,
)
/datum/component/slime_friends/Initialize(...)
. = ..()
if(!isliving(parent))
return COMPONENT_INCOMPATIBLE
var/mob/living/living_parent = parent
living_parent.faction |= FACTION_SLIME
RegisterSignal(living_parent, COMSIG_ENTER_AREA, PROC_REF(start_slime_prodaction))
/datum/component/slime_friends/Destroy(force)
. = ..()
var/mob/living/living_parent = parent
living_parent.faction -= FACTION_SLIME
timer = null
/// Start slime prodaction when we leave wizden.
/datum/component/slime_friends/proc/start_slime_prodaction(mob/living/friend, area/new_area)
if(new_area == GLOB.areas_by_type[/area/centcom/wizard_station])
return
timer = addtimer(CALLBACK(src, PROC_REF(make_slime_friend), friend), 20 SECONDS)
UnregisterSignal(friend, COMSIG_ENTER_AREA)
/// Slime prodactor proc.
/datum/component/slime_friends/proc/make_slime_friend(mob/living/friend)
timer = addtimer(CALLBACK(src, PROC_REF(make_slime_friend), friend), 20 SECONDS)
if(get_area(friend) == GLOB.areas_by_type[/area/centcom/wizard_station])
return
var/turf/where = get_turf(friend)
var/new_colour = pick(colours)
var/mob/living/basic/slime/new_friend = new(where, new_colour, SLIME_LIFE_STAGE_ADULT)
new_friend.faction = friend.faction.Copy()
new_friend.set_enraged_behaviour()
friend.nutrition -= 50
+74
View File
@@ -0,0 +1,74 @@
/datum/component/wormborn
/datum/component/wormborn/Initialize(...)
. = ..()
if(!isliving(parent))
return COMPONENT_INCOMPATIBLE
/datum/component/wormborn/RegisterWithParent()
. = ..()
RegisterSignal(parent, COMSIG_LIVING_DEATH, PROC_REF(second_breath))
/datum/component/wormborn/UnregisterFromParent()
. = ..()
UnregisterSignal(parent, COMSIG_LIVING_DEATH)
/datum/component/wormborn/proc/second_breath(mob/living/source)
SIGNAL_HANDLER
if(get_area(source) == GLOB.areas_by_type[/area/centcom/wizard_station])
return
source.buckled?.unbuckle_mob(source, force = TRUE)
if(source.movement_type & VENTCRAWLING)
source.forceMove(get_turf(source))
var/mob/living/worm = new /mob/living/basic/wizard_worm(get_turf(source))
source.mind?.transfer_to(worm)
source.forceMove(worm)
/mob/living/basic/wizard_worm
name = "Magic Worm"
desc = "Large blue worm. What happens if you put your hand in his mouth?."
icon = 'icons/mob/simple/mob.dmi'
icon_state = "wizard_start"
icon_living = "wizard_start"
base_icon_state = "wizard"
maxHealth = 800
health = 800
melee_damage_lower = 20
melee_damage_upper = 30
obj_damage = 200
speed = 0
move_force = MOVE_FORCE_OVERPOWERING
move_resist = MOVE_FORCE_OVERPOWERING
pull_force = MOVE_FORCE_OVERPOWERING
mob_size = MOB_SIZE_HUGE
sentience_type = SENTIENCE_BOSS
mob_biotypes = MOB_ORGANIC|MOB_SPECIAL
/mob/living/basic/wizard_worm/has_gravity(turf/gravity_turf)
return TRUE
/mob/living/basic/wizard_worm/can_be_pulled()
return FALSE
/mob/living/basic/wizard_worm/Initialize(mapload, spawn_bodyparts = TRUE)
. = ..()
AddElement(/datum/element/wall_tearer)
if(spawn_bodyparts)
build_tail()
/mob/living/basic/wizard_worm/proc/build_tail(mob/living/tail)
AddComponent(/datum/component/mob_chain, vary_icon_state = TRUE)
var/mob/living/basic/wizard_worm/prev = src
for(var/i in 1 to 5)
prev = new_segment(behind = prev)
update_appearance(UPDATE_ICON_STATE)
/mob/living/basic/wizard_worm/proc/new_segment(mob/living/basic/wizard_worm/behind)
var/mob/living/segment = new type(drop_location(), FALSE)
ADD_TRAIT(segment, TRAIT_PERMANENTLY_MORTAL, INNATE_TRAIT)
segment.AddComponent(/datum/component/mob_chain, front = behind, vary_icon_state = TRUE)
return segment
@@ -70,6 +70,15 @@
for(var/spell in user.actions)
if(is_type_in_typecache(spell, no_coexistance_typecache))
return FALSE
var/datum/antagonist/wizard/wizard_datum = user.mind.has_antag_datum(/datum/antagonist/wizard)
if(!wizard_datum)
return TRUE
for(var/perks in wizard_datum.perks)
if(is_type_in_typecache(perks, no_coexistance_typecache))
return FALSE
if(is_type_in_list(src, wizard_datum.perks))
to_chat(user, span_warning("This perk already learned!"))
return FALSE
return TRUE
/**
@@ -137,6 +146,9 @@
* Return TRUE if it can refunded, FALSE otherwise
*/
/datum/spellbook_entry/proc/can_refund(mob/living/carbon/human/user, obj/item/spellbook/book)
if(HAS_TRAIT(user, TRAIT_SPELLS_LOTTERY))
to_chat(user, span_notice("No refund."))
return FALSE
if(!refundable)
return FALSE
if(!book.refunds_allowed)
@@ -55,7 +55,7 @@
it will become easier for others to find your item of power."
spell_type = /datum/action/cooldown/spell/lichdom
category = SPELLBOOK_CATEGORY_DEFENSIVE
no_coexistance_typecache = list(/datum/action/cooldown/spell/splattercasting)
no_coexistance_typecache = list(/datum/action/cooldown/spell/splattercasting, /datum/spellbook_entry/perks/wormborn)
/datum/spellbook_entry/chuunibyou
name = "Chuuni Invocations"
@@ -0,0 +1,184 @@
#define SPELLBOOK_CATEGORY_PERKS "Perks"
/datum/spellbook_entry/perks
desc = "Main node of perks"
category = SPELLBOOK_CATEGORY_PERKS
refundable = FALSE // no refund
requires_wizard_garb = FALSE
/datum/spellbook_entry/perks/buy_spell(mob/living/carbon/human/user, obj/item/spellbook/book, log_buy)
var/datum/antagonist/wizard/wizard_datum = user.mind.has_antag_datum(/datum/antagonist/wizard)
if(wizard_datum)
wizard_datum.perks += src
to_chat(user, span_notice("You got a new perk: [src.name]."))
return TRUE
/datum/spellbook_entry/perks/fourhands
name = "Four Hands"
desc = "Gives you even more hands to perform magic"
/datum/spellbook_entry/perks/fourhands/buy_spell(mob/living/carbon/human/user, obj/item/spellbook/book, log_buy)
. = ..()
user.change_number_of_hands(4)
/datum/spellbook_entry/perks/wormborn
name = "Worm Born"
desc = "Your soul is infested with mana worms. When you die, you will be reborn as a large worm. \
When the worm dies, it has no such luck. Parasitic infection prevents you from binding your soul to objects."
no_coexistance_typecache = list(/datum/action/cooldown/spell/lichdom)
/datum/spellbook_entry/perks/wormborn/buy_spell(mob/living/carbon/human/user, obj/item/spellbook/book, log_buy)
. = ..()
user.AddComponent(/datum/component/wormborn)
/datum/spellbook_entry/perks/dejavu
name = "Déjà vu"
desc = "Every 60 seconds returns you to the place where you were 60 seconds ago with the same amount of health as you had 60 seconds ago."
/datum/spellbook_entry/perks/dejavu/buy_spell(mob/living/carbon/human/user, obj/item/spellbook/book, log_buy)
. = ..()
RegisterSignal(user, COMSIG_ENTER_AREA, PROC_REF(give_dejavu))
/datum/spellbook_entry/perks/dejavu/proc/give_dejavu(mob/living/carbon/human/wizard, area/new_area)
SIGNAL_HANDLER
if(new_area == GLOB.areas_by_type[/area/centcom/wizard_station])
return
wizard.AddComponent(/datum/component/dejavu/timeline, -1, 60 SECONDS)
UnregisterSignal(wizard, COMSIG_ENTER_AREA)
/datum/spellbook_entry/perks/spell_lottery
name = "Spells Lottery"
desc = "Spells Lottery gives you the chance to get something from the book absolutely free, but you can no longer refund any purchases."
/datum/spellbook_entry/perks/spell_lottery/buy_spell(mob/living/carbon/human/user, obj/item/spellbook/book, log_buy)
. = ..()
ADD_TRAIT(user, TRAIT_SPELLS_LOTTERY, REF(src))
/datum/spellbook_entry/perks/gamble
name = "Gamble"
desc = "You get 2 random perks."
/datum/spellbook_entry/perks/gamble/buy_spell(mob/living/carbon/human/user, obj/item/spellbook/book, log_buy)
. = ..()
var/datum/antagonist/wizard/check_perks = user.mind.has_antag_datum(/datum/antagonist/wizard)
var/perks_allocated = 0
var/list/taking_perks = list()
for(var/datum/spellbook_entry/perks/generate_perk in book.entries)
if(istype(generate_perk, src))
continue
if(check_perks && is_type_in_list(generate_perk, check_perks.perks))
continue
taking_perks += generate_perk
perks_allocated++
if(perks_allocated >= 2)
break
if(taking_perks.len < 1)
to_chat(user, span_warning("Gamble cannot give 2 perks, so points are returned"))
return FALSE
taking_perks = shuffle(taking_perks)
for(var/datum/spellbook_entry/perks/perks_ready in taking_perks)
perks_ready.buy_spell(user, book, log_buy)
/datum/spellbook_entry/perks/heart_eater
name = "Heart Eater"
desc = "Gives you ability to obtain a person's life force by eating their heart. \
By eating someone's heart you can increase your damage resistance or gain random mutation. \
Heart also give strong healing buff."
/datum/spellbook_entry/perks/heart_eater/buy_spell(mob/living/carbon/human/user, obj/item/spellbook/book, log_buy)
. = ..()
user.AddComponent(/datum/component/heart_eater)
/datum/spellbook_entry/perks/slime_friends
name = "Slime Friends"
desc = "Slimes are your friends. \
Every 15 seconds you lose some nutriments and summon a random evil slime to fight on your side."
/datum/spellbook_entry/perks/slime_friends/buy_spell(mob/living/carbon/human/user, obj/item/spellbook/book, log_buy)
. = ..()
user.AddComponent(/datum/component/slime_friends)
/datum/spellbook_entry/perks/transparence
name = "Transparence"
desc = "You become a little closer to the world of the dead. \
Projectiles pass through you, but you lose 25% of your health and you are hunted by a terrible curse which wants to return you to the afterlife."
/datum/spellbook_entry/perks/transparence/buy_spell(mob/living/carbon/human/user, obj/item/spellbook/book, log_buy)
. = ..()
user.maxHealth *= 0.75
user.alpha = 125
ADD_TRAIT(user, TRAIT_UNHITTABLE_BY_PROJECTILES, REF(src))
RegisterSignal(user, COMSIG_ENTER_AREA, PROC_REF(make_stalker))
/datum/spellbook_entry/perks/transparence/proc/make_stalker(mob/living/carbon/human/wizard, area/new_area)
SIGNAL_HANDLER
if(new_area == GLOB.areas_by_type[/area/centcom/wizard_station])
return
wizard.gain_trauma(/datum/brain_trauma/magic/stalker)
UnregisterSignal(wizard, COMSIG_ENTER_AREA)
/datum/spellbook_entry/perks/magnetism
name = "Magnetism"
desc = "You get a small gravity anomaly that orbit around you. \
Nearby things will be attracted to you."
/datum/spellbook_entry/perks/magnetism/buy_spell(mob/living/carbon/human/user, obj/item/spellbook/book, log_buy)
. = ..()
var/atom/movable/magnitizm = new /obj/effect/wizard_magnetism(get_turf(user))
magnitizm.orbit(user, 20)
/obj/effect/wizard_magnetism
name = "magnetic anomaly"
icon = 'icons/effects/effects.dmi'
icon_state = "shield2"
/// We need to orbit around someone.
var/datum/weakref/owner
/obj/effect/wizard_magnetism/New(loc, ...)
. = ..()
transform *= 0.4
/obj/effect/wizard_magnetism/orbit(atom/new_owner, radius, clockwise, rotation_speed, rotation_segments, pre_rotation)
. = ..()
if(!isliving(new_owner))
return
owner = WEAKREF(new_owner)
RegisterSignal(new_owner, COMSIG_ENTER_AREA, PROC_REF(check_area))
RegisterSignal(new_owner, COMSIG_LIVING_DEATH, PROC_REF(on_owner_death))
/obj/effect/wizard_magnetism/proc/check_area(mob/living/wizard, area/new_area)
SIGNAL_HANDLER
if(new_area == GLOB.areas_by_type[/area/centcom/wizard_station])
return
START_PROCESSING(SSprocessing, src)
UnregisterSignal(wizard, COMSIG_ENTER_AREA)
/obj/effect/wizard_magnetism/proc/on_owner_death()
SIGNAL_HANDLER
stop_orbit()
/obj/effect/wizard_magnetism/process(seconds_per_tick)
if(isnull(owner))
stop_orbit()
return
var/mob/living/wizard = owner.resolve()
var/list/things_in_range = orange(5, wizard) - orange(1, wizard)
for(var/obj/take_object in things_in_range)
if(!take_object.anchored)
step_towards(take_object, wizard)
for(var/mob/living/living_mov in things_in_range)
if(wizard)
if(living_mov == wizard)
continue
if(!living_mov.mob_negates_gravity())
step_towards(living_mov, wizard)
/obj/effect/wizard_magnetism/stop_orbit()
STOP_PROCESSING(SSprocessing, src)
qdel(src)
#undef SPELLBOOK_CATEGORY_PERKS
@@ -229,6 +229,10 @@
return FALSE
to_buy.times++
if(HAS_TRAIT(user, TRAIT_SPELLS_LOTTERY))
if(prob(50 / to_buy.cost))
to_chat(user, span_notice("This spell was given to you for free!"))
return TRUE
uses -= to_buy.cost
return TRUE
@@ -25,6 +25,8 @@ GLOBAL_LIST_EMPTY(wizard_spellbook_purchases_by_key)
show_to_ghosts = TRUE
/// This mob's Grand Ritual ability
var/datum/action/cooldown/grand_ritual/ritual
/// Perks that wizard learn
var/list/perks = list()
/datum/antagonist/wizard_minion
name = "Wizard Minion"
+1 -1
View File
@@ -182,7 +182,7 @@
return
var/atom/movable/screen/inventory/hand/hand = new_owner.hud_used.hand_slots["[held_index]"]
hand.update_appearance()
hand?.update_appearance()
/obj/item/bodypart/arm/left
name = "left arm"
@@ -25,6 +25,8 @@
///Are our wings open or closed?
var/wings_open = FALSE
///We cant hide this wings in suit
var/cant_hide = FALSE
// grind_results = list(/datum/reagent/flightpotion = 5)
food_reagents = list(/datum/reagent/flightpotion = 5)
@@ -66,7 +68,7 @@
if(human.stat || human.body_position == LYING_DOWN)
return FALSE
//Jumpsuits have tail holes, so it makes sense they have wing holes too
if(human.wear_suit && ((human.wear_suit.flags_inv & HIDEJUMPSUIT) && (!human.wear_suit.species_exception || !is_type_in_list(src, human.wear_suit.species_exception))))
if(!cant_hide && human.wear_suit && ((human.wear_suit.flags_inv & HIDEJUMPSUIT) && (!human.wear_suit.species_exception || !is_type_in_list(src, human.wear_suit.species_exception))))
to_chat(human, span_warning("Your suit blocks your wings from extending!"))
return FALSE
var/turf/location = get_turf(human)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 186 KiB

After

Width:  |  Height:  |  Size: 177 KiB

+4
View File
@@ -1114,6 +1114,7 @@
#include "code\datums\components\hazard_area.dm"
#include "code\datums\components\healing_touch.dm"
#include "code\datums\components\health_scaling_effects.dm"
#include "code\datums\components\heart_eater.dm"
#include "code\datums\components\heirloom.dm"
#include "code\datums\components\hide_highest_offset.dm"
#include "code\datums\components\holderloving.dm"
@@ -1203,6 +1204,7 @@
#include "code\datums\components\sisyphus_awarder.dm"
#include "code\datums\components\sitcomlaughter.dm"
#include "code\datums\components\sizzle.dm"
#include "code\datums\components\slime_friends.dm"
#include "code\datums\components\slippery.dm"
#include "code\datums\components\smooth_tunes.dm"
#include "code\datums\components\soul_stealer.dm"
@@ -1266,6 +1268,7 @@
#include "code\datums\components\wearertargeting.dm"
#include "code\datums\components\weatherannouncer.dm"
#include "code\datums\components\wet_floor.dm"
#include "code\datums\components\wormborn.dm"
#include "code\datums\components\container_item\container_item.dm"
#include "code\datums\components\container_item\tank_holder.dm"
#include "code\datums\components\crafting\_recipes.dm"
@@ -3319,6 +3322,7 @@
#include "code\modules\antagonists\wizard\equipment\spellbook_entries\defensive.dm"
#include "code\modules\antagonists\wizard\equipment\spellbook_entries\mobility.dm"
#include "code\modules\antagonists\wizard\equipment\spellbook_entries\offensive.dm"
#include "code\modules\antagonists\wizard\equipment\spellbook_entries\perks.dm"
#include "code\modules\antagonists\wizard\equipment\spellbook_entries\summons.dm"
#include "code\modules\antagonists\wizard\grand_ritual\fluff.dm"
#include "code\modules\antagonists\wizard\grand_ritual\grand_ritual.dm"
+21 -2
View File
@@ -22,6 +22,7 @@ enum SpellCategory {
Mobility = 'Mobility',
Assistance = 'Assistance',
Rituals = 'Rituals',
Perks = 'Perks',
}
type byondRef = string;
@@ -124,6 +125,16 @@ const TAB2NAME: TabType[] = [
"If you didn't like the loadouts offered, you can embrace chaos. Not recommended for newer wizards.",
component: () => <Randomize />,
},
{
title: 'Perks',
blurb:
'Perks are useful (and not so useful) improvements to the soul and body collected from all corners of the universe.',
scrollable: true,
},
{
title: 'Table of Contents',
component: () => <TableOfContents />,
},
];
enum Buywords {
@@ -158,7 +169,7 @@ const EnscribedName = (props) => {
);
};
const lineHeightToc = '34.6px';
const lineHeightToc = '30.6px';
const TableOfContents = (props) => {
const [tabIndex, setTabIndex] = useLocalState('tab-index', 1);
@@ -238,6 +249,14 @@ const TableOfContents = (props) => {
content="Arcane Randomizer"
onClick={() => setTabIndex(9)}
/>
<Divider />
<Button
lineHeight={lineHeightToc}
fluid
icon="cog"
content="Perks"
onClick={() => setTabIndex(11)}
/>
</Box>
);
};
@@ -731,7 +750,7 @@ export const Spellbook = (props) => {
<Button
mr={0}
icon="arrow-right"
disabled={tabIndex === 9}
disabled={tabIndex === 11}
content="Next Page"
onClick={() => setTabIndex(tabIndex + 2)}
/>