mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-30 00:29:02 +01:00
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.  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:
@@ -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
|
||||
|
||||
@@ -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?
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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"
|
||||
|
||||
@@ -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 |
@@ -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"
|
||||
|
||||
@@ -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)}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user