Merge pull request #15675 from Fox-McCloud/his-grace-ascended

Implements Better His Grace
This commit is contained in:
variableundefined
2021-09-18 15:26:30 -05:00
committed by GitHub
26 changed files with 474 additions and 249 deletions

View File

@@ -124,6 +124,17 @@
#define WEAPON_MEDIUM 2 #define WEAPON_MEDIUM 2
#define WEAPON_HEAVY 3 #define WEAPON_HEAVY 3
//His Grace.
#define HIS_GRACE_SATIATED 0 //He hungers not. If bloodthirst is set to this, His Grace is asleep.
#define HIS_GRACE_PECKISH 20 //Slightly hungry.
#define HIS_GRACE_HUNGRY 60 //Getting closer. Increases damage up to a minimum of 20.
#define HIS_GRACE_FAMISHED 100 //Dangerous. Increases damage up to a minimum of 25 and cannot be dropped.
#define HIS_GRACE_STARVING 120 //Incredibly close to breaking loose. Increases damage up to a minimum of 30.
#define HIS_GRACE_CONSUME_OWNER 140 //His Grace consumes His owner at this point and becomes aggressive.
#define HIS_GRACE_FALL_ASLEEP 160 //If it reaches this point, He falls asleep and resets.
#define HIS_GRACE_FORCE_BONUS 4 //How much force is gained per kill.
#define EXPLODE_NONE 0 //Don't even ask me why we need this. #define EXPLODE_NONE 0 //Don't even ask me why we need this.
#define EXPLODE_DEVASTATE 1 #define EXPLODE_DEVASTATE 1
#define EXPLODE_HEAVY 2 #define EXPLODE_HEAVY 2

View File

@@ -13,6 +13,8 @@
// BUFFS // // BUFFS //
/////////// ///////////
#define STATUS_EFFECT_HISGRACE /datum/status_effect/his_grace //His Grace.
#define STATUS_EFFECT_SHADOW_MEND /datum/status_effect/shadow_mend //Quick, powerful heal that deals damage afterwards. Heals 15 brute/burn every second for 3 seconds. #define STATUS_EFFECT_SHADOW_MEND /datum/status_effect/shadow_mend //Quick, powerful heal that deals damage afterwards. Heals 15 brute/burn every second for 3 seconds.
#define STATUS_EFFECT_VOID_PRICE /datum/status_effect/void_price //The price of healing yourself with void energy. Deals 3 brute damage every 3 seconds for 30 seconds. #define STATUS_EFFECT_VOID_PRICE /datum/status_effect/void_price //The price of healing yourself with void energy. Deals 3 brute damage every 3 seconds for 30 seconds.
#define STATUS_EFFECT_EXERCISED /datum/status_effect/exercised //Prevents heart disease #define STATUS_EFFECT_EXERCISED /datum/status_effect/exercised //Prevents heart disease
@@ -27,7 +29,6 @@
//#define STATUS_EFFECT_POWERREGEN /datum/status_effect/cyborg_power_regen //Regenerates power on a given cyborg over time //#define STATUS_EFFECT_POWERREGEN /datum/status_effect/cyborg_power_regen //Regenerates power on a given cyborg over time
//#define STATUS_EFFECT_HISGRACE /datum/status_effect/his_grace //His Grace.
//#define STATUS_EFFECT_WISH_GRANTERS_GIFT /datum/status_effect/wish_granters_gift //If you're currently resurrecting with the Wish Granter //#define STATUS_EFFECT_WISH_GRANTERS_GIFT /datum/status_effect/wish_granters_gift //If you're currently resurrecting with the Wish Granter
@@ -53,7 +54,7 @@
//#define MAX_MANIA_SEVERITY 100 //how high the mania severity can go //#define MAX_MANIA_SEVERITY 100 //how high the mania severity can go
//#define MANIA_DAMAGE_TO_CONVERT 90 //how much damage is required before it'll convert affected targets //#define MANIA_DAMAGE_TO_CONVERT 90 //how much damage is required before it'll convert affected targets
//#define STATUS_EFFECT_HISWRATH /datum/status_effect/his_wrath //His Wrath. #define STATUS_EFFECT_HISWRATH /datum/status_effect/his_wrath //His Wrath.
#define STATUS_EFFECT_SUMMONEDGHOST /datum/status_effect/cultghost //is a cult ghost: can see dead people, can't manifest more ghosts #define STATUS_EFFECT_SUMMONEDGHOST /datum/status_effect/cultghost //is a cult ghost: can see dead people, can't manifest more ghosts

View File

@@ -188,3 +188,21 @@
animate(A, transform = matrix(punchstr, MATRIX_ROTATE), pixel_y = 16, time = 2, color = "#eeeeee", easing = BOUNCE_EASING) animate(A, transform = matrix(punchstr, MATRIX_ROTATE), pixel_y = 16, time = 2, color = "#eeeeee", easing = BOUNCE_EASING)
animate(transform = matrix(-punchstr, MATRIX_ROTATE), pixel_y = original_y, time = 2, color = "#ffffff", easing = BOUNCE_EASING) animate(transform = matrix(-punchstr, MATRIX_ROTATE), pixel_y = original_y, time = 2, color = "#ffffff", easing = BOUNCE_EASING)
animate(transform = null, time = 3, easing = BOUNCE_EASING) animate(transform = null, time = 3, easing = BOUNCE_EASING)
/proc/animate_rumble(atom/A)
var/static/list/transforms
if(!transforms)
var/matrix/M1 = matrix()
var/matrix/M2 = matrix()
var/matrix/M3 = matrix()
var/matrix/M4 = matrix()
M1.Translate(-1, 0)
M2.Translate(0, 1)
M3.Translate(1, 0)
M4.Translate(0, -1)
transforms = list(M1, M2, M3, M4)
animate(A, transform = transforms[1], time = 0.2, loop = -1)
animate(transform = transforms[2], time = 0.1)
animate(transform = transforms[3], time = 0.2)
animate(transform = transforms[4], time = 0.3)

View File

@@ -3,7 +3,7 @@
Turn(.) //BYOND handles cases such as -270, 360, 540 etc. DOES NOT HANDLE 180 TURNS WELL, THEY TWEEN AND LOOK LIKE SHIT Turn(.) //BYOND handles cases such as -270, 360, 540 etc. DOES NOT HANDLE 180 TURNS WELL, THEY TWEEN AND LOOK LIKE SHIT
/atom/proc/SpinAnimation(speed = 10, loops = -1, clockwise = 1, segments = 3) /atom/proc/SpinAnimation(speed = 10, loops = -1, clockwise = 1, segments = 3, parallel = TRUE)
if(!segments) if(!segments)
return return
var/segment = 360/segments var/segment = 360/segments
@@ -19,7 +19,10 @@
speed /= segments speed /= segments
animate(src, transform = matrices[1], time = speed, loops) if(parallel)
animate(src, transform = matrices[1], time = speed, loops , flags = ANIMATION_PARALLEL)
else
animate(src, transform = matrices[1], time = speed, loops)
for(var/i in 2 to segments) //2 because 1 is covered above for(var/i in 2 to segments) //2 because 1 is covered above
animate(transform = matrices[i], time = speed) animate(transform = matrices[i], time = speed)
//doesn't have an object argument because this is "Stacking" with the animate call above //doesn't have an object argument because this is "Stacking" with the animate call above

View File

@@ -464,12 +464,15 @@ Turf and target are seperate in case you want to teleport some distance from a t
if(GLOB.stealthminID[P] == txt) if(GLOB.stealthminID[P] == txt)
return P return P
// Returns the atom sitting on the turf. //Returns the atom sitting on the turf.
// For example, using this on a disk, which is in a bag, on a mob, will return the mob because it's on the turf. //For example, using this on a disk, which is in a bag, on a mob, will return the mob because it's on the turf.
/proc/get_atom_on_turf(atom/movable/M) //Optional arg 'type' to stop once it reaches a specific type instead of a turf.
/proc/get_atom_on_turf(atom/movable/M, stop_type)
var/atom/loc = M var/atom/loc = M
while(loc && loc.loc && !istype(loc.loc, /turf/)) while(loc?.loc && !isturf(loc.loc))
loc = loc.loc loc = loc.loc
if(stop_type && istype(loc, stop_type))
break
return loc return loc
/* /*
@@ -1536,7 +1539,7 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
shift.Translate(0,radius) shift.Translate(0,radius)
transform = shift transform = shift
SpinAnimation(rotation_speed, -1, clockwise, rotation_segments) SpinAnimation(rotation_speed, -1, clockwise, rotation_segments, parallel = FALSE)
while(orbiting && orbiting == A && A.loc) while(orbiting && orbiting == A && A.loc)
var/targetloc = get_turf(A) var/targetloc = get_turf(A)

View File

@@ -1,5 +1,58 @@
//Largely beneficial effects go here, even if they have drawbacks. An example is provided in Shadow Mend. //Largely beneficial effects go here, even if they have drawbacks. An example is provided in Shadow Mend.
/datum/status_effect/his_grace
id = "his_grace"
duration = -1
tick_interval = 4
alert_type = /obj/screen/alert/status_effect/his_grace
var/bloodlust = 0
/obj/screen/alert/status_effect/his_grace
name = "His Grace"
desc = "His Grace hungers, and you must feed Him."
icon_state = "his_grace"
alerttooltipstyle = "hisgrace"
/obj/screen/alert/status_effect/his_grace/MouseEntered(location, control, params)
desc = initial(desc)
var/datum/status_effect/his_grace/HG = attached_effect
desc += "<br><font size=3><b>Current Bloodthirst: [HG.bloodlust]</b></font>\
<br>Becomes undroppable at <b>[HIS_GRACE_FAMISHED]</b>\
<br>Will consume you at <b>[HIS_GRACE_CONSUME_OWNER]</b>"
..()
/datum/status_effect/his_grace/on_apply()
add_attack_logs(owner, owner, "gained His Grace's stun immunity", ATKLOG_ALL)
owner.add_stun_absorption("hisgrace", INFINITY, 3, null, "His Grace protects you from the stun!")
return ..()
/datum/status_effect/his_grace/tick()
bloodlust = 0
var/graces = 0
var/list/held_items = list()
held_items += owner.l_hand
held_items += owner.r_hand
for(var/obj/item/his_grace/HG in held_items)
if(HG.bloodthirst > bloodlust)
bloodlust = HG.bloodthirst
if(HG.awakened)
graces++
if(!graces)
owner.apply_status_effect(STATUS_EFFECT_HISWRATH)
qdel(src)
return
var/grace_heal = bloodlust * 0.05
owner.adjustBruteLoss(-grace_heal)
owner.adjustFireLoss(-grace_heal)
owner.adjustToxLoss(-grace_heal)
owner.adjustOxyLoss(-(grace_heal * 2))
owner.adjustCloneLoss(-grace_heal)
/datum/status_effect/his_grace/on_remove()
add_attack_logs(owner, owner, "lost His Grace's stun immunity", ATKLOG_ALL)
if(islist(owner.stun_absorption) && owner.stun_absorption["hisgrace"])
owner.stun_absorption -= "hisgrace"
/datum/status_effect/shadow_mend /datum/status_effect/shadow_mend
id = "shadow_mend" id = "shadow_mend"
duration = 30 duration = 30

View File

@@ -1,5 +1,28 @@
//OTHER DEBUFFS //OTHER DEBUFFS
/datum/status_effect/his_wrath //does minor damage over time unless holding His Grace
id = "his_wrath"
duration = -1
tick_interval = 4
alert_type = /obj/screen/alert/status_effect/his_wrath
/obj/screen/alert/status_effect/his_wrath
name = "His Wrath"
desc = "You fled from His Grace instead of feeding Him, and now you suffer."
icon_state = "his_grace"
alerttooltipstyle = "hisgrace"
/datum/status_effect/his_wrath/tick()
var/list/held_items = list()
held_items += owner.l_hand
held_items += owner.r_hand
for(var/obj/item/his_grace/HG in held_items)
qdel(src)
return
owner.adjustBruteLoss(0.1)
owner.adjustFireLoss(0.1)
owner.adjustToxLoss(0.2)
/datum/status_effect/cultghost //is a cult ghost and can't use manifest runes /datum/status_effect/cultghost //is a cult ghost and can't use manifest runes
id = "cult_ghost" id = "cult_ghost"
duration = -1 duration = -1

View File

@@ -257,10 +257,13 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
job = list("Chaplain") job = list("Chaplain")
/datum/uplink_item/jobspecific/artistic_toolbox /datum/uplink_item/jobspecific/artistic_toolbox
name = "Artistic Toolbox" name = "His Grace"
desc = "An accursed toolbox that grants its followers extreme power at the cost of requiring repeated sacrifices to it. If sacrifices are not provided, it will turn on its follower." desc = "An incredibly dangerous weapon recovered from a station overcome by the grey tide. Once activated, He will thirst for blood and must be used to kill to sate that thirst. \
reference = "HGAT" His Grace grants gradual regeneration and complete stun immunity to His wielder, but be wary: if He gets too hungry, He will become impossible to drop and eventually kill you if not fed. \
item = /obj/item/storage/toolbox/green/memetic However, if left alone for long enough, He will fall back to slumber. \
To activate His Grace, simply unlatch Him."
reference = "HG"
item = /obj/item/his_grace
cost = 20 cost = 20
job = list("Chaplain") job = list("Chaplain")
surplus = 0 //No lucky chances from the crate; if you get this, this is ALL you're getting surplus = 0 //No lucky chances from the crate; if you get this, this is ALL you're getting

View File

@@ -420,6 +420,7 @@
if(spin && !no_spin && !no_spin_thrown) if(spin && !no_spin && !no_spin_thrown)
SpinAnimation(5, 1) SpinAnimation(5, 1)
SEND_SIGNAL(src, COMSIG_MOVABLE_POST_THROW, TT, spin)
SSthrowing.processing[src] = TT SSthrowing.processing[src] = TT
TT.tick() TT.tick()

View File

@@ -0,0 +1,263 @@
//His Grace is a very special weapon granted only to traitor chaplains.
//When awakened, He thirsts for blood and begins ticking a "bloodthirst" counter.
//The wielder of His Grace is immune to stuns and gradually heals.
//If the wielder fails to feed His Grace in time, He will devour them and become incredibly aggressive.
//Leaving His Grace alone for some time will reset His thirst and put Him to sleep.
//Using His Grace effectively requires extreme speed and care.
/obj/item/his_grace
name = "artistic toolbox"
desc = "A toolbox painted bright green. Looking at it makes you feel uneasy."
icon = 'icons/obj/storage.dmi'
icon_state = "green"
item_state = "artistic_toolbox"
lefthand_file = 'icons/mob/inhands/equipment/toolbox_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/toolbox_righthand.dmi'
w_class = WEIGHT_CLASS_GIGANTIC
force = 12
attack_verb = list("robusted")
hitsound = 'sound/weapons/smash.ogg'
drop_sound = 'sound/items/handling/toolbox_drop.ogg'
pickup_sound = 'sound/items/handling/toolbox_pickup.ogg'
var/awakened = FALSE
var/bloodthirst = HIS_GRACE_SATIATED
var/prev_bloodthirst = HIS_GRACE_SATIATED
var/force_bonus = 0
var/ascended = FALSE
var/victims_needed = 25
var/ascend_bonus = 15
/obj/item/his_grace/Initialize(mapload)
. = ..()
START_PROCESSING(SSprocessing, src)
GLOB.poi_list |= src
RegisterSignal(src, COMSIG_MOVABLE_POST_THROW, .proc/move_gracefully)
update_icon()
/obj/item/his_grace/Destroy()
STOP_PROCESSING(SSprocessing, src)
for(var/mob/living/L in src)
L.forceMove(get_turf(src))
GLOB.poi_list -= src
return ..()
/obj/item/his_grace/update_icon()
icon_state = ascended ? "gold" : "green"
item_state = ascended ? "toolbox_gold" : "artistic_toolbox"
cut_overlays()
if(ascended)
add_overlay("triple_latch")
else if(awakened)
add_overlay("single_latch_open")
else
add_overlay("single_latch")
/obj/item/his_grace/attack_self(mob/living/user)
if(!awakened)
INVOKE_ASYNC(src, .proc/awaken, user)
/obj/item/his_grace/attack(mob/living/M, mob/user)
if(awakened && M.stat)
consume(M)
else
..()
/obj/item/his_grace/can_be_pulled(user, grab_state, force, show_message = FALSE) //you can't pull his grace
return FALSE
/obj/item/his_grace/examine(mob/user)
. = ..()
if(awakened)
switch(bloodthirst)
if(HIS_GRACE_SATIATED to HIS_GRACE_PECKISH)
. += "<span class='his_grace'>[src] isn't very hungry. Not yet.</span>"
if(HIS_GRACE_PECKISH to HIS_GRACE_HUNGRY)
. += "<span class='his_grace'>[src] would like a snack.</span>"
if(HIS_GRACE_HUNGRY to HIS_GRACE_FAMISHED)
. += "<span class='his_grace'>[src] is quite hungry now.</span>"
if(HIS_GRACE_FAMISHED to HIS_GRACE_STARVING)
. += "<span class='his_grace'>[src] is openly salivating at the sight of you. Be careful.</span>"
if(HIS_GRACE_STARVING to HIS_GRACE_CONSUME_OWNER)
. += "<span class='his_grace bold'>You walk a fine line. [src] is very close to devouring you.</span>"
if(HIS_GRACE_CONSUME_OWNER to HIS_GRACE_FALL_ASLEEP)
. += "<span class='his_grace bold'>[src] is shaking violently and staring directly at you.</span>"
else
. += "<span class='his_grace'>[src] is latched closed.</span>"
/obj/item/his_grace/relaymove(mob/living/user, direction) //Allows changelings, etc. to climb out of Him after they revive, provided He isn't active
if(!awakened)
user.forceMove(get_turf(src))
user.visible_message("<span class='warning'>[user] scrambles out of [src]!</span>", "<span class='notice'>You climb out of [src]!</span>")
/obj/item/his_grace/process()
if(!bloodthirst)
drowse()
return
if(bloodthirst < HIS_GRACE_CONSUME_OWNER && !ascended)
adjust_bloodthirst(1 + FLOOR(length(contents) * 0.5, 1)) //Maybe adjust this?
else
adjust_bloodthirst(1) //don't cool off rapidly once we're at the point where His Grace consumes all.
var/mob/living/master = get_atom_on_turf(src, /mob/living)
var/list/held_items = list()
if(istype(master))
held_items += master.l_hand
held_items += master.r_hand
if(istype(master) && (src in held_items))
switch(bloodthirst)
if(HIS_GRACE_CONSUME_OWNER to HIS_GRACE_FALL_ASLEEP)
master.visible_message("<span class='boldwarning'>[src] turns on [master]!</span>", "<span class='his_grace big bold'>[src] turns on you!</span>")
do_attack_animation(master, null, src)
master.emote("scream")
master.remove_status_effect(STATUS_EFFECT_HISGRACE)
flags &= ~NODROP
master.Weaken(3)
master.adjustBruteLoss(1000)
playsound(master, 'sound/effects/splat.ogg', 100, FALSE)
else
master.apply_status_effect(STATUS_EFFECT_HISGRACE)
return
forceMove(get_turf(src)) //no you can't put His Grace in a locker you just have to deal with Him
if(bloodthirst < HIS_GRACE_CONSUME_OWNER)
return
if(bloodthirst >= HIS_GRACE_FALL_ASLEEP)
drowse()
return
var/list/targets = list()
for(var/mob/living/L in oview(2, src))
targets += L
if(!length(targets))
return
var/mob/living/L = pick(targets)
step_to(src, L)
if(Adjacent(L))
if(!L.stat)
L.visible_message("<span class='warning'>[src] lunges at [L]!</span>", "<span class='his_grace big bold'>[src] lunges at you!</span>")
do_attack_animation(L, null, src)
playsound(L, 'sound/weapons/smash.ogg', 50, TRUE)
playsound(L, 'sound/misc/desceration-01.ogg', 50, TRUE)
L.adjustBruteLoss(force)
adjust_bloodthirst(-5) //Don't stop attacking they're right there!
else
consume(L)
/obj/item/his_grace/proc/awaken(mob/user) //Good morning, Mr. Grace.
if(awakened)
return
awakened = TRUE
user.visible_message("<span class='boldwarning'>[src] begins to rattle. He thirsts.</span>", "<span class='his_grace'>You flick [src]'s latch up. You hope this is a good idea.</span>")
name = "His Grace"
desc = "A bloodthirsty artifact created by a profane rite."
gender = MALE
adjust_bloodthirst(1)
force_bonus = HIS_GRACE_FORCE_BONUS * length(contents)
playsound(user, 'sound/effects/pope_entry.ogg', 100)
update_icon()
move_gracefully()
/obj/item/his_grace/proc/move_gracefully()
SIGNAL_HANDLER
if(!awakened)
return
animate_rumble(src)
/obj/item/his_grace/proc/drowse() //Good night, Mr. Grace.
if(!awakened || ascended)
return
var/turf/T = get_turf(src)
T.visible_message("<span class='boldwarning'>[src] slowly stops rattling and falls still, His latch snapping shut.</span>")
playsound(loc, 'sound/weapons/batonextend.ogg', 100, TRUE)
name = initial(name)
desc = initial(desc)
animate(src, transform = matrix())
gender = initial(gender)
force = initial(force)
force_bonus = initial(force_bonus)
awakened = FALSE
bloodthirst = 0
update_icon()
/obj/item/his_grace/proc/consume(mob/living/meal) //Here's your dinner, Mr. Grace.
if(!meal)
return
var/victims = 0
meal.visible_message("<span class='warning'>[src] swings open and devours [meal]!</span>", "<span class='his_grace big bold'>[src] consumes you!</span>")
meal.adjustBruteLoss(300)
playsound(meal, 'sound/misc/desceration-02.ogg', 75, TRUE)
playsound(src, 'sound/items/eatfood.ogg', 100, TRUE)
meal.forceMove(src)
force_bonus += HIS_GRACE_FORCE_BONUS
prev_bloodthirst = bloodthirst
if(prev_bloodthirst < HIS_GRACE_CONSUME_OWNER)
bloodthirst = max(length(contents), 1) //Never fully sated, and His hunger will only grow.
else
bloodthirst = HIS_GRACE_CONSUME_OWNER
for(var/mob/living/C in contents)
if(C.mind)
victims++
if(victims >= victims_needed)
ascend()
update_stats()
/obj/item/his_grace/proc/adjust_bloodthirst(amt)
prev_bloodthirst = bloodthirst
if(prev_bloodthirst < HIS_GRACE_CONSUME_OWNER && !ascended)
bloodthirst = clamp(bloodthirst + amt, HIS_GRACE_SATIATED, HIS_GRACE_CONSUME_OWNER)
else if(!ascended)
bloodthirst = clamp(bloodthirst + amt, HIS_GRACE_CONSUME_OWNER, HIS_GRACE_FALL_ASLEEP)
update_stats()
/obj/item/his_grace/proc/update_stats()
flags &= ~NODROP
var/mob/living/master = get_atom_on_turf(src, /mob/living)
switch(bloodthirst)
if(HIS_GRACE_CONSUME_OWNER to HIS_GRACE_FALL_ASLEEP)
if(HIS_GRACE_CONSUME_OWNER > prev_bloodthirst)
master.visible_message("<span class='userdanger'>[src] enters a frenzy!</span>")
if(HIS_GRACE_STARVING to HIS_GRACE_CONSUME_OWNER)
flags |= NODROP
if(HIS_GRACE_STARVING > prev_bloodthirst)
master.visible_message("<span class='boldwarning'>[src] is starving!</span>", "<span class='his_grace big'>[src]'s bloodlust overcomes you. [src] must be fed, or you will become His meal.\
[force_bonus < 15 ? " And still, His power grows.":""]</span>")
force_bonus = max(force_bonus, 15)
if(HIS_GRACE_FAMISHED to HIS_GRACE_STARVING)
flags |= NODROP
if(HIS_GRACE_FAMISHED > prev_bloodthirst)
master.visible_message("<span class='warning'>[src] is very hungry!</span>", "<span class='his_grace big'>Spines sink into your hand. [src] must feed immediately.\
[force_bonus < 10 ? " His power grows.":""]</span>")
force_bonus = max(force_bonus, 10)
if(prev_bloodthirst >= HIS_GRACE_STARVING)
master.visible_message("<span class='warning'>[src] is now only very hungry!</span>", "<span class='his_grace big'>Your bloodlust recedes.</span>")
if(HIS_GRACE_HUNGRY to HIS_GRACE_FAMISHED)
if(HIS_GRACE_HUNGRY > prev_bloodthirst)
master.visible_message("<span class='warning'>[src] is getting hungry.</span>", "<span class='his_grace big'>You feel [src]'s hunger within you.\
[force_bonus < 5 ? " His power grows.":""]</span>")
force_bonus = max(force_bonus, 5)
if(prev_bloodthirst >= HIS_GRACE_FAMISHED)
master.visible_message("<span class='warning'>[src] is now only somewhat hungry.</span>", "<span class='his_grace'>[src]'s hunger recedes a little...</span>")
if(HIS_GRACE_PECKISH to HIS_GRACE_HUNGRY)
if(HIS_GRACE_PECKISH > prev_bloodthirst)
master.visible_message("<span class='warning'>[src] is feeling snackish.</span>", "<span class='his_grace'>[src] begins to hunger.</span>")
if(prev_bloodthirst >= HIS_GRACE_HUNGRY)
master.visible_message("<span class='warning'>[src] is now only a little peckish.</span>", "<span class='his_grace big'>[src]'s hunger recedes somewhat...</span>")
if(HIS_GRACE_SATIATED to HIS_GRACE_PECKISH)
if(prev_bloodthirst >= HIS_GRACE_PECKISH)
master.visible_message("<span class='warning'>[src] is satiated.</span>", "<span class='his_grace big'>[src]'s hunger recedes...</span>")
force = initial(force) + force_bonus
/obj/item/his_grace/proc/ascend()
if(ascended)
return
force_bonus += ascend_bonus
desc = "A legendary toolbox and a distant artifact from The Age of Three Powers. On its three latches engraved are the words \"The Sun\", \"The Moon\", and \"The Stars\". The entire toolbox has the words \"The World\" engraved into its sides."
icon_state = "his_grace_ascended"
item_state = "toolbox_gold"
ascended = TRUE
update_icon()
playsound(src, 'sound/effects/his_grace_ascend.ogg', 100)
var/mob/living/carbon/human/master = loc
if(istype(master))
master.visible_message("<span class='his_grace big bold'>Gods will be watching.</span>")
name = "[master]'s mythical toolbox of three powers"
master.update_inv_l_hand()
master.update_inv_r_hand()

View File

@@ -1066,6 +1066,50 @@
w_class = WEIGHT_CLASS_SMALL w_class = WEIGHT_CLASS_SMALL
resistance_flags = FLAMMABLE resistance_flags = FLAMMABLE
/obj/item/toy/windup_toolbox
name = "windup toolbox"
desc = "A replica toolbox that rumbles when you turn the key."
icon = 'icons/obj/storage.dmi'
icon_state = "green"
item_state = "artistic_toolbox"
lefthand_file = 'icons/mob/inhands/equipment/toolbox_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/toolbox_righthand.dmi'
hitsound = 'sound/weapons/smash.ogg'
drop_sound = 'sound/items/handling/toolbox_drop.ogg'
pickup_sound = 'sound/items/handling/toolbox_pickup.ogg'
attack_verb = list("robusted")
var/active = FALSE
/obj/item/toy/windup_toolbox/Initialize(mapload)
. = ..()
update_icon()
/obj/item/toy/windup_toolbox/update_icon()
..()
cut_overlays()
if(active)
add_overlay("single_latch_open")
else
add_overlay("single_latch")
/obj/item/toy/windup_toolbox/attack_self(mob/user)
if(!active)
to_chat(user, "<span class='notice'>You wind up [src], it begins to rumble.</span>")
active = TRUE
update_icon()
playsound(src, 'sound/effects/pope_entry.ogg', 100)
animate_rumble(src)
addtimer(CALLBACK(src, .proc/stopRumble), 60 SECONDS)
else
to_chat(user, "<span class='warning'>[src] is already active!</span>")
/obj/item/toy/windup_toolbox/proc/stopRumble()
active = FALSE
update_icon()
visible_message("<span class='warning'>[src] slowly stops rattling and falls still, its latch snapping shut.</span>") //subtle difference
playsound(loc, 'sound/weapons/batonextend.ogg', 100, TRUE)
animate(src, transform = matrix())
/* /*
* Toy/fake flash * Toy/fake flash
*/ */

View File

@@ -1,223 +0,0 @@
/obj/item/storage/toolbox/green
name = "artistic toolbox"
desc = "A metal container designed to hold various tools. This variety holds art supplies."
icon_state = "green"
item_state = "artistic_toolbox"
/obj/item/storage/toolbox/green/memetic
name = "artistic toolbox"
desc = "His Grace."
force = 5
throwforce = 10
origin_tech = "combat=4;engineering=4;syndicate=2"
actions_types = list(/datum/action/item_action/toggle)
var/list/servantlinks = list()
var/hunger = 0
var/hunger_message_level = 0
var/mob/living/carbon/human/original_owner = null
var/activated = FALSE
/obj/item/storage/toolbox/green/memetic/ui_action_click(mob/user)
if(user.HasDisease(new /datum/disease/memetic_madness(0)))
var/obj/item/storage/toolbox/green/memetic/M = user.get_active_hand()
if(istype(M))
to_chat(user, "<span class='warning'>His Grace [flags & NODROP ? "releases from" : "binds to"] your hand!</span>")
flags ^= NODROP
else if(!activated && loc == user)
if(link_user(user))
to_chat(user, "<span class='notice'>Call to His Grace again if you wish it bound to your hand!</span>")
else
to_chat(user, "<span class='warning'>You can't seem to understand what this does.</span>")
/obj/item/storage/toolbox/green/memetic/attack_hand(mob/living/carbon/user)
if(!activated && loc == user)
link_user(user)
return
..()
/obj/item/storage/toolbox/green/memetic/proc/link_user(mob/living/carbon/user)
if(ishuman(user) && !user.HasDisease(new /datum/disease/memetic_madness(0)))
activated = TRUE
user.ForceContractDisease(new /datum/disease/memetic_madness(0))
for(var/datum/disease/memetic_madness/DD in user.viruses)
DD.progenitor = src
servantlinks.Add(DD)
break
force += 4
throwforce += 4
SEND_SOUND(user, sound('sound/goonstation/effects/screech.ogg'))
shake_camera(user, 20, 1)
var/acount = 0
var/amax = rand(10, 15)
var/up_and_down
var/asize = 1
while(acount <= amax)
up_and_down += "<font size=[asize]>a</font>"
if(acount > (amax * 0.5))
asize--
else
asize++
acount++
to_chat(user, "<span class='warning'>[up_and_down]</span>")
to_chat(user, "<i><b><font face = Tempus Sans ITC>His Grace accepts thee, spread His will! All who look close to the Enlightened may share His gifts.</font></b></i>")
original_owner = user
return TRUE
return FALSE
/obj/item/storage/toolbox/green/memetic/attackby(obj/item/I, mob/user)
if(activated)
if(istype(I, /obj/item/grab))
var/obj/item/grab/G = I
var/mob/living/victim = G.affecting
if(!user.HasDisease(new /datum/disease/memetic_madness(0)))
to_chat(user, "<span class='warning'>You can't seem to find the latch to open this.</span>")
return
if(!victim)
return
if(!victim.stat && !victim.restrained() && !victim.IsWeakened())
to_chat(user, "<span class='warning'>They're moving too much to feed to His Grace!</span>")
return
user.visible_message("<span class='userdanger'>[user] is trying to feed [victim] to [src]!</span>")
if(!do_mob(user, victim, 30))
return
user.visible_message("<span class='userdanger'>[user] has fed [victim] to [src]!</span>")
consume(victim)
qdel(G)
to_chat(user, "<i><b><font face = Tempus Sans ITC>You have done well...</font></b></i>")
force += 5
throwforce += 5
return
return ..()
/obj/item/storage/toolbox/green/memetic/proc/consume(mob/living/L)
if(!L)
return
hunger = 0
hunger_message_level = 0
playsound(loc, 'sound/goonstation/misc/burp_alien.ogg', 50, 0)
if(L != original_owner)
var/list/equipped_items = L.get_equipped_items(TRUE)
if(L.l_hand)
equipped_items += L.l_hand
if(L.r_hand)
equipped_items += L.r_hand
if(equipped_items.len)
var/obj/item/storage/box/B = new(src)
B.name = "Box-'[L.real_name]'"
for(var/obj/item/SI in equipped_items)
L.unEquip(SI, TRUE)
SI.forceMove(B)
equipped_items.Cut()
L.forceMove(src)
L.emote("scream")
L.death()
L.ghostize()
if(L == original_owner)
L.unEquip(src, TRUE)
qdel(L)
var/obj/item/storage/toolbox/green/fake_toolbox = new(get_turf(src))
fake_toolbox.desc = "It looks a lot duller than it used to."
qdel(src)
else
qdel(L)
/obj/item/storage/toolbox/green/memetic/Destroy()
for(var/datum/disease/memetic_madness/D in servantlinks)
D.cure()
servantlinks.Cut()
servantlinks = null
original_owner = null
visible_message("<span class='userdanger'>[src] screams!</span>")
playsound(loc, 'sound/goonstation/effects/screech.ogg', 100, 1)
return ..()
/datum/disease/memetic_madness
name = "Memetic Kill Agent"
max_stages = 4
stage_prob = 8
spread_text = "Non-Contagious"
spread_flags = SPECIAL
cure_text = "Unknown"
viable_mobtypes = list(/mob/living/carbon/human)
severity = BIOHAZARD
disease_flags = CAN_CARRY
spread_flags = NON_CONTAGIOUS
virus_heal_resistant = TRUE
var/obj/item/storage/toolbox/green/memetic/progenitor = null
/datum/disease/memetic_madness/Destroy()
if(progenitor)
progenitor.servantlinks.Remove(src)
progenitor = null
if(affected_mob)
affected_mob.status_flags |= CANSTUN | CANWEAKEN | CANPARALYSE
return ..()
/datum/disease/memetic_madness/stage_act()
..()
if(!progenitor) //if someone admin spawns this, cure it right away; this should only ever be given directly from the toolbox itself.
cure()
return
if(progenitor in affected_mob.contents)
affected_mob.adjustOxyLoss(-5)
affected_mob.adjustBruteLoss(-12)
affected_mob.adjustFireLoss(-12)
affected_mob.adjustToxLoss(-5)
affected_mob.setStaminaLoss(0)
var/status = CANSTUN | CANWEAKEN | CANPARALYSE
affected_mob.status_flags &= ~status
affected_mob.AdjustDizzy(-10)
affected_mob.AdjustDrowsy(-10)
affected_mob.SetSleeping(0)
affected_mob.SetSlowed(0)
affected_mob.SetConfused(0)
stage = 1
switch(progenitor.hunger)
if(10 to 60)
if(progenitor.hunger_message_level < 1)
progenitor.hunger_message_level = 1
to_chat(affected_mob, "<i><b><font face = Tempus Sans ITC>Feed Me the unclean ones...They will be purified...</font></b></i>")
if(61 to 120)
if(progenitor.hunger_message_level < 2)
progenitor.hunger_message_level = 2
to_chat(affected_mob, "<i><b><font face = Tempus Sans ITC>I hunger for the flesh of the impure...</font></b></i>")
if(121 to 210)
if(prob(10) && progenitor.hunger_message_level < 3)
progenitor.hunger_message_level = 3
to_chat(affected_mob, "<i><b><font face = Tempus Sans ITC>The hunger of your Master grows with every passing moment. Feed Me at once.</font></b></i>")
if(211 to 399)
if(progenitor.hunger_message_level < 4)
progenitor.hunger_message_level = 4
to_chat(affected_mob, "<i><b><font face = Tempus Sans ITC>His Grace starves in your hands. Feed Me the unclean or suffer.</font></b></i>")
if(400 to INFINITY)
affected_mob.visible_message("<span class='userdanger'>[progenitor] consumes [affected_mob] whole!</span>")
progenitor.consume(affected_mob)
return
progenitor.hunger += min(max((progenitor.force / 10), 1), 10)
else
affected_mob.status_flags |= CANSTUN | CANWEAKEN | CANPARALYSE
if(stage == 4)
if(get_dist(get_turf(progenitor), get_turf(affected_mob)) <= 7)
stage = 1
return
if(prob(4))
to_chat(affected_mob, "<span class='danger'>You are too far from His Grace...</span>")
affected_mob.adjustToxLoss(5)
else if(prob(6))
to_chat(affected_mob, "<span class='danger'>You feel weak.</span>")
affected_mob.adjustBruteLoss(5)
if(ismob(progenitor.loc))
progenitor.hunger++

View File

@@ -132,3 +132,24 @@
new /obj/item/stack/cable_coil(src, 30, paramcolor = pickedcolor) new /obj/item/stack/cable_coil(src, 30, paramcolor = pickedcolor)
new /obj/item/wirecutters(src) new /obj/item/wirecutters(src)
new /obj/item/multitool(src) new /obj/item/multitool(src)
/obj/item/storage/toolbox/artistic
name = "artistic toolbox"
desc = "A toolbox painted bright green. Why anyone would store art supplies in a toolbox is beyond you, but it has plenty of extra space."
icon_state = "green"
item_state = "artistic_toolbox"
w_class = WEIGHT_CLASS_GIGANTIC //Holds more than a regular toolbox!
max_combined_w_class = 20
storage_slots = 10
/obj/item/storage/toolbox/artistic/populate_contents()
new /obj/item/storage/fancy/crayons(src)
new /obj/item/crowbar(src)
new /obj/item/stack/cable_coil(src)
new /obj/item/stack/cable_coil/yellow(src)
new /obj/item/stack/cable_coil/blue(src)
new /obj/item/stack/cable_coil/green(src)
new /obj/item/stack/cable_coil/pink(src)
new /obj/item/stack/cable_coil/orange(src)
new /obj/item/stack/cable_coil/cyan(src)
new /obj/item/stack/cable_coil/white(src)

View File

@@ -251,6 +251,12 @@ GLOBAL_DATUM_INIT(global_prizes, /datum/prizes, new())
typepath = /obj/item/toy/foamblade typepath = /obj/item/toy/foamblade
cost = 100 cost = 100
/datum/prize_item/wind_up_toolbox
name = "Wind Up Toolbox"
desc = "A replica toolbox that rumbles when you turn the key."
typepath = /obj/item/toy/windup_toolbox
cost = 100
/datum/prize_item/redbutton /datum/prize_item/redbutton
name = "Shiny Red Button" name = "Shiny Red Button"
desc = "PRESS IT!" desc = "PRESS IT!"

View File

@@ -323,7 +323,7 @@
/obj/item/lava_staff, /obj/item/lava_staff,
/obj/item/katana/energy, /obj/item/katana/energy,
/obj/item/hierophant_club, /obj/item/hierophant_club,
/obj/item/storage/toolbox/green/memetic, /obj/item/his_grace,
/obj/item/gun/projectile/automatic/l6_saw, /obj/item/gun/projectile/automatic/l6_saw,
/obj/item/gun/magic/staff/chaos, /obj/item/gun/magic/staff/chaos,
/obj/item/gun/magic/staff/spellblade, /obj/item/gun/magic/staff/spellblade,

View File

@@ -214,7 +214,7 @@
var/list/allowed_toolbox = list(/obj/item/storage/toolbox/emergency, //which toolboxes can be made into floorbots var/list/allowed_toolbox = list(/obj/item/storage/toolbox/emergency, //which toolboxes can be made into floorbots
/obj/item/storage/toolbox/electrical, /obj/item/storage/toolbox/electrical,
/obj/item/storage/toolbox/mechanical, /obj/item/storage/toolbox/mechanical,
/obj/item/storage/toolbox/green, /obj/item/storage/toolbox/artistic,
/obj/item/storage/toolbox/syndicate, /obj/item/storage/toolbox/syndicate,
/obj/item/storage/toolbox/fakesyndi) /obj/item/storage/toolbox/fakesyndi)
@@ -223,8 +223,6 @@
return return
if(!is_type_in_list(src, allowed_toolbox)) if(!is_type_in_list(src, allowed_toolbox))
return return
if(type == /obj/item/storage/toolbox/green/memetic)
return
if(contents.len >= 1) if(contents.len >= 1)
to_chat(user, "<span class='warning'>They won't fit in, as there is already stuff inside.</span>") to_chat(user, "<span class='warning'>They won't fit in, as there is already stuff inside.</span>")
return return
@@ -242,7 +240,7 @@
B.toolbox_color = "or" B.toolbox_color = "or"
if(/obj/item/storage/toolbox/electrical) if(/obj/item/storage/toolbox/electrical)
B.toolbox_color = "y" B.toolbox_color = "y"
if(/obj/item/storage/toolbox/green) if(/obj/item/storage/toolbox/artistic)
B.toolbox_color = "g" B.toolbox_color = "g"
if(/obj/item/storage/toolbox/syndicate) if(/obj/item/storage/toolbox/syndicate)
B.toolbox_color = "s" B.toolbox_color = "s"

View File

@@ -69,7 +69,7 @@ Difficulty: Medium
ranged_cooldown = world.time + ranged_cooldown_time ranged_cooldown = world.time + ranged_cooldown_time
else else
visible_message("<span class='warning'><b>[src] charges!</b></span>") visible_message("<span class='warning'><b>[src] charges!</b></span>")
SpinAnimation(speed = 20, loops = 5) SpinAnimation(speed = 20, loops = 5, parallel = FALSE)
ranged = 0 ranged = 0
retreat_distance = 0 retreat_distance = 0
minimum_distance = 0 minimum_distance = 0

View File

@@ -365,9 +365,6 @@
// STUN // STUN
/mob/living/Stun(amount, updating = 1, force = 0) /mob/living/Stun(amount, updating = 1, force = 0)
if(status_flags & CANSTUN || force)
if(absorb_stun(amount, force))
return FALSE
return SetStunned(max(stunned, amount), updating, force) return SetStunned(max(stunned, amount), updating, force)
/mob/living/SetStunned(amount, updating = 1, force = 0) //if you REALLY need to set stun to a set amount without the whole "can't go below current stunned" /mob/living/SetStunned(amount, updating = 1, force = 0) //if you REALLY need to set stun to a set amount without the whole "can't go below current stunned"
@@ -377,6 +374,8 @@
. = STATUS_UPDATE_NONE . = STATUS_UPDATE_NONE
if(status_flags & CANSTUN || force) if(status_flags & CANSTUN || force)
if(absorb_stun(amount, force))
return STATUS_UPDATE_NONE
stunned = max(amount, 0) stunned = max(amount, 0)
if(updating) if(updating)
update_canmove() update_canmove()
@@ -405,9 +404,6 @@
// WEAKEN // WEAKEN
/mob/living/Weaken(amount, updating = 1, force = 0) /mob/living/Weaken(amount, updating = 1, force = 0)
if(status_flags & CANWEAKEN || force)
if(absorb_stun(amount, force))
return FALSE
return SetWeakened(max(weakened, amount), updating, force) return SetWeakened(max(weakened, amount), updating, force)
/mob/living/SetWeakened(amount, updating = 1, force = 0) /mob/living/SetWeakened(amount, updating = 1, force = 0)
@@ -416,6 +412,8 @@
updating = FALSE updating = FALSE
. = STATUS_UPDATE_NONE . = STATUS_UPDATE_NONE
if(status_flags & CANWEAKEN || force) if(status_flags & CANWEAKEN || force)
if(absorb_stun(amount, force))
return STATUS_UPDATE_NONE
weakened = max(amount, 0) weakened = max(amount, 0)
if(updating) if(updating)
update_canmove() //updates lying, canmove and icons update_canmove() //updates lying, canmove and icons

0
code/modules/pda/PDA.dm Normal file → Executable file
View File

View File

@@ -365,6 +365,7 @@ h1.alert, h2.alert {color: #FFF;}
.greentext {color: #00FF00; font-size: 150%;} .greentext {color: #00FF00; font-size: 150%;}
.redtext {color: #FF0000; font-size: 150%;} .redtext {color: #FF0000; font-size: 150%;}
.bold {font-weight: bold;} .bold {font-weight: bold;}
.his_grace {color: #15D512; font-family: "Courier New", cursive, sans-serif; font-style: italic;}
.center {text-align: center;} .center {text-align: center;}
.red {color: #FF0000;} .red {color: #FF0000;}
.purple {color: #9031C4;} .purple {color: #9031C4;}

View File

@@ -362,6 +362,7 @@ h1.alert, h2.alert {color: #000000;}
.greentext {color: #00FF00; font-size: 150%;} .greentext {color: #00FF00; font-size: 150%;}
.redtext {color: #FF0000; font-size: 150%;} .redtext {color: #FF0000; font-size: 150%;}
.bold {font-weight: bold;} .bold {font-weight: bold;}
.his_grace {color: #15D512; font-family: "Courier New", cursive, sans-serif; font-style: italic;}
.center {text-align: center;} .center {text-align: center;}
.red {color: #FF0000;} .red {color: #FF0000;}
.purple {color: #5e2d79;} .purple {color: #5e2d79;}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 70 KiB

View File

@@ -851,6 +851,7 @@
#include "code\game\objects\items\documents.dm" #include "code\game\objects\items\documents.dm"
#include "code\game\objects\items\flag.dm" #include "code\game\objects\items\flag.dm"
#include "code\game\objects\items\hand_item.dm" #include "code\game\objects\items\hand_item.dm"
#include "code\game\objects\items\his_grace.dm"
#include "code\game\objects\items\latexballoon.dm" #include "code\game\objects\items\latexballoon.dm"
#include "code\game\objects\items\misc.dm" #include "code\game\objects\items\misc.dm"
#include "code\game\objects\items\mixing_bowl.dm" #include "code\game\objects\items\mixing_bowl.dm"
@@ -1023,7 +1024,6 @@
#include "code\game\objects\items\weapons\implants\implantuplink.dm" #include "code\game\objects\items\weapons\implants\implantuplink.dm"
#include "code\game\objects\items\weapons\melee\energy.dm" #include "code\game\objects\items\weapons\melee\energy.dm"
#include "code\game\objects\items\weapons\melee\misc.dm" #include "code\game\objects\items\weapons\melee\misc.dm"
#include "code\game\objects\items\weapons\storage\artistic_toolbox.dm"
#include "code\game\objects\items\weapons\storage\backpack.dm" #include "code\game\objects\items\weapons\storage\backpack.dm"
#include "code\game\objects\items\weapons\storage\bags.dm" #include "code\game\objects\items\weapons\storage\bags.dm"
#include "code\game\objects\items\weapons\storage\belt.dm" #include "code\game\objects\items\weapons\storage\belt.dm"

Binary file not shown.

Binary file not shown.