Tg 1 28 sync testing/confirmation (#5178)
* maps, tgui, tools * defines and helpers * onclick and controllers * datums fucking caught that hulk reversal too. * game and shuttle modular * module/admin * oh god they fucking moved antag shit again * haaaaate. Haaaaaaaaaate. * enables moff wings * more modules things * tgstation.dme before I forget something important * some mob stuff * s'more mob/living stuff * some carbon stuff * ayy lmaos and kitchen meat * Human stuff * species things moff wings have a 'none' version too * the rest of the module stuff. * some strings * misc * mob icons * some other icons. * It compiles FUCK BORERS FUCK BORERS
This commit is contained in:
@@ -1,411 +0,0 @@
|
||||
|
||||
//Apprenticeship contract - moved to antag_spawner.dm
|
||||
|
||||
///////////////////////////Veil Render//////////////////////
|
||||
|
||||
/obj/item/veilrender
|
||||
name = "veil render"
|
||||
desc = "A wicked curved blade of alien origin, recovered from the ruins of a vast city."
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "render"
|
||||
item_state = "knife"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/kitchen_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/kitchen_righthand.dmi'
|
||||
force = 15
|
||||
throwforce = 10
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
hitsound = 'sound/weapons/bladeslice.ogg'
|
||||
var/charges = 1
|
||||
var/spawn_type = /obj/singularity/wizard
|
||||
var/spawn_amt = 1
|
||||
var/activate_descriptor = "reality"
|
||||
var/rend_desc = "You should run now."
|
||||
var/spawn_fast = 0 //if 1, ignores checking for mobs on loc before spawning
|
||||
|
||||
/obj/item/veilrender/attack_self(mob/user)
|
||||
if(charges > 0)
|
||||
new /obj/effect/rend(get_turf(user), spawn_type, spawn_amt, rend_desc, spawn_fast)
|
||||
charges--
|
||||
user.visible_message("<span class='boldannounce'>[src] hums with power as [user] deals a blow to [activate_descriptor] itself!</span>")
|
||||
else
|
||||
to_chat(user, "<span class='danger'>The unearthly energies that powered the blade are now dormant.</span>")
|
||||
|
||||
/obj/effect/rend
|
||||
name = "tear in the fabric of reality"
|
||||
desc = "You should run now."
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
icon_state = "rift"
|
||||
density = TRUE
|
||||
anchored = TRUE
|
||||
var/spawn_path = /mob/living/simple_animal/cow //defaulty cows to prevent unintentional narsies
|
||||
var/spawn_amt_left = 20
|
||||
var/spawn_fast = 0
|
||||
|
||||
/obj/effect/rend/New(loc, var/spawn_type, var/spawn_amt, var/desc, var/spawn_fast)
|
||||
src.spawn_path = spawn_type
|
||||
src.spawn_amt_left = spawn_amt
|
||||
src.desc = desc
|
||||
src.spawn_fast = spawn_fast
|
||||
START_PROCESSING(SSobj, src)
|
||||
return
|
||||
|
||||
/obj/effect/rend/process()
|
||||
if(!spawn_fast)
|
||||
if(locate(/mob) in loc)
|
||||
return
|
||||
new spawn_path(loc)
|
||||
spawn_amt_left--
|
||||
if(spawn_amt_left <= 0)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/rend/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/nullrod))
|
||||
user.visible_message("<span class='danger'>[user] seals \the [src] with \the [I].</span>")
|
||||
qdel(src)
|
||||
return
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/effect/rend/singularity_pull()
|
||||
return
|
||||
|
||||
/obj/effect/rend/singularity_pull()
|
||||
return
|
||||
|
||||
/obj/item/veilrender/vealrender
|
||||
name = "veal render"
|
||||
desc = "A wicked curved blade of alien origin, recovered from the ruins of a vast farm."
|
||||
spawn_type = /mob/living/simple_animal/cow
|
||||
spawn_amt = 20
|
||||
activate_descriptor = "hunger"
|
||||
rend_desc = "Reverberates with the sound of ten thousand moos."
|
||||
|
||||
/obj/item/veilrender/honkrender
|
||||
name = "honk render"
|
||||
desc = "A wicked curved blade of alien origin, recovered from the ruins of a vast circus."
|
||||
spawn_type = /mob/living/simple_animal/hostile/retaliate/clown
|
||||
spawn_amt = 10
|
||||
activate_descriptor = "depression"
|
||||
rend_desc = "Gently wafting with the sounds of endless laughter."
|
||||
icon_state = "clownrender"
|
||||
|
||||
////TEAR IN REALITY
|
||||
|
||||
/obj/singularity/wizard
|
||||
name = "tear in the fabric of reality"
|
||||
desc = "This isn't right."
|
||||
icon = 'icons/effects/224x224.dmi'
|
||||
icon_state = "reality"
|
||||
pixel_x = -96
|
||||
pixel_y = -96
|
||||
grav_pull = 6
|
||||
consume_range = 3
|
||||
current_size = STAGE_FOUR
|
||||
allowed_size = STAGE_FOUR
|
||||
|
||||
/obj/singularity/wizard/process()
|
||||
move()
|
||||
eat()
|
||||
return
|
||||
/////////////////////////////////////////Scrying///////////////////
|
||||
|
||||
/obj/item/scrying
|
||||
name = "scrying orb"
|
||||
desc = "An incandescent orb of otherworldly energy, staring into it gives you vision beyond mortal means."
|
||||
icon = 'icons/obj/projectiles.dmi'
|
||||
icon_state ="bluespace"
|
||||
throw_speed = 3
|
||||
throw_range = 7
|
||||
throwforce = 15
|
||||
damtype = BURN
|
||||
force = 15
|
||||
hitsound = 'sound/items/welder2.ogg'
|
||||
|
||||
var/xray_granted = FALSE
|
||||
|
||||
/obj/item/scrying/equipped(mob/user)
|
||||
if(!xray_granted && ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(!(H.dna.check_mutation(XRAY)))
|
||||
H.dna.add_mutation(XRAY)
|
||||
xray_granted = TRUE
|
||||
. = ..()
|
||||
|
||||
/obj/item/scrying/attack_self(mob/user)
|
||||
to_chat(user, "<span class='notice'>You can see...everything!</span>")
|
||||
visible_message("<span class='danger'>[user] stares into [src], their eyes glazing over.</span>")
|
||||
user.ghostize(1)
|
||||
|
||||
/////////////////////////////////////////Necromantic Stone///////////////////
|
||||
|
||||
/obj/item/device/necromantic_stone
|
||||
name = "necromantic stone"
|
||||
desc = "A shard capable of resurrecting humans as skeleton thralls."
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "necrostone"
|
||||
item_state = "electronic"
|
||||
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
var/list/spooky_scaries = list()
|
||||
var/unlimited = 0
|
||||
|
||||
/obj/item/device/necromantic_stone/unlimited
|
||||
unlimited = 1
|
||||
|
||||
/obj/item/device/necromantic_stone/attack(mob/living/carbon/human/M, mob/living/carbon/human/user)
|
||||
if(!istype(M))
|
||||
return ..()
|
||||
|
||||
if(!istype(user) || !user.canUseTopic(M,1))
|
||||
return
|
||||
|
||||
if(M.stat != DEAD)
|
||||
to_chat(user, "<span class='warning'>This artifact can only affect the dead!</span>")
|
||||
return
|
||||
|
||||
if(!M.mind || !M.client)
|
||||
to_chat(user, "<span class='warning'>There is no soul connected to this body...</span>")
|
||||
return
|
||||
|
||||
check_spooky()//clean out/refresh the list
|
||||
if(spooky_scaries.len >= 3 && !unlimited)
|
||||
to_chat(user, "<span class='warning'>This artifact can only affect three undead at a time!</span>")
|
||||
return
|
||||
|
||||
M.set_species(/datum/species/skeleton, icon_update=0)
|
||||
M.revive(full_heal = 1, admin_revive = 1)
|
||||
spooky_scaries |= M
|
||||
to_chat(M, "<span class='userdanger'>You have been revived by </span><B>[user.real_name]!</B>")
|
||||
to_chat(M, "<span class='userdanger'>[user.p_they(TRUE)] [user.p_are()] your master now, assist them even if it costs you your new life!</span>")
|
||||
|
||||
equip_roman_skeleton(M)
|
||||
|
||||
desc = "A shard capable of resurrecting humans as skeleton thralls[unlimited ? "." : ", [spooky_scaries.len]/3 active thralls."]"
|
||||
|
||||
/obj/item/device/necromantic_stone/proc/check_spooky()
|
||||
if(unlimited) //no point, the list isn't used.
|
||||
return
|
||||
|
||||
for(var/X in spooky_scaries)
|
||||
if(!ishuman(X))
|
||||
spooky_scaries.Remove(X)
|
||||
continue
|
||||
var/mob/living/carbon/human/H = X
|
||||
if(H.stat == DEAD)
|
||||
H.dust(TRUE)
|
||||
spooky_scaries.Remove(X)
|
||||
continue
|
||||
listclearnulls(spooky_scaries)
|
||||
|
||||
//Funny gimmick, skeletons always seem to wear roman/ancient armour
|
||||
/obj/item/device/necromantic_stone/proc/equip_roman_skeleton(mob/living/carbon/human/H)
|
||||
for(var/obj/item/I in H)
|
||||
H.dropItemToGround(I)
|
||||
|
||||
var/hat = pick(/obj/item/clothing/head/helmet/roman, /obj/item/clothing/head/helmet/roman/legionaire)
|
||||
H.equip_to_slot_or_del(new hat(H), slot_head)
|
||||
H.equip_to_slot_or_del(new /obj/item/clothing/under/roman(H), slot_w_uniform)
|
||||
H.equip_to_slot_or_del(new /obj/item/clothing/shoes/roman(H), slot_shoes)
|
||||
H.put_in_hands(new /obj/item/shield/riot/roman(H), TRUE)
|
||||
H.put_in_hands(new /obj/item/claymore(H), TRUE)
|
||||
H.equip_to_slot_or_del(new /obj/item/twohanded/spear(H), slot_back)
|
||||
|
||||
|
||||
/obj/item/voodoo
|
||||
name = "wicker doll"
|
||||
desc = "Something creepy about it."
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "voodoo"
|
||||
item_state = "electronic"
|
||||
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
|
||||
var/mob/living/carbon/human/target = null
|
||||
var/list/mob/living/carbon/human/possible = list()
|
||||
var/obj/item/voodoo_link = null
|
||||
var/cooldown_time = 30 //3s
|
||||
var/cooldown = 0
|
||||
max_integrity = 10
|
||||
resistance_flags = FLAMMABLE
|
||||
|
||||
/obj/item/voodoo/attackby(obj/item/I, mob/user, params)
|
||||
if(target && cooldown < world.time)
|
||||
if(I.is_hot())
|
||||
to_chat(target, "<span class='userdanger'>You suddenly feel very hot</span>")
|
||||
target.bodytemperature += 50
|
||||
GiveHint(target)
|
||||
else if(is_pointed(I))
|
||||
to_chat(target, "<span class='userdanger'>You feel a stabbing pain in [parse_zone(user.zone_selected)]!</span>")
|
||||
target.Knockdown(40)
|
||||
GiveHint(target)
|
||||
else if(istype(I, /obj/item/bikehorn))
|
||||
to_chat(target, "<span class='userdanger'>HONK</span>")
|
||||
SEND_SOUND(target, 'sound/items/airhorn.ogg')
|
||||
target.adjustEarDamage(0,3)
|
||||
GiveHint(target)
|
||||
cooldown = world.time +cooldown_time
|
||||
return
|
||||
|
||||
if(!voodoo_link)
|
||||
if(I.loc == user && istype(I) && I.w_class <= WEIGHT_CLASS_SMALL)
|
||||
if (user.transferItemToLoc(I,src))
|
||||
voodoo_link = I
|
||||
to_chat(user, "You attach [I] to the doll.")
|
||||
update_targets()
|
||||
|
||||
/obj/item/voodoo/check_eye(mob/user)
|
||||
if(loc != user)
|
||||
user.reset_perspective(null)
|
||||
user.unset_machine()
|
||||
|
||||
/obj/item/voodoo/attack_self(mob/user)
|
||||
if(!target && possible.len)
|
||||
target = input(user, "Select your victim!", "Voodoo") as null|anything in possible
|
||||
return
|
||||
|
||||
if(user.zone_selected == "chest")
|
||||
if(voodoo_link)
|
||||
target = null
|
||||
voodoo_link.forceMove(drop_location())
|
||||
to_chat(user, "<span class='notice'>You remove the [voodoo_link] from the doll.</span>")
|
||||
voodoo_link = null
|
||||
update_targets()
|
||||
return
|
||||
|
||||
if(target && cooldown < world.time)
|
||||
switch(user.zone_selected)
|
||||
if("mouth")
|
||||
var/wgw = sanitize(input(user, "What would you like the victim to say", "Voodoo", null) as text)
|
||||
target.say(wgw)
|
||||
log_game("[user][user.key] made [target][target.key] say [wgw] with a voodoo doll.")
|
||||
if("eyes")
|
||||
user.set_machine(src)
|
||||
user.reset_perspective(target)
|
||||
spawn(100)
|
||||
user.reset_perspective(null)
|
||||
user.unset_machine()
|
||||
if("r_leg","l_leg")
|
||||
to_chat(user, "<span class='notice'>You move the doll's legs around.</span>")
|
||||
var/turf/T = get_step(target,pick(GLOB.cardinals))
|
||||
target.Move(T)
|
||||
if("r_arm","l_arm")
|
||||
target.click_random_mob()
|
||||
GiveHint(target)
|
||||
if("head")
|
||||
to_chat(user, "<span class='notice'>You smack the doll's head with your hand.</span>")
|
||||
target.Dizzy(10)
|
||||
to_chat(target, "<span class='warning'>You suddenly feel as if your head was hit with a hammer!</span>")
|
||||
GiveHint(target,user)
|
||||
cooldown = world.time + cooldown_time
|
||||
|
||||
/obj/item/voodoo/proc/update_targets()
|
||||
possible = list()
|
||||
if(!voodoo_link)
|
||||
return
|
||||
var/list/prints = voodoo_link.return_fingerprints()
|
||||
if(!length(prints))
|
||||
return FALSE
|
||||
for(var/mob/living/carbon/human/H in GLOB.alive_mob_list)
|
||||
if(prints[md5(H.dna.uni_identity)])
|
||||
possible |= H
|
||||
|
||||
/obj/item/voodoo/proc/GiveHint(mob/victim,force=0)
|
||||
if(prob(50) || force)
|
||||
var/way = dir2text(get_dir(victim,get_turf(src)))
|
||||
to_chat(victim, "<span class='notice'>You feel a dark presence from [way]</span>")
|
||||
if(prob(20) || force)
|
||||
var/area/A = get_area(src)
|
||||
to_chat(victim, "<span class='notice'>You feel a dark presence from [A.name]</span>")
|
||||
|
||||
/obj/item/voodoo/suicide_act(mob/living/carbon/user)
|
||||
user.visible_message("<span class='suicide'>[user] links the voodoo doll to themself and sits on it, infinitely crushing themself! It looks like [user.p_theyre()] trying to commit suicide!</span>")
|
||||
user.gib()
|
||||
return(BRUTELOSS)
|
||||
|
||||
/obj/item/voodoo/fire_act(exposed_temperature, exposed_volume)
|
||||
if(target)
|
||||
target.adjust_fire_stacks(20)
|
||||
target.IgniteMob()
|
||||
GiveHint(target,1)
|
||||
return ..()
|
||||
|
||||
//Provides a decent heal, need to pump every 6 seconds
|
||||
/obj/item/organ/heart/cursed/wizard
|
||||
pump_delay = 60
|
||||
heal_brute = 25
|
||||
heal_burn = 25
|
||||
heal_oxy = 25
|
||||
|
||||
//Warp Whistle: Provides uncontrolled long distance teleportation.
|
||||
|
||||
/obj/item/warpwhistle
|
||||
name = "warp whistle"
|
||||
desc = "One toot on this whistle will send you to a far away land!"
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "whistle"
|
||||
var/on_cooldown = 0 //0: usable, 1: in use, 2: on cooldown
|
||||
var/mob/living/carbon/last_user
|
||||
|
||||
/obj/item/warpwhistle/proc/interrupted(mob/living/carbon/user)
|
||||
if(!user || QDELETED(src) || user.notransform)
|
||||
on_cooldown = FALSE
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/item/warpwhistle/attack_self(mob/living/carbon/user)
|
||||
if(!istype(user) || on_cooldown)
|
||||
return
|
||||
on_cooldown = TRUE
|
||||
last_user = user
|
||||
var/turf/T = get_turf(user)
|
||||
playsound(T,'sound/magic/warpwhistle.ogg', 200, 1)
|
||||
user.canmove = 0
|
||||
new /obj/effect/temp_visual/tornado(T)
|
||||
sleep(20)
|
||||
if(interrupted(user))
|
||||
return
|
||||
user.invisibility = INVISIBILITY_MAXIMUM
|
||||
user.status_flags |= GODMODE
|
||||
sleep(20)
|
||||
if(interrupted(user))
|
||||
return
|
||||
var/breakout = 0
|
||||
while(breakout < 50)
|
||||
var/turf/potential_T = find_safe_turf()
|
||||
if(T.z != potential_T.z || abs(get_dist_euclidian(potential_T,T)) > 50 - breakout)
|
||||
user.forceMove(potential_T)
|
||||
user.canmove = 0
|
||||
T = potential_T
|
||||
break
|
||||
breakout += 1
|
||||
new /obj/effect/temp_visual/tornado(T)
|
||||
sleep(20)
|
||||
if(interrupted(user))
|
||||
return
|
||||
user.invisibility = initial(user.invisibility)
|
||||
user.status_flags &= ~GODMODE
|
||||
user.canmove = 1
|
||||
on_cooldown = 2
|
||||
sleep(40)
|
||||
on_cooldown = 0
|
||||
|
||||
/obj/item/warpwhistle/Destroy()
|
||||
if(on_cooldown == 1 && last_user) //Flute got dunked somewhere in the teleport
|
||||
last_user.invisibility = initial(last_user.invisibility)
|
||||
last_user.status_flags &= ~GODMODE
|
||||
last_user.canmove = 1
|
||||
return ..()
|
||||
|
||||
/obj/effect/temp_visual/tornado
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "tornado"
|
||||
name = "tornado"
|
||||
desc = "This thing sucks!"
|
||||
layer = FLY_LAYER
|
||||
randomdir = 0
|
||||
duration = 40
|
||||
pixel_x = 500
|
||||
|
||||
/obj/effect/temp_visual/tornado/Initialize()
|
||||
. = ..()
|
||||
animate(src, pixel_x = -500, time = 40)
|
||||
@@ -1,164 +0,0 @@
|
||||
/datum/game_mode/wizard/raginmages
|
||||
name = "ragin' mages"
|
||||
config_tag = "raginmages"
|
||||
required_players = 20
|
||||
use_huds = 1
|
||||
announce_span = "userdanger"
|
||||
announce_text = "There are many, many wizards attacking the station!\n\
|
||||
<span class='danger'>Wizards</span>: Accomplish your objectives and cause utter catastrophe!\n\
|
||||
<span class='notice'>Crew</span>: Try not to die..."
|
||||
var/max_mages = 0
|
||||
var/making_mage = 0
|
||||
var/mages_made = 1
|
||||
var/time_checked = 0
|
||||
var/bullshit_mode = 0 // requested by hornygranny
|
||||
var/time_check = 1500
|
||||
var/spawn_delay_min = 500
|
||||
var/spawn_delay_max = 700
|
||||
|
||||
/datum/game_mode/wizard/raginmages/post_setup()
|
||||
..()
|
||||
var/playercount = 0
|
||||
if(!max_mages && !bullshit_mode)
|
||||
for(var/mob/living/player in GLOB.mob_list)
|
||||
if(player.client && player.stat != 2)
|
||||
playercount += 1
|
||||
max_mages = round(playercount / 8)
|
||||
if(max_mages > 20)
|
||||
max_mages = 20
|
||||
if(max_mages < 1)
|
||||
max_mages = 1
|
||||
if(bullshit_mode)
|
||||
max_mages = INFINITY
|
||||
/datum/game_mode/wizard/raginmages/greet_wizard(datum/mind/wizard, you_are=1)
|
||||
if (you_are)
|
||||
to_chat(wizard.current, "<B>You are the Space Wizard!</B>")
|
||||
wizard.current.playsound_local('sound/ambience/antag/RagesMages.ogg',100,0)
|
||||
to_chat(wizard.current, "<B>The Space Wizards Federation has given you the following tasks:</B>")
|
||||
|
||||
var/obj_count = 1
|
||||
to_chat(wizard.current, "<b>Objective Alpha</b>: Make sure the station pays for its actions against our diplomats")
|
||||
for(var/datum/objective/objective in wizard.objectives)
|
||||
to_chat(wizard.current, "<B>Objective #[obj_count]</B>: [objective.explanation_text]")
|
||||
obj_count++
|
||||
return
|
||||
|
||||
/datum/game_mode/wizard/raginmages/check_finished()
|
||||
var/wizards_alive = 0
|
||||
for(var/datum/mind/wizard in wizards)
|
||||
if(!istype(wizard.current,/mob/living/carbon))
|
||||
continue
|
||||
if(istype(wizard.current,/mob/living/brain))
|
||||
continue
|
||||
if(wizard.current.stat==DEAD)
|
||||
continue
|
||||
if(wizard.current.stat==UNCONSCIOUS)
|
||||
if(wizard.current.health < 0)
|
||||
to_chat(wizard.current, "<font size='4'>The Space Wizard Federation is upset with your performance and have terminated your employment.</font>")
|
||||
wizard.current.death()
|
||||
continue
|
||||
wizards_alive++
|
||||
if(!time_checked)
|
||||
time_checked = world.time
|
||||
if(bullshit_mode)
|
||||
if(world.time > time_checked + time_check)
|
||||
max_mages = INFINITY
|
||||
time_checked = world.time
|
||||
make_more_mages()
|
||||
return ..()
|
||||
if (wizards_alive)
|
||||
if(world.time > time_checked + time_check && (mages_made < max_mages))
|
||||
time_checked = world.time
|
||||
make_more_mages()
|
||||
|
||||
else
|
||||
if(mages_made >= max_mages)
|
||||
finished = 1
|
||||
return ..()
|
||||
else
|
||||
make_more_mages()
|
||||
return ..()
|
||||
|
||||
/datum/game_mode/wizard/raginmages/proc/make_more_mages()
|
||||
|
||||
if(making_mage)
|
||||
return 0
|
||||
if(mages_made >= max_mages)
|
||||
return 0
|
||||
making_mage = 1
|
||||
mages_made++
|
||||
var/list/mob/dead/observer/candidates = list()
|
||||
var/mob/dead/observer/theghost = null
|
||||
spawn(rand(spawn_delay_min, spawn_delay_max))
|
||||
message_admins("SWF is still pissed, sending another wizard - [max_mages - mages_made] left.")
|
||||
for(var/mob/dead/observer/G in GLOB.player_list)
|
||||
if(G.client && !G.client.holder && !G.client.is_afk() && (ROLE_WIZARD in G.client.prefs.be_special))
|
||||
if(!jobban_isbanned(G, ROLE_WIZARD) && !jobban_isbanned(G, "Syndicate"))
|
||||
if(age_check(G.client))
|
||||
candidates += G
|
||||
if(!candidates.len)
|
||||
message_admins("No applicable ghosts for the next ragin' mage, asking ghosts instead.")
|
||||
var/time_passed = world.time
|
||||
for(var/mob/dead/observer/G in GLOB.player_list)
|
||||
if(!jobban_isbanned(G, "wizard") && !jobban_isbanned(G, "Syndicate"))
|
||||
if(age_check(G.client))
|
||||
spawn(0)
|
||||
switch(alert(G, "Do you wish to be considered for the position of Space Wizard Foundation 'diplomat'?","Please answer in 30 seconds!","Yes","No"))
|
||||
if("Yes")
|
||||
if((world.time-time_passed)>300)//If more than 30 game seconds passed.
|
||||
continue
|
||||
candidates += G
|
||||
if("No")
|
||||
continue
|
||||
|
||||
sleep(300)
|
||||
if(!candidates.len)
|
||||
message_admins("This is awkward, sleeping until another mage check...")
|
||||
making_mage = 0
|
||||
mages_made--
|
||||
return
|
||||
else
|
||||
shuffle_inplace(candidates)
|
||||
for(var/mob/i in candidates)
|
||||
if(!i || !i.client) continue //Dont bother removing them from the list since we only grab one wizard
|
||||
|
||||
theghost = i
|
||||
break
|
||||
|
||||
if(theghost)
|
||||
var/mob/living/carbon/human/new_character= makeBody(theghost)
|
||||
new_character.mind.make_Wizard()
|
||||
making_mage = 0
|
||||
return 1
|
||||
|
||||
/datum/game_mode/wizard/raginmages/declare_completion()
|
||||
if(finished)
|
||||
SSticker.mode_result = "loss - wizard killed"
|
||||
to_chat(world, "<FONT size=3><B>The crew has managed to hold off the wizard attack! The Space Wizards Federation has been taught a lesson they will not soon forget!</B></FONT>")
|
||||
..(1)
|
||||
|
||||
/datum/game_mode/wizard/raginmages/proc/makeBody(mob/dead/observer/G_found) // Uses stripped down and bastardized code from respawn character
|
||||
if(!G_found || !G_found.key)
|
||||
return
|
||||
|
||||
//First we spawn a dude.
|
||||
var/mob/living/carbon/human/new_character = new//The mob being spawned.
|
||||
SSjob.SendToLateJoin(new_character)
|
||||
|
||||
G_found.client.prefs.copy_to(new_character)
|
||||
new_character.dna.update_dna_identity()
|
||||
new_character.key = G_found.key
|
||||
|
||||
return new_character
|
||||
|
||||
/datum/game_mode/wizard/raginmages/bullshit
|
||||
name = "very ragin' bullshit mages"
|
||||
config_tag = "veryraginbullshitmages"
|
||||
required_players = 20
|
||||
use_huds = 1
|
||||
bullshit_mode = 1
|
||||
time_check = 250
|
||||
spawn_delay_min = 50
|
||||
spawn_delay_max = 150
|
||||
announce_text = "<span class='userdanger'>CRAAAWLING IIIN MY SKIIIN\n\
|
||||
THESE WOOOUNDS THEY WIIIL NOT HEEEAL</span>"
|
||||
@@ -1,287 +0,0 @@
|
||||
/obj/item/device/soulstone
|
||||
name = "soulstone shard"
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "soulstone"
|
||||
item_state = "electronic"
|
||||
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
|
||||
layer = HIGH_OBJ_LAYER
|
||||
desc = "A fragment of the legendary treasure known simply as the 'Soul Stone'. The shard still flickers with a fraction of the full artefact's power."
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
slot_flags = SLOT_BELT
|
||||
var/usability = 0
|
||||
|
||||
var/old_shard = FALSE
|
||||
var/spent = FALSE
|
||||
|
||||
/obj/item/device/soulstone/proc/was_used()
|
||||
if(old_shard)
|
||||
spent = TRUE
|
||||
name = "dull [name]"
|
||||
desc = "A fragment of the legendary treasure known simply as \
|
||||
the 'Soul Stone'. The shard lies still, dull and lifeless; \
|
||||
whatever spark it once held long extinguished."
|
||||
|
||||
/obj/item/device/soulstone/anybody
|
||||
usability = 1
|
||||
|
||||
/obj/item/device/soulstone/anybody/chaplain
|
||||
name = "mysterious old shard"
|
||||
old_shard = TRUE
|
||||
|
||||
/obj/item/device/soulstone/pickup(mob/living/user)
|
||||
..()
|
||||
if(!iscultist(user) && !iswizard(user) && !usability)
|
||||
to_chat(user, "<span class='danger'>An overwhelming feeling of dread comes over you as you pick up the soulstone. It would be wise to be rid of this quickly.</span>")
|
||||
user.Dizzy(120)
|
||||
|
||||
/obj/item/device/soulstone/examine(mob/user)
|
||||
..()
|
||||
if(usability || iscultist(user) || iswizard(user) || isobserver(user))
|
||||
if (old_shard)
|
||||
to_chat(user, "<span class='cult'>A soulstone, used to capture a soul, either from dead humans or from freed shades.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='cult'>A soulstone, used to capture souls, either from unconscious or sleeping humans or from freed shades.</span>")
|
||||
to_chat(user, "<span class='cult'>The captured soul can be placed into a construct shell to produce a construct, or released from the stone as a shade.</span>")
|
||||
if(spent)
|
||||
to_chat(user, "<span class='cult'>This shard is spent; it is now just a creepy rock.</span>")
|
||||
|
||||
/obj/item/device/soulstone/Destroy() //Stops the shade from being qdel'd immediately and their ghost being sent back to the arrival shuttle.
|
||||
for(var/mob/living/simple_animal/shade/A in src)
|
||||
A.death()
|
||||
return ..()
|
||||
|
||||
//////////////////////////////Capturing////////////////////////////////////////////////////////
|
||||
|
||||
/obj/item/device/soulstone/attack(mob/living/carbon/human/M, mob/living/user)
|
||||
if(!iscultist(user) && !iswizard(user) && !usability)
|
||||
user.Unconscious(100)
|
||||
to_chat(user, "<span class='userdanger'>Your body is wracked with debilitating pain!</span>")
|
||||
return
|
||||
if(spent)
|
||||
to_chat(user, "<span class='warning'>There is no power left in the shard.</span>")
|
||||
return
|
||||
if(!ishuman(M))//If target is not a human.
|
||||
return ..()
|
||||
if(iscultist(M))
|
||||
to_chat(user, "<span class='cultlarge'>\"Come now, do not capture your bretheren's soul.\"</span>")
|
||||
return
|
||||
add_logs(user, M, "captured [M.name]'s soul", src)
|
||||
transfer_soul("VICTIM", M, user)
|
||||
|
||||
///////////////////Options for using captured souls///////////////////////////////////////
|
||||
|
||||
/obj/item/device/soulstone/attack_self(mob/living/user)
|
||||
if(!in_range(src, user))
|
||||
return
|
||||
if(!iscultist(user) && !iswizard(user) && !usability)
|
||||
user.Unconscious(100)
|
||||
to_chat(user, "<span class='userdanger'>Your body is wracked with debilitating pain!</span>")
|
||||
return
|
||||
release_shades(user)
|
||||
|
||||
/obj/item/device/soulstone/proc/release_shades(mob/user)
|
||||
for(var/mob/living/simple_animal/shade/A in src)
|
||||
A.status_flags &= ~GODMODE
|
||||
A.canmove = 1
|
||||
A.forceMove(get_turf(user))
|
||||
A.cancel_camera()
|
||||
icon_state = "soulstone"
|
||||
name = initial(name)
|
||||
if(iswizard(user) || usability)
|
||||
to_chat(A, "<b>You have been released from your prison, but you are still bound to [user.real_name]'s will. Help them succeed in their goals at all costs.</b>")
|
||||
else if(iscultist(user))
|
||||
to_chat(A, "<b>You have been released from your prison, but you are still bound to the cult's will. Help them succeed in their goals at all costs.</b>")
|
||||
was_used()
|
||||
|
||||
///////////////////////////Transferring to constructs/////////////////////////////////////////////////////
|
||||
/obj/structure/constructshell
|
||||
name = "empty shell"
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "construct-cult"
|
||||
desc = "A wicked machine used by those skilled in magical arts. It is inactive."
|
||||
|
||||
/obj/structure/constructshell/examine(mob/user)
|
||||
..()
|
||||
if(iscultist(user) || iswizard(user) || user.stat == DEAD)
|
||||
to_chat(user, "<span class='cult'>A construct shell, used to house bound souls from a soulstone.</span>")
|
||||
to_chat(user, "<span class='cult'>Placing a soulstone with a soul into this shell allows you to produce your choice of the following:</span>")
|
||||
to_chat(user, "<span class='cult'>An <b>Artificer</b>, which can produce <b>more shells and soulstones</b>, as well as fortifications.</span>")
|
||||
to_chat(user, "<span class='cult'>A <b>Wraith</b>, which does high damage and can jaunt through walls, though it is quite fragile.</span>")
|
||||
to_chat(user, "<span class='cult'>A <b>Juggernaut</b>, which is very hard to kill and can produce temporary walls, but is slow.</span>")
|
||||
|
||||
/obj/structure/constructshell/attackby(obj/item/O, mob/user, params)
|
||||
if(istype(O, /obj/item/device/soulstone))
|
||||
var/obj/item/device/soulstone/SS = O
|
||||
if(!iscultist(user) && !iswizard(user) && !SS.usability)
|
||||
to_chat(user, "<span class='danger'>An overwhelming feeling of dread comes over you as you attempt to place the soulstone into the shell. It would be wise to be rid of this quickly.</span>")
|
||||
user.Dizzy(120)
|
||||
return
|
||||
SS.transfer_soul("CONSTRUCT",src,user)
|
||||
SS.was_used()
|
||||
else
|
||||
return ..()
|
||||
|
||||
////////////////////////////Proc for moving soul in and out off stone//////////////////////////////////////
|
||||
|
||||
|
||||
/obj/item/device/soulstone/proc/transfer_soul(choice as text, target, mob/user)
|
||||
switch(choice)
|
||||
if("FORCE")
|
||||
if(!iscarbon(target)) //TODO: Add sacrifice stoning for non-organics, just because you have no body doesnt mean you dont have a soul
|
||||
return 0
|
||||
if(contents.len)
|
||||
return 0
|
||||
var/mob/living/carbon/T = target
|
||||
if(T.client != null)
|
||||
for(var/obj/item/W in T)
|
||||
T.dropItemToGround(W)
|
||||
init_shade(T, user)
|
||||
return 1
|
||||
else
|
||||
to_chat(user, "<span class='userdanger'>Capture failed!</span>: The soul has already fled its mortal frame. You attempt to bring it back...")
|
||||
return getCultGhost(T,user)
|
||||
|
||||
if("VICTIM")
|
||||
var/mob/living/carbon/human/T = target
|
||||
var/datum/antagonist/cult/C = user.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
|
||||
if(C && C.cult_team.is_sacrifice_target(T.mind))
|
||||
if(iscultist(user))
|
||||
to_chat(user, "<span class='cult'><b>\"This soul is mine.</b></span> <span class='cultlarge'>SACRIFICE THEM!\"</span>")
|
||||
else
|
||||
to_chat(user, "<span class='danger'>The soulstone seems to reject this soul.</span>")
|
||||
return 0
|
||||
if(contents.len)
|
||||
to_chat(user, "<span class='userdanger'>Capture failed!</span>: The soulstone is full! Free an existing soul to make room.")
|
||||
else
|
||||
if((!old_shard && T.stat != CONSCIOUS) || (old_shard && T.stat == DEAD))
|
||||
if(T.client == null)
|
||||
to_chat(user, "<span class='userdanger'>Capture failed!</span>: The soul has already fled its mortal frame. You attempt to bring it back...")
|
||||
getCultGhost(T,user)
|
||||
else
|
||||
for(var/obj/item/W in T)
|
||||
T.dropItemToGround(W)
|
||||
init_shade(T, user, vic = 1)
|
||||
qdel(T)
|
||||
else
|
||||
to_chat(user, "<span class='userdanger'>Capture failed!</span>: Kill or maim the victim first!")
|
||||
|
||||
if("SHADE")
|
||||
var/mob/living/simple_animal/shade/T = target
|
||||
if(contents.len)
|
||||
to_chat(user, "<span class='userdanger'>Capture failed!</span>: The soulstone is full! Free an existing soul to make room.")
|
||||
else
|
||||
T.forceMove(src) //put shade in stone
|
||||
T.status_flags |= GODMODE
|
||||
T.canmove = 0
|
||||
T.health = T.maxHealth
|
||||
icon_state = "soulstone2"
|
||||
name = "soulstone: Shade of [T.real_name]"
|
||||
to_chat(T, "<span class='notice'>Your soul has been captured by the soulstone. Its arcane energies are reknitting your ethereal form.</span>")
|
||||
if(user != T)
|
||||
to_chat(user, "<span class='info'><b>Capture successful!</b>:</span> [T.real_name]'s soul has been captured and stored within the soulstone.")
|
||||
|
||||
if("CONSTRUCT")
|
||||
var/obj/structure/constructshell/T = target
|
||||
var/mob/living/simple_animal/shade/A = locate() in src
|
||||
if(A)
|
||||
var/construct_class = alert(user, "Please choose which type of construct you wish to create.",,"Juggernaut","Wraith","Artificer")
|
||||
if(!T || !T.loc)
|
||||
return
|
||||
switch(construct_class)
|
||||
if("Juggernaut")
|
||||
makeNewConstruct(/mob/living/simple_animal/hostile/construct/armored, A, user, 0, T.loc)
|
||||
|
||||
if("Wraith")
|
||||
makeNewConstruct(/mob/living/simple_animal/hostile/construct/wraith, A, user, 0, T.loc)
|
||||
|
||||
if("Artificer")
|
||||
if(iscultist(user) || iswizard(user))
|
||||
makeNewConstruct(/mob/living/simple_animal/hostile/construct/builder, A, user, 0, T.loc)
|
||||
|
||||
else
|
||||
makeNewConstruct(/mob/living/simple_animal/hostile/construct/builder/noncult, A, user, 0, T.loc)
|
||||
for(var/datum/mind/B in SSticker.mode.cult)
|
||||
if(B == A.mind)
|
||||
SSticker.mode.cult -= A.mind
|
||||
SSticker.mode.update_cult_icons_removed(A.mind)
|
||||
qdel(T)
|
||||
qdel(src)
|
||||
else
|
||||
to_chat(user, "<span class='userdanger'>Creation failed!</span>: The soul stone is empty! Go kill someone!")
|
||||
|
||||
|
||||
/proc/makeNewConstruct(mob/living/simple_animal/hostile/construct/ctype, mob/target, mob/stoner = null, cultoverride = 0, loc_override = null)
|
||||
var/mob/living/simple_animal/hostile/construct/newstruct = new ctype((loc_override) ? (loc_override) : (get_turf(target)))
|
||||
if(stoner)
|
||||
newstruct.faction |= "[REF(stoner)]"
|
||||
newstruct.master = stoner
|
||||
var/datum/action/innate/seek_master/SM = new()
|
||||
SM.Grant(newstruct)
|
||||
newstruct.key = target.key
|
||||
var/obj/screen/alert/bloodsense/BS
|
||||
if(newstruct.mind && ((stoner && iscultist(stoner)) || cultoverride) && SSticker && SSticker.mode)
|
||||
SSticker.mode.add_cultist(newstruct.mind, 0)
|
||||
if(iscultist(stoner) || cultoverride)
|
||||
to_chat(newstruct, "<b>You are still bound to serve the cult[stoner ? " and [stoner]":""], follow their orders and help them complete their goals at all costs.</b>")
|
||||
else if(stoner)
|
||||
to_chat(newstruct, "<b>You are still bound to serve your creator, [stoner], follow their orders and help them complete their goals at all costs.</b>")
|
||||
newstruct.clear_alert("bloodsense")
|
||||
BS = newstruct.throw_alert("bloodsense", /obj/screen/alert/bloodsense)
|
||||
if(BS)
|
||||
BS.Cviewer = newstruct
|
||||
newstruct.cancel_camera()
|
||||
|
||||
|
||||
/obj/item/device/soulstone/proc/init_shade(mob/living/carbon/human/T, mob/U, vic = 0)
|
||||
new /obj/effect/decal/remains/human(T.loc) //Spawns a skeleton
|
||||
T.stop_sound_channel(CHANNEL_HEARTBEAT)
|
||||
T.invisibility = INVISIBILITY_ABSTRACT
|
||||
T.dust_animation()
|
||||
var/mob/living/simple_animal/shade/S = new /mob/living/simple_animal/shade(src)
|
||||
S.status_flags |= GODMODE //So they won't die inside the stone somehow
|
||||
S.canmove = 0//Can't move out of the soul stone
|
||||
S.name = "Shade of [T.real_name]"
|
||||
S.real_name = "Shade of [T.real_name]"
|
||||
S.key = T.key
|
||||
S.language_holder = U.language_holder.copy(S)
|
||||
if(U)
|
||||
S.faction |= "[REF(U)]" //Add the master as a faction, allowing inter-mob cooperation
|
||||
if(U && iscultist(U))
|
||||
SSticker.mode.add_cultist(S.mind, 0)
|
||||
S.cancel_camera()
|
||||
name = "soulstone: Shade of [T.real_name]"
|
||||
icon_state = "soulstone2"
|
||||
if(U && (iswizard(U) || usability))
|
||||
to_chat(S, "Your soul has been captured! You are now bound to [U.real_name]'s will. Help them succeed in their goals at all costs.")
|
||||
else if(U && iscultist(U))
|
||||
to_chat(S, "Your soul has been captured! You are now bound to the cult's will. Help them succeed in their goals at all costs.")
|
||||
if(vic && U)
|
||||
to_chat(U, "<span class='info'><b>Capture successful!</b>:</span> [T.real_name]'s soul has been ripped from their body and stored within the soul stone.")
|
||||
|
||||
|
||||
/obj/item/device/soulstone/proc/getCultGhost(mob/living/carbon/human/T, mob/U)
|
||||
var/mob/dead/observer/chosen_ghost
|
||||
|
||||
for(var/mob/dead/observer/ghost in GLOB.player_list) //We put them back in their body
|
||||
if(ghost.mind && ghost.mind.current == T && ghost.client)
|
||||
chosen_ghost = ghost
|
||||
break
|
||||
|
||||
if(!chosen_ghost) //Failing that, we grab a ghost
|
||||
var/list/consenting_candidates = pollGhostCandidates("Would you like to play as a Shade?", "Cultist", null, ROLE_CULTIST, poll_time = 50)
|
||||
if(consenting_candidates.len)
|
||||
chosen_ghost = pick(consenting_candidates)
|
||||
if(!T)
|
||||
return 0
|
||||
if(!chosen_ghost)
|
||||
to_chat(U, "<span class='danger'>There were no spirits willing to become a shade.</span>")
|
||||
return 0
|
||||
if(contents.len) //If they used the soulstone on someone else in the meantime
|
||||
return 0
|
||||
T.ckey = chosen_ghost.ckey
|
||||
for(var/obj/item/W in T)
|
||||
T.dropItemToGround(W)
|
||||
init_shade(T, U)
|
||||
qdel(T)
|
||||
return 1
|
||||
@@ -1,908 +0,0 @@
|
||||
/datum/spellbook_entry
|
||||
var/name = "Entry Name"
|
||||
|
||||
var/spell_type = null
|
||||
var/desc = ""
|
||||
var/category = "Offensive"
|
||||
var/cost = 2
|
||||
var/refundable = 1
|
||||
var/surplus = -1 // -1 for infinite, not used by anything atm
|
||||
var/obj/effect/proc_holder/spell/S = null //Since spellbooks can be used by only one person anyway we can track the actual spell
|
||||
var/buy_word = "Learn"
|
||||
var/limit //used to prevent a spellbook_entry from being bought more than X times with one wizard spellbook
|
||||
var/list/no_coexistance_typecache //Used so you can't have specific spells together
|
||||
|
||||
/datum/spellbook_entry/New()
|
||||
..()
|
||||
no_coexistance_typecache = typecacheof(no_coexistance_typecache)
|
||||
|
||||
/datum/spellbook_entry/proc/IsAvailible() // For config prefs / gamemode restrictions - these are round applied
|
||||
return 1
|
||||
|
||||
/datum/spellbook_entry/proc/CanBuy(mob/living/carbon/human/user,obj/item/spellbook/book) // Specific circumstances
|
||||
if(book.uses<cost || limit == 0)
|
||||
return 0
|
||||
for(var/spell in user.mind.spell_list)
|
||||
if(is_type_in_typecache(spell, no_coexistance_typecache))
|
||||
return 0
|
||||
return 1
|
||||
|
||||
/datum/spellbook_entry/proc/Buy(mob/living/carbon/human/user,obj/item/spellbook/book) //return 1 on success
|
||||
if(!S || QDELETED(S))
|
||||
S = new spell_type()
|
||||
//Check if we got the spell already
|
||||
for(var/obj/effect/proc_holder/spell/aspell in user.mind.spell_list)
|
||||
if(initial(S.name) == initial(aspell.name)) // Not using directly in case it was learned from one spellbook then upgraded in another
|
||||
if(aspell.spell_level >= aspell.level_max)
|
||||
to_chat(user, "<span class='warning'>This spell cannot be improved further.</span>")
|
||||
return 0
|
||||
else
|
||||
aspell.name = initial(aspell.name)
|
||||
aspell.spell_level++
|
||||
aspell.charge_max = round(initial(aspell.charge_max) - aspell.spell_level * (initial(aspell.charge_max) - aspell.cooldown_min)/ aspell.level_max)
|
||||
if(aspell.charge_max < aspell.charge_counter)
|
||||
aspell.charge_counter = aspell.charge_max
|
||||
switch(aspell.spell_level)
|
||||
if(1)
|
||||
to_chat(user, "<span class='notice'>You have improved [aspell.name] into Efficient [aspell.name].</span>")
|
||||
aspell.name = "Efficient [aspell.name]"
|
||||
if(2)
|
||||
to_chat(user, "<span class='notice'>You have further improved [aspell.name] into Quickened [aspell.name].</span>")
|
||||
aspell.name = "Quickened [aspell.name]"
|
||||
if(3)
|
||||
to_chat(user, "<span class='notice'>You have further improved [aspell.name] into Free [aspell.name].</span>")
|
||||
aspell.name = "Free [aspell.name]"
|
||||
if(4)
|
||||
to_chat(user, "<span class='notice'>You have further improved [aspell.name] into Instant [aspell.name].</span>")
|
||||
aspell.name = "Instant [aspell.name]"
|
||||
if(aspell.spell_level >= aspell.level_max)
|
||||
to_chat(user, "<span class='notice'>This spell cannot be strengthened any further.</span>")
|
||||
SSblackbox.record_feedback("nested tally", "wizard_spell_improved", 1, list("[name]", "[aspell.spell_level]"))
|
||||
return 1
|
||||
//No same spell found - just learn it
|
||||
SSblackbox.record_feedback("tally", "wizard_spell_learned", 1, name)
|
||||
user.mind.AddSpell(S)
|
||||
to_chat(user, "<span class='notice'>You have learned [S.name].</span>")
|
||||
return 1
|
||||
|
||||
/datum/spellbook_entry/proc/CanRefund(mob/living/carbon/human/user,obj/item/spellbook/book)
|
||||
if(!refundable)
|
||||
return 0
|
||||
if(!S)
|
||||
S = new spell_type()
|
||||
for(var/obj/effect/proc_holder/spell/aspell in user.mind.spell_list)
|
||||
if(initial(S.name) == initial(aspell.name))
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/datum/spellbook_entry/proc/Refund(mob/living/carbon/human/user,obj/item/spellbook/book) //return point value or -1 for failure
|
||||
var/area/wizard_station/A = locate() in GLOB.sortedAreas
|
||||
if(!(user in A.contents))
|
||||
to_chat(user, "<span class='warning'>You can only refund spells at the wizard lair</span>")
|
||||
return -1
|
||||
if(!S)
|
||||
S = new spell_type()
|
||||
var/spell_levels = 0
|
||||
for(var/obj/effect/proc_holder/spell/aspell in user.mind.spell_list)
|
||||
if(initial(S.name) == initial(aspell.name))
|
||||
spell_levels = aspell.spell_level
|
||||
user.mind.spell_list.Remove(aspell)
|
||||
qdel(S)
|
||||
return cost * (spell_levels+1)
|
||||
return -1
|
||||
/datum/spellbook_entry/proc/GetInfo()
|
||||
if(!S)
|
||||
S = new spell_type()
|
||||
var/dat =""
|
||||
dat += "<b>[initial(S.name)]</b>"
|
||||
if(S.charge_type == "recharge")
|
||||
dat += " Cooldown:[S.charge_max/10]"
|
||||
dat += " Cost:[cost]<br>"
|
||||
dat += "<i>[S.desc][desc]</i><br>"
|
||||
dat += "[S.clothes_req?"Needs wizard garb":"Can be cast without wizard garb"]<br>"
|
||||
return dat
|
||||
|
||||
/datum/spellbook_entry/fireball
|
||||
name = "Fireball"
|
||||
spell_type = /obj/effect/proc_holder/spell/aimed/fireball
|
||||
|
||||
/datum/spellbook_entry/rod_form
|
||||
name = "Rod Form"
|
||||
spell_type = /obj/effect/proc_holder/spell/targeted/rod_form
|
||||
|
||||
/datum/spellbook_entry/magicm
|
||||
name = "Magic Missile"
|
||||
spell_type = /obj/effect/proc_holder/spell/targeted/projectile/magic_missile
|
||||
category = "Defensive"
|
||||
|
||||
/datum/spellbook_entry/disintegrate
|
||||
name = "Disintegrate"
|
||||
spell_type = /obj/effect/proc_holder/spell/targeted/touch/disintegrate
|
||||
|
||||
/datum/spellbook_entry/disabletech
|
||||
name = "Disable Tech"
|
||||
spell_type = /obj/effect/proc_holder/spell/targeted/emplosion/disable_tech
|
||||
category = "Defensive"
|
||||
cost = 1
|
||||
|
||||
/datum/spellbook_entry/repulse
|
||||
name = "Repulse"
|
||||
spell_type = /obj/effect/proc_holder/spell/aoe_turf/repulse
|
||||
category = "Defensive"
|
||||
|
||||
/datum/spellbook_entry/lightningPacket
|
||||
name = "Lightning bolt! Lightning bolt!"
|
||||
spell_type = /obj/effect/proc_holder/spell/targeted/conjure_item/spellpacket
|
||||
category = "Defensive"
|
||||
|
||||
/datum/spellbook_entry/timestop
|
||||
name = "Time Stop"
|
||||
spell_type = /obj/effect/proc_holder/spell/aoe_turf/conjure/timestop
|
||||
category = "Defensive"
|
||||
|
||||
/datum/spellbook_entry/smoke
|
||||
name = "Smoke"
|
||||
spell_type = /obj/effect/proc_holder/spell/targeted/smoke
|
||||
category = "Defensive"
|
||||
cost = 1
|
||||
|
||||
/datum/spellbook_entry/blind
|
||||
name = "Blind"
|
||||
spell_type = /obj/effect/proc_holder/spell/targeted/trigger/blind
|
||||
cost = 1
|
||||
|
||||
/datum/spellbook_entry/mindswap
|
||||
name = "Mindswap"
|
||||
spell_type = /obj/effect/proc_holder/spell/targeted/mind_transfer
|
||||
category = "Mobility"
|
||||
|
||||
/datum/spellbook_entry/forcewall
|
||||
name = "Force Wall"
|
||||
spell_type = /obj/effect/proc_holder/spell/targeted/forcewall
|
||||
category = "Defensive"
|
||||
cost = 1
|
||||
|
||||
/datum/spellbook_entry/blink
|
||||
name = "Blink"
|
||||
spell_type = /obj/effect/proc_holder/spell/targeted/turf_teleport/blink
|
||||
category = "Mobility"
|
||||
|
||||
/datum/spellbook_entry/teleport
|
||||
name = "Teleport"
|
||||
spell_type = /obj/effect/proc_holder/spell/targeted/area_teleport/teleport
|
||||
category = "Mobility"
|
||||
|
||||
/datum/spellbook_entry/mutate
|
||||
name = "Mutate"
|
||||
spell_type = /obj/effect/proc_holder/spell/targeted/genetic/mutate
|
||||
|
||||
/datum/spellbook_entry/jaunt
|
||||
name = "Ethereal Jaunt"
|
||||
spell_type = /obj/effect/proc_holder/spell/targeted/ethereal_jaunt
|
||||
category = "Mobility"
|
||||
|
||||
/datum/spellbook_entry/knock
|
||||
name = "Knock"
|
||||
spell_type = /obj/effect/proc_holder/spell/aoe_turf/knock
|
||||
category = "Mobility"
|
||||
cost = 1
|
||||
|
||||
/datum/spellbook_entry/fleshtostone
|
||||
name = "Flesh to Stone"
|
||||
spell_type = /obj/effect/proc_holder/spell/targeted/touch/flesh_to_stone
|
||||
|
||||
/datum/spellbook_entry/summonitem
|
||||
name = "Summon Item"
|
||||
spell_type = /obj/effect/proc_holder/spell/targeted/summonitem
|
||||
category = "Assistance"
|
||||
cost = 1
|
||||
|
||||
/datum/spellbook_entry/lichdom
|
||||
name = "Bind Soul"
|
||||
spell_type = /obj/effect/proc_holder/spell/targeted/lichdom
|
||||
category = "Defensive"
|
||||
|
||||
/datum/spellbook_entry/teslablast
|
||||
name = "Tesla Blast"
|
||||
spell_type = /obj/effect/proc_holder/spell/targeted/tesla
|
||||
|
||||
/datum/spellbook_entry/lightningbolt
|
||||
name = "Lightning Bolt"
|
||||
spell_type = /obj/effect/proc_holder/spell/aimed/lightningbolt
|
||||
cost = 3
|
||||
|
||||
/datum/spellbook_entry/lightningbolt/Buy(mob/living/carbon/human/user,obj/item/spellbook/book) //return 1 on success
|
||||
. = ..()
|
||||
user.flags_2 |= TESLA_IGNORE_2
|
||||
|
||||
/datum/spellbook_entry/infinite_guns
|
||||
name = "Lesser Summon Guns"
|
||||
spell_type = /obj/effect/proc_holder/spell/targeted/infinite_guns/gun
|
||||
cost = 3
|
||||
no_coexistance_typecache = /obj/effect/proc_holder/spell/targeted/infinite_guns/arcane_barrage
|
||||
|
||||
/datum/spellbook_entry/arcane_barrage
|
||||
name = "Arcane Barrage"
|
||||
spell_type = /obj/effect/proc_holder/spell/targeted/infinite_guns/arcane_barrage
|
||||
cost = 3
|
||||
no_coexistance_typecache = /obj/effect/proc_holder/spell/targeted/infinite_guns/gun
|
||||
|
||||
/datum/spellbook_entry/barnyard
|
||||
name = "Barnyard Curse"
|
||||
spell_type = /obj/effect/proc_holder/spell/targeted/barnyardcurse
|
||||
|
||||
/datum/spellbook_entry/charge
|
||||
name = "Charge"
|
||||
spell_type = /obj/effect/proc_holder/spell/targeted/charge
|
||||
category = "Assistance"
|
||||
cost = 1
|
||||
|
||||
/datum/spellbook_entry/shapeshift
|
||||
name = "Wild Shapeshift"
|
||||
spell_type = /obj/effect/proc_holder/spell/targeted/shapeshift
|
||||
category = "Assistance"
|
||||
cost = 1
|
||||
|
||||
/datum/spellbook_entry/spacetime_dist
|
||||
name = "Spacetime Distortion"
|
||||
spell_type = /obj/effect/proc_holder/spell/spacetime_dist
|
||||
category = "Defensive"
|
||||
cost = 1
|
||||
|
||||
/datum/spellbook_entry/the_traps
|
||||
name = "The Traps!"
|
||||
spell_type = /obj/effect/proc_holder/spell/aoe_turf/conjure/the_traps
|
||||
category = "Defensive"
|
||||
cost = 1
|
||||
|
||||
|
||||
/datum/spellbook_entry/item
|
||||
name = "Buy Item"
|
||||
refundable = 0
|
||||
buy_word = "Summon"
|
||||
var/item_path= null
|
||||
|
||||
|
||||
/datum/spellbook_entry/item/Buy(mob/living/carbon/human/user,obj/item/spellbook/book)
|
||||
new item_path(get_turf(user))
|
||||
SSblackbox.record_feedback("tally", "wizard_spell_learned", 1, name)
|
||||
return 1
|
||||
|
||||
/datum/spellbook_entry/item/GetInfo()
|
||||
var/dat =""
|
||||
dat += "<b>[name]</b>"
|
||||
dat += " Cost:[cost]<br>"
|
||||
dat += "<i>[desc]</i><br>"
|
||||
if(surplus>=0)
|
||||
dat += "[surplus] left.<br>"
|
||||
return dat
|
||||
|
||||
/datum/spellbook_entry/item/staffchange
|
||||
name = "Staff of Change"
|
||||
desc = "An artefact that spits bolts of coruscating energy which cause the target's very form to reshape itself."
|
||||
item_path = /obj/item/gun/magic/staff/change
|
||||
|
||||
/datum/spellbook_entry/item/staffanimation
|
||||
name = "Staff of Animation"
|
||||
desc = "An arcane staff capable of shooting bolts of eldritch energy which cause inanimate objects to come to life. This magic doesn't affect machines."
|
||||
item_path = /obj/item/gun/magic/staff/animate
|
||||
category = "Assistance"
|
||||
|
||||
/datum/spellbook_entry/item/staffchaos
|
||||
name = "Staff of Chaos"
|
||||
desc = "A caprious tool that can fire all sorts of magic without any rhyme or reason. Using it on people you care about is not recommended."
|
||||
item_path = /obj/item/gun/magic/staff/chaos
|
||||
|
||||
/datum/spellbook_entry/item/spellblade
|
||||
name = "Spellblade"
|
||||
desc = "A sword capable of firing blasts of energy which rip targets limb from limb."
|
||||
item_path = /obj/item/gun/magic/staff/spellblade
|
||||
|
||||
/datum/spellbook_entry/item/staffdoor
|
||||
name = "Staff of Door Creation"
|
||||
desc = "A particular staff that can mold solid metal into ornate doors. Useful for getting around in the absence of other transportation. Does not work on glass."
|
||||
item_path = /obj/item/gun/magic/staff/door
|
||||
cost = 1
|
||||
category = "Mobility"
|
||||
|
||||
/datum/spellbook_entry/item/staffhealing
|
||||
name = "Staff of Healing"
|
||||
desc = "An altruistic staff that can heal the lame and raise the dead."
|
||||
item_path = /obj/item/gun/magic/staff/healing
|
||||
cost = 1
|
||||
category = "Defensive"
|
||||
|
||||
/datum/spellbook_entry/item/scryingorb
|
||||
name = "Scrying Orb"
|
||||
desc = "An incandescent orb of crackling energy, using it will allow you to ghost while alive, allowing you to spy upon the station with ease. In addition, buying it will permanently grant you x-ray vision."
|
||||
item_path = /obj/item/scrying
|
||||
category = "Defensive"
|
||||
|
||||
/datum/spellbook_entry/item/soulstones
|
||||
name = "Six Soul Stone Shards and the spell Artificer"
|
||||
desc = "Soul Stone Shards are ancient tools capable of capturing and harnessing the spirits of the dead and dying. The spell Artificer allows you to create arcane machines for the captured souls to pilot."
|
||||
item_path = /obj/item/storage/belt/soulstone/full
|
||||
category = "Assistance"
|
||||
|
||||
/datum/spellbook_entry/item/soulstones/Buy(mob/living/carbon/human/user,obj/item/spellbook/book)
|
||||
. =..()
|
||||
if(.)
|
||||
user.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/conjure/construct(null))
|
||||
return .
|
||||
|
||||
/datum/spellbook_entry/item/necrostone
|
||||
name = "A Necromantic Stone"
|
||||
desc = "A Necromantic stone is able to resurrect three dead individuals as skeletal thralls for you to command."
|
||||
item_path = /obj/item/device/necromantic_stone
|
||||
category = "Assistance"
|
||||
|
||||
/datum/spellbook_entry/item/wands
|
||||
name = "Wand Assortment"
|
||||
desc = "A collection of wands that allow for a wide variety of utility. Wands have a limited number of charges, so be conservative in use. Comes in a handy belt."
|
||||
item_path = /obj/item/storage/belt/wands/full
|
||||
category = "Defensive"
|
||||
|
||||
/datum/spellbook_entry/item/armor
|
||||
name = "Mastercrafted Armor Set"
|
||||
desc = "An artefact suit of armor that allows you to cast spells while providing more protection against attacks and the void of space."
|
||||
item_path = /obj/item/clothing/suit/space/hardsuit/wizard
|
||||
category = "Defensive"
|
||||
|
||||
/datum/spellbook_entry/item/armor/Buy(mob/living/carbon/human/user,obj/item/spellbook/book)
|
||||
. = ..()
|
||||
if(.)
|
||||
new /obj/item/clothing/shoes/sandal/magic(get_turf(user)) //In case they've lost them.
|
||||
new /obj/item/clothing/gloves/color/purple(get_turf(user))//To complete the outfit
|
||||
|
||||
/datum/spellbook_entry/item/contract
|
||||
name = "Contract of Apprenticeship"
|
||||
desc = "A magical contract binding an apprentice wizard to your service, using it will summon them to your side."
|
||||
item_path = /obj/item/antag_spawner/contract
|
||||
category = "Assistance"
|
||||
|
||||
/datum/spellbook_entry/item/guardian
|
||||
name = "Guardian Deck"
|
||||
desc = "A deck of guardian tarot cards, capable of binding a personal guardian to your body. There are multiple types of guardian available, but all of them will transfer some amount of damage to you. \
|
||||
It would be wise to avoid buying these with anything capable of causing you to swap bodies with others."
|
||||
item_path = /obj/item/guardiancreator/choose/wizard
|
||||
category = "Assistance"
|
||||
|
||||
/datum/spellbook_entry/item/guardian/Buy(mob/living/carbon/human/user,obj/item/spellbook/book)
|
||||
. = ..()
|
||||
if(.)
|
||||
new /obj/item/paper/guides/antag/guardian/wizard(get_turf(user))
|
||||
|
||||
/datum/spellbook_entry/item/bloodbottle
|
||||
name = "Bottle of Blood"
|
||||
desc = "A bottle of magically infused blood, the smell of which will attract extradimensional beings when broken. Be careful though, the kinds of creatures summoned by blood magic are indiscriminate in their killing, and you yourself may become a victim."
|
||||
item_path = /obj/item/antag_spawner/slaughter_demon
|
||||
limit = 3
|
||||
category = "Assistance"
|
||||
|
||||
/datum/spellbook_entry/item/hugbottle
|
||||
name = "Bottle of Tickles"
|
||||
desc = "A bottle of magically infused fun, the smell of which will \
|
||||
attract adorable extradimensional beings when broken. These beings \
|
||||
are similar to slaughter demons, but they do not permamently kill \
|
||||
their victims, instead putting them in an extradimensional hugspace, \
|
||||
to be released on the demon's death. Chaotic, but not ultimately \
|
||||
damaging. The crew's reaction to the other hand could be very \
|
||||
destructive."
|
||||
item_path = /obj/item/antag_spawner/slaughter_demon/laughter
|
||||
cost = 1 //non-destructive; it's just a jape, sibling!
|
||||
limit = 3
|
||||
category = "Assistance"
|
||||
|
||||
/datum/spellbook_entry/item/mjolnir
|
||||
name = "Mjolnir"
|
||||
desc = "A mighty hammer on loan from Thor, God of Thunder. It crackles with barely contained power."
|
||||
item_path = /obj/item/twohanded/mjollnir
|
||||
|
||||
/datum/spellbook_entry/item/singularity_hammer
|
||||
name = "Singularity Hammer"
|
||||
desc = "A hammer that creates an intensely powerful field of gravity where it strikes, pulling everything nearby to the point of impact."
|
||||
item_path = /obj/item/twohanded/singularityhammer
|
||||
|
||||
/datum/spellbook_entry/item/battlemage
|
||||
name = "Battlemage Armour"
|
||||
desc = "An ensorcelled suit of armour, protected by a powerful shield. The shield can completly negate sixteen attacks before being permanently depleted."
|
||||
item_path = /obj/item/clothing/suit/space/hardsuit/shielded/wizard
|
||||
limit = 1
|
||||
category = "Defensive"
|
||||
|
||||
/datum/spellbook_entry/item/battlemage_charge
|
||||
name = "Battlemage Armour Charges"
|
||||
desc = "A powerful defensive rune, it will grant eight additional charges to a suit of battlemage armour."
|
||||
item_path = /obj/item/wizard_armour_charge
|
||||
category = "Defensive"
|
||||
cost = 1
|
||||
|
||||
/datum/spellbook_entry/item/warpwhistle
|
||||
name = "Warp Whistle"
|
||||
desc = "A strange whistle that will transport you to a distant safe place on the station. There is a window of vulnerability at the beginning of every use."
|
||||
item_path = /obj/item/warpwhistle
|
||||
category = "Mobility"
|
||||
cost = 1
|
||||
|
||||
/datum/spellbook_entry/summon
|
||||
name = "Summon Stuff"
|
||||
category = "Rituals"
|
||||
refundable = 0
|
||||
buy_word = "Cast"
|
||||
var/active = 0
|
||||
|
||||
/datum/spellbook_entry/summon/CanBuy(mob/living/carbon/human/user,obj/item/spellbook/book)
|
||||
return ..() && !active
|
||||
|
||||
/datum/spellbook_entry/summon/GetInfo()
|
||||
var/dat =""
|
||||
dat += "<b>[name]</b>"
|
||||
if(cost>0)
|
||||
dat += " Cost:[cost]<br>"
|
||||
else
|
||||
dat += " No Cost<br>"
|
||||
dat += "<i>[desc]</i><br>"
|
||||
if(active)
|
||||
dat += "<b>Already cast!</b><br>"
|
||||
return dat
|
||||
|
||||
/datum/spellbook_entry/summon/ghosts
|
||||
name = "Summon Ghosts"
|
||||
desc = "Spook the crew out by making them see dead people. Be warned, ghosts are capricious and occasionally vindicative, and some will use their incredibly minor abilties to frustrate you."
|
||||
cost = 0
|
||||
|
||||
/datum/spellbook_entry/summon/ghosts/IsAvailible()
|
||||
if(!SSticker.mode)
|
||||
return FALSE
|
||||
else
|
||||
return TRUE
|
||||
|
||||
/datum/spellbook_entry/summon/ghosts/Buy(mob/living/carbon/human/user, obj/item/spellbook/book)
|
||||
SSblackbox.record_feedback("tally", "wizard_spell_learned", 1, name)
|
||||
new /datum/round_event/wizard/ghost()
|
||||
active = TRUE
|
||||
to_chat(user, "<span class='notice'>You have cast summon ghosts!</span>")
|
||||
playsound(get_turf(user), 'sound/effects/ghost2.ogg', 50, 1)
|
||||
return TRUE
|
||||
|
||||
/datum/spellbook_entry/summon/guns
|
||||
name = "Summon Guns"
|
||||
desc = "Nothing could possibly go wrong with arming a crew of lunatics just itching for an excuse to kill you. Just be careful not to stand still too long!"
|
||||
|
||||
/datum/spellbook_entry/summon/guns/IsAvailible()
|
||||
if(!SSticker.mode) // In case spellbook is placed on map
|
||||
return 0
|
||||
return !CONFIG_GET(flag/no_summon_guns)
|
||||
|
||||
/datum/spellbook_entry/summon/guns/Buy(mob/living/carbon/human/user,obj/item/spellbook/book)
|
||||
SSblackbox.record_feedback("tally", "wizard_spell_learned", 1, name)
|
||||
rightandwrong(SUMMON_GUNS, user, 25)
|
||||
active = 1
|
||||
playsound(get_turf(user), 'sound/magic/castsummon.ogg', 50, 1)
|
||||
to_chat(user, "<span class='notice'>You have cast summon guns!</span>")
|
||||
return 1
|
||||
|
||||
/datum/spellbook_entry/summon/magic
|
||||
name = "Summon Magic"
|
||||
desc = "Share the wonders of magic with the crew and show them why they aren't to be trusted with it at the same time."
|
||||
|
||||
/datum/spellbook_entry/summon/magic/IsAvailible()
|
||||
if(!SSticker.mode) // In case spellbook is placed on map
|
||||
return 0
|
||||
return !CONFIG_GET(flag/no_summon_magic)
|
||||
|
||||
/datum/spellbook_entry/summon/magic/Buy(mob/living/carbon/human/user,obj/item/spellbook/book)
|
||||
SSblackbox.record_feedback("tally", "wizard_spell_learned", 1, name)
|
||||
rightandwrong(SUMMON_MAGIC, user, 25)
|
||||
active = 1
|
||||
playsound(get_turf(user), 'sound/magic/castsummon.ogg', 50, 1)
|
||||
to_chat(user, "<span class='notice'>You have cast summon magic!</span>")
|
||||
return 1
|
||||
|
||||
/datum/spellbook_entry/summon/events
|
||||
name = "Summon Events"
|
||||
desc = "Give Murphy's law a little push and replace all events with special wizard ones that will confound and confuse everyone. Multiple castings increase the rate of these events."
|
||||
var/times = 0
|
||||
|
||||
/datum/spellbook_entry/summon/events/IsAvailible()
|
||||
if(!SSticker.mode) // In case spellbook is placed on map
|
||||
return 0
|
||||
return !CONFIG_GET(flag/no_summon_events)
|
||||
|
||||
/datum/spellbook_entry/summon/events/Buy(mob/living/carbon/human/user,obj/item/spellbook/book)
|
||||
SSblackbox.record_feedback("tally", "wizard_spell_learned", 1, name)
|
||||
summonevents()
|
||||
times++
|
||||
playsound(get_turf(user), 'sound/magic/castsummon.ogg', 50, 1)
|
||||
to_chat(user, "<span class='notice'>You have cast summon events.</span>")
|
||||
return 1
|
||||
|
||||
/datum/spellbook_entry/summon/events/GetInfo()
|
||||
. = ..()
|
||||
if(times>0)
|
||||
. += "You cast it [times] times.<br>"
|
||||
return .
|
||||
|
||||
/obj/item/spellbook
|
||||
name = "spell book"
|
||||
desc = "An unearthly tome that glows with power."
|
||||
icon = 'icons/obj/library.dmi'
|
||||
icon_state ="book"
|
||||
throw_speed = 2
|
||||
throw_range = 5
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
persistence_replacement = /obj/item/spellbook/oneuse/random
|
||||
var/uses = 10
|
||||
var/temp = null
|
||||
var/tab = null
|
||||
var/mob/living/carbon/human/owner
|
||||
var/list/datum/spellbook_entry/entries = list()
|
||||
var/list/categories = list()
|
||||
|
||||
/obj/item/spellbook/examine(mob/user)
|
||||
..()
|
||||
if(owner)
|
||||
to_chat(user, "There is a small signature on the front cover: \"[owner]\".")
|
||||
else
|
||||
to_chat(user, "It appears to have no author.")
|
||||
|
||||
/obj/item/spellbook/Initialize()
|
||||
. = ..()
|
||||
prepare_spells()
|
||||
|
||||
/obj/item/spellbook/proc/prepare_spells()
|
||||
var/entry_types = subtypesof(/datum/spellbook_entry) - /datum/spellbook_entry/item - /datum/spellbook_entry/summon
|
||||
for(var/T in entry_types)
|
||||
var/datum/spellbook_entry/E = new T
|
||||
if(E.IsAvailible())
|
||||
entries |= E
|
||||
categories |= E.category
|
||||
else
|
||||
qdel(E)
|
||||
tab = categories[1]
|
||||
|
||||
/obj/item/spellbook/attackby(obj/item/O, mob/user, params)
|
||||
if(istype(O, /obj/item/antag_spawner/contract))
|
||||
var/obj/item/antag_spawner/contract/contract = O
|
||||
if(contract.used)
|
||||
to_chat(user, "<span class='warning'>The contract has been used, you can't get your points back now!</span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You feed the contract back into the spellbook, refunding your points.</span>")
|
||||
uses++
|
||||
for(var/datum/spellbook_entry/item/contract/CT in entries)
|
||||
if(!isnull(CT.limit))
|
||||
CT.limit++
|
||||
qdel(O)
|
||||
else if(istype(O, /obj/item/antag_spawner/slaughter_demon))
|
||||
to_chat(user, "<span class='notice'>On second thought, maybe summoning a demon is a bad idea. You refund your points.</span>")
|
||||
uses++
|
||||
for(var/datum/spellbook_entry/item/bloodbottle/BB in entries)
|
||||
if(!isnull(BB.limit))
|
||||
BB.limit++
|
||||
qdel(O)
|
||||
|
||||
/obj/item/spellbook/proc/GetCategoryHeader(category)
|
||||
var/dat = ""
|
||||
switch(category)
|
||||
if("Offensive")
|
||||
dat += "Spells and items geared towards debilitating and destroying.<BR><BR>"
|
||||
dat += "Items are not bound to you and can be stolen. Additionaly they cannot typically be returned once purchased.<BR>"
|
||||
dat += "For spells: the number after the spell name is the cooldown time.<BR>"
|
||||
dat += "You can reduce this number by spending more points on the spell.<BR>"
|
||||
if("Defensive")
|
||||
dat += "Spells and items geared towards improving your survivabilty or reducing foes' ability to attack.<BR><BR>"
|
||||
dat += "Items are not bound to you and can be stolen. Additionaly they cannot typically be returned once purchased.<BR>"
|
||||
dat += "For spells: the number after the spell name is the cooldown time.<BR>"
|
||||
dat += "You can reduce this number by spending more points on the spell.<BR>"
|
||||
if("Mobility")
|
||||
dat += "Spells and items geared towards improving your ability to move. It is a good idea to take at least one.<BR><BR>"
|
||||
dat += "Items are not bound to you and can be stolen. Additionaly they cannot typically be returned once purchased.<BR>"
|
||||
dat += "For spells: the number after the spell name is the cooldown time.<BR>"
|
||||
dat += "You can reduce this number by spending more points on the spell.<BR>"
|
||||
if("Assistance")
|
||||
dat += "Spells and items geared towards bringing in outside forces to aid you or improving upon your other items and abilties.<BR><BR>"
|
||||
dat += "Items are not bound to you and can be stolen. Additionaly they cannot typically be returned once purchased.<BR>"
|
||||
dat += "For spells: the number after the spell name is the cooldown time.<BR>"
|
||||
dat += "You can reduce this number by spending more points on the spell.<BR>"
|
||||
if("Challenges")
|
||||
dat += "The Wizard Federation typically has hard limits on the potency and number of spells brought to the station based on risk.<BR>"
|
||||
dat += "Arming the station against you will increases the risk, but will grant you one more charge for your spellbook.<BR>"
|
||||
if("Rituals")
|
||||
dat += "These powerful spells change the very fabric of reality. Not always in your favour.<BR>"
|
||||
return dat
|
||||
|
||||
/obj/item/spellbook/proc/wrap(content)
|
||||
var/dat = ""
|
||||
dat +="<html><head><title>Spellbook</title></head>"
|
||||
dat += {"
|
||||
<head>
|
||||
<style type="text/css">
|
||||
body { font-size: 80%; font-family: 'Lucida Grande', Verdana, Arial, Sans-Serif; }
|
||||
ul#tabs { list-style-type: none; margin: 30px 0 0 0; padding: 0 0 0.3em 0; }
|
||||
ul#tabs li { display: inline; }
|
||||
ul#tabs li a { color: #42454a; background-color: #dedbde; border: 1px solid #c9c3ba; border-bottom: none; padding: 0.3em; text-decoration: none; }
|
||||
ul#tabs li a:hover { background-color: #f1f0ee; }
|
||||
ul#tabs li a.selected { color: #000; background-color: #f1f0ee; font-weight: bold; padding: 0.7em 0.3em 0.38em 0.3em; }
|
||||
div.tabContent { border: 1px solid #c9c3ba; padding: 0.5em; background-color: #f1f0ee; }
|
||||
div.tabContent.hide { display: none; }
|
||||
</style>
|
||||
</head>
|
||||
"}
|
||||
dat += {"[content]</body></html>"}
|
||||
return dat
|
||||
|
||||
/obj/item/spellbook/attack_self(mob/user)
|
||||
if(!owner)
|
||||
to_chat(user, "<span class='notice'>You bind the spellbook to yourself.</span>")
|
||||
owner = user
|
||||
return
|
||||
if(user != owner)
|
||||
to_chat(user, "<span class='warning'>The [name] does not recognize you as its owner and refuses to open!</span>")
|
||||
return
|
||||
user.set_machine(src)
|
||||
var/dat = ""
|
||||
|
||||
dat += "<ul id=\"tabs\">"
|
||||
var/list/cat_dat = list()
|
||||
for(var/category in categories)
|
||||
cat_dat[category] = "<hr>"
|
||||
dat += "<li><a [tab==category?"class=selected":""] href='byond://?src=[REF(src)];page=[category]'>[category]</a></li>"
|
||||
|
||||
dat += "<li><a><b>Points remaining : [uses]</b></a></li>"
|
||||
dat += "</ul>"
|
||||
|
||||
var/datum/spellbook_entry/E
|
||||
for(var/i=1,i<=entries.len,i++)
|
||||
var/spell_info = ""
|
||||
E = entries[i]
|
||||
spell_info += E.GetInfo()
|
||||
if(E.CanBuy(user,src))
|
||||
spell_info+= "<a href='byond://?src=[REF(src)];buy=[i]'>[E.buy_word]</A><br>"
|
||||
else
|
||||
spell_info+= "<span>Can't [E.buy_word]</span><br>"
|
||||
if(E.CanRefund(user,src))
|
||||
spell_info+= "<a href='byond://?src=[REF(src)];refund=[i]'>Refund</A><br>"
|
||||
spell_info += "<hr>"
|
||||
if(cat_dat[E.category])
|
||||
cat_dat[E.category] += spell_info
|
||||
|
||||
for(var/category in categories)
|
||||
dat += "<div class=\"[tab==category?"tabContent":"tabContent hide"]\" id=\"[category]\">"
|
||||
dat += GetCategoryHeader(category)
|
||||
dat += cat_dat[category]
|
||||
dat += "</div>"
|
||||
|
||||
user << browse(wrap(dat), "window=spellbook;size=700x500")
|
||||
onclose(user, "spellbook")
|
||||
return
|
||||
|
||||
/obj/item/spellbook/Topic(href, href_list)
|
||||
..()
|
||||
var/mob/living/carbon/human/H = usr
|
||||
|
||||
if(H.stat || H.restrained())
|
||||
return
|
||||
if(!ishuman(H))
|
||||
return 1
|
||||
|
||||
if(H.mind.special_role == "apprentice")
|
||||
temp = "If you got caught sneaking a peek from your teacher's spellbook, you'd likely be expelled from the Wizard Academy. Better not."
|
||||
return
|
||||
|
||||
var/datum/spellbook_entry/E = null
|
||||
if(loc == H || (in_range(src, H) && isturf(loc)))
|
||||
H.set_machine(src)
|
||||
if(href_list["buy"])
|
||||
E = entries[text2num(href_list["buy"])]
|
||||
if(E && E.CanBuy(H,src))
|
||||
if(E.Buy(H,src))
|
||||
if(E.limit)
|
||||
E.limit--
|
||||
uses -= E.cost
|
||||
else if(href_list["refund"])
|
||||
E = entries[text2num(href_list["refund"])]
|
||||
if(E && E.refundable)
|
||||
var/result = E.Refund(H,src)
|
||||
if(result > 0)
|
||||
if(!isnull(E.limit))
|
||||
E.limit += result
|
||||
uses += result
|
||||
else if(href_list["page"])
|
||||
tab = sanitize(href_list["page"])
|
||||
attack_self(H)
|
||||
return
|
||||
|
||||
//Single Use Spellbooks//
|
||||
|
||||
/obj/item/spellbook/oneuse
|
||||
var/spell = /obj/effect/proc_holder/spell/targeted/projectile/magic_missile //just a placeholder to avoid runtimes if someone spawned the generic
|
||||
var/spellname = "sandbox"
|
||||
var/used = 0
|
||||
name = "spellbook of "
|
||||
uses = 1
|
||||
desc = "This template spellbook was never meant for the eyes of man..."
|
||||
persistence_replacement = null
|
||||
|
||||
/obj/item/spellbook/oneuse/prepare_spells()
|
||||
name += spellname
|
||||
|
||||
/obj/item/spellbook/oneuse/attack_self(mob/user)
|
||||
var/obj/effect/proc_holder/spell/S = new spell
|
||||
for(var/obj/effect/proc_holder/spell/knownspell in user.mind.spell_list)
|
||||
if(knownspell.type == S.type)
|
||||
if(user.mind)
|
||||
if(iswizard(user))
|
||||
to_chat(user,"<span class='notice'>You're already far more versed in this spell than this flimsy how-to book can provide.</span>")
|
||||
else
|
||||
to_chat(user,"<span class='notice'>You've already read this one.</span>")
|
||||
return
|
||||
if(used)
|
||||
recoil(user)
|
||||
else
|
||||
user.mind.AddSpell(S)
|
||||
to_chat(user,"<span class='notice'>You rapidly read through the arcane book. Suddenly you realize you understand [spellname]!</span>")
|
||||
user.log_message("<font color='orange'>learned the spell [spellname] ([S]).</font>", INDIVIDUAL_ATTACK_LOG)
|
||||
onlearned(user)
|
||||
|
||||
/obj/item/spellbook/oneuse/proc/recoil(mob/user)
|
||||
user.visible_message("<span class='warning'>[src] glows in a black light!</span>")
|
||||
|
||||
/obj/item/spellbook/oneuse/proc/onlearned(mob/user)
|
||||
used = 1
|
||||
user.visible_message("<span class='caution'>[src] glows dark for a second!</span>")
|
||||
|
||||
/obj/item/spellbook/oneuse/attackby()
|
||||
return
|
||||
|
||||
/obj/item/spellbook/oneuse/fireball
|
||||
spell = /obj/effect/proc_holder/spell/aimed/fireball
|
||||
spellname = "fireball"
|
||||
icon_state ="bookfireball"
|
||||
desc = "This book feels warm to the touch."
|
||||
|
||||
/obj/item/spellbook/oneuse/fireball/recoil(mob/user)
|
||||
..()
|
||||
explosion(user.loc, -1, 0, 2, 3, 0, flame_range = 2)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/spellbook/oneuse/smoke
|
||||
spell = /obj/effect/proc_holder/spell/targeted/smoke
|
||||
spellname = "smoke"
|
||||
icon_state ="booksmoke"
|
||||
desc = "This book is overflowing with the dank arts."
|
||||
|
||||
/obj/item/spellbook/oneuse/smoke/lesser //Chaplain smoke book
|
||||
spell = /obj/effect/proc_holder/spell/targeted/smoke/lesser
|
||||
|
||||
/obj/item/spellbook/oneuse/smoke/recoil(mob/user)
|
||||
..()
|
||||
to_chat(user,"<span class='caution'>Your stomach rumbles...</span>")
|
||||
if(user.nutrition)
|
||||
user.nutrition -= 200
|
||||
if(user.nutrition <= 0)
|
||||
user.nutrition = 0
|
||||
|
||||
|
||||
/obj/item/spellbook/oneuse/blind
|
||||
spell = /obj/effect/proc_holder/spell/targeted/trigger/blind
|
||||
spellname = "blind"
|
||||
icon_state ="bookblind"
|
||||
desc = "This book looks blurry, no matter how you look at it."
|
||||
|
||||
/obj/item/spellbook/oneuse/blind/recoil(mob/user)
|
||||
..()
|
||||
to_chat(user,"<span class='warning'>You go blind!</span>")
|
||||
user.blind_eyes(10)
|
||||
|
||||
/obj/item/spellbook/oneuse/mindswap
|
||||
spell = /obj/effect/proc_holder/spell/targeted/mind_transfer
|
||||
spellname = "mindswap"
|
||||
icon_state ="bookmindswap"
|
||||
desc = "This book's cover is pristine, though its pages look ragged and torn."
|
||||
var/mob/stored_swap = null //Used in used book recoils to store an identity for mindswaps
|
||||
|
||||
/obj/item/spellbook/oneuse/mindswap/onlearned()
|
||||
spellname = pick("fireball","smoke","blind","forcewall","knock","barnyard","charge")
|
||||
icon_state = "book[spellname]"
|
||||
name = "spellbook of [spellname]" //Note, desc doesn't change by design
|
||||
..()
|
||||
|
||||
/obj/item/spellbook/oneuse/mindswap/recoil(mob/user)
|
||||
..()
|
||||
if(stored_swap in GLOB.dead_mob_list)
|
||||
stored_swap = null
|
||||
if(!stored_swap)
|
||||
stored_swap = user
|
||||
to_chat(user,"<span class='warning'>For a moment you feel like you don't even know who you are anymore.</span>")
|
||||
return
|
||||
if(stored_swap == user)
|
||||
to_chat(user,"<span class='notice'>You stare at the book some more, but there doesn't seem to be anything else to learn...</span>")
|
||||
return
|
||||
|
||||
var/obj/effect/proc_holder/spell/targeted/mind_transfer/swapper = new
|
||||
swapper.cast(user, stored_swap, 1)
|
||||
|
||||
to_chat(stored_swap,"<span class='warning'>You're suddenly somewhere else... and someone else?!</span>")
|
||||
to_chat(user,"<span class='warning'>Suddenly you're staring at [src] again... where are you, who are you?!</span>")
|
||||
stored_swap = null
|
||||
|
||||
/obj/item/spellbook/oneuse/forcewall
|
||||
spell = /obj/effect/proc_holder/spell/targeted/forcewall
|
||||
spellname = "forcewall"
|
||||
icon_state ="bookforcewall"
|
||||
desc = "This book has a dedication to mimes everywhere inside the front cover."
|
||||
|
||||
/obj/item/spellbook/oneuse/forcewall/recoil(mob/living/user)
|
||||
..()
|
||||
to_chat(user,"<span class='warning'>You suddenly feel very solid!</span>")
|
||||
user.Stun(40, ignore_canstun = TRUE)
|
||||
user.petrify(30)
|
||||
|
||||
/obj/item/spellbook/oneuse/knock
|
||||
spell = /obj/effect/proc_holder/spell/aoe_turf/knock
|
||||
spellname = "knock"
|
||||
icon_state ="bookknock"
|
||||
desc = "This book is hard to hold closed properly."
|
||||
|
||||
/obj/item/spellbook/oneuse/knock/recoil(mob/living/user)
|
||||
..()
|
||||
to_chat(user,"<span class='warning'>You're knocked down!</span>")
|
||||
user.Knockdown(40)
|
||||
|
||||
/obj/item/spellbook/oneuse/barnyard
|
||||
spell = /obj/effect/proc_holder/spell/targeted/barnyardcurse
|
||||
spellname = "barnyard"
|
||||
icon_state ="bookhorses"
|
||||
desc = "This book is more horse than your mind has room for."
|
||||
|
||||
/obj/item/spellbook/oneuse/barnyard/recoil(mob/living/carbon/user)
|
||||
if(ishuman(user))
|
||||
to_chat(user,"<font size='15' color='red'><b>HOR-SIE HAS RISEN</b></font>")
|
||||
var/obj/item/clothing/mask/horsehead/magichead = new /obj/item/clothing/mask/horsehead
|
||||
magichead.flags_1 |= NODROP_1 //curses!
|
||||
magichead.flags_inv &= ~HIDEFACE //so you can still see their face
|
||||
magichead.voicechange = 1 //NEEEEIIGHH
|
||||
if(!user.dropItemToGround(user.wear_mask))
|
||||
qdel(user.wear_mask)
|
||||
user.equip_to_slot_if_possible(magichead, slot_wear_mask, 1, 1)
|
||||
qdel(src)
|
||||
else
|
||||
to_chat(user,"<span class='notice'>I say thee neigh</span>") //It still lives here
|
||||
|
||||
/obj/item/spellbook/oneuse/charge
|
||||
spell = /obj/effect/proc_holder/spell/targeted/charge
|
||||
spellname = "charging"
|
||||
icon_state ="bookcharge"
|
||||
desc = "This book is made of 100% post-consumer wizard."
|
||||
|
||||
/obj/item/spellbook/oneuse/charge/recoil(mob/user)
|
||||
..()
|
||||
to_chat(user,"<span class='warning'>[src] suddenly feels very warm!</span>")
|
||||
empulse(src, 1, 1)
|
||||
|
||||
/obj/item/spellbook/oneuse/summonitem
|
||||
spell = /obj/effect/proc_holder/spell/targeted/summonitem
|
||||
spellname = "instant summons"
|
||||
icon_state ="booksummons"
|
||||
desc = "This book is bright and garish, very hard to miss."
|
||||
|
||||
/obj/item/spellbook/oneuse/summonitem/recoil(mob/user)
|
||||
..()
|
||||
to_chat(user,"<span class='warning'>[src] suddenly vanishes!</span>")
|
||||
qdel(src)
|
||||
|
||||
/obj/item/spellbook/oneuse/random
|
||||
icon_state = "random_book"
|
||||
|
||||
/obj/item/spellbook/oneuse/random/Initialize()
|
||||
..()
|
||||
var/static/banned_spells = list(/obj/item/spellbook/oneuse/mimery_blockade, /obj/item/spellbook/oneuse/mimery_guns)
|
||||
var/real_type = pick(subtypesof(/obj/item/spellbook/oneuse) - banned_spells)
|
||||
new real_type(loc)
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
/obj/item/spellbook/oneuse/sacredflame
|
||||
spell = /obj/effect/proc_holder/spell/targeted/sacred_flame
|
||||
spellname = "sacred flame"
|
||||
icon_state ="booksacredflame"
|
||||
desc = "Become one with the flames that burn within... and invite others to do so as well."
|
||||
Reference in New Issue
Block a user