diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm index cc8104f98b..d505f69ac9 100644 --- a/code/__DEFINES/status_effects.dm +++ b/code/__DEFINES/status_effects.dm @@ -42,6 +42,8 @@ #define STATUS_EFFECT_BELLIGERENT /datum/status_effect/belligerent //forces the affected to walk, doing damage if they try to run +#define STATUS_EFFECT_GEISTRACKER /datum/status_effect/geis_tracker //if you're using geis, this tracks that and keeps you from using scripture + #define STATUS_EFFECT_MANIAMOTOR /datum/status_effect/maniamotor //disrupts, damages, and confuses the affected as long as they're in range of the motor #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 diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm index 2c651b7738..02e7d0f515 100644 --- a/code/datums/status_effects/debuffs.dm +++ b/code/datums/status_effects/debuffs.dm @@ -139,6 +139,20 @@ if(owner.m_intent == MOVE_INTENT_WALK) owner.toggle_move_intent() +/datum/status_effect/geis_tracker + id = "geis_tracker" + duration = -1 + alert_type = null + var/obj/structure/destructible/clockwork/geis_binding/binding + +/datum/status_effect/geis_tracker/on_creation(mob/living/new_owner, obj/structure/destructible/clockwork/geis_binding/new_binding) + . = ..() + if(.) + binding = new_binding + +/datum/status_effect/geis_tracker/tick() + if(QDELETED(binding)) + qdel(src) /datum/status_effect/maniamotor id = "maniamotor" diff --git a/code/game/gamemodes/clock_cult/clock_effects/clock_sigils.dm b/code/game/gamemodes/clock_cult/clock_effects/clock_sigils.dm index 31a98f572f..507c673921 100644 --- a/code/game/gamemodes/clock_cult/clock_effects/clock_sigils.dm +++ b/code/game/gamemodes/clock_cult/clock_effects/clock_sigils.dm @@ -11,9 +11,21 @@ var/stat_affected = CONSCIOUS var/sigil_name = "Sigil" var/resist_string = "glows blinding white" //string for when a null rod blocks its effects, "glows [resist_string]" + var/list/component_refund = list() /obj/effect/clockwork/sigil/attackby(obj/item/I, mob/living/user, params) - if(I.force && !is_servant_of_ratvar(user)) + if(is_servant_of_ratvar(user)) + if(istype(I, /obj/item/clockwork/slab)) + user.visible_message("[user] starts to dispel [src]...", "You start to dispel [src]...") + if(do_after(user, 20, target = src)) + user.visible_message("[user] dispels [src]!", "You dispel [src]!") + for(var/i in component_refund) + if(component_refund[i]) + for(var/r in 1 to component_refund[i]) + generate_cache_component(i, src) + qdel(src) + return 1 + else if(I.force) user.visible_message("[user] scatters [src] with [I]!", "You scatter [src] with [I]!") qdel(src) return 1 @@ -63,6 +75,7 @@ light_power = 1 light_color = "#FAE48C" sigil_name = "Sigil of Transgression" + component_refund = list(HIEROPHANT_ANSIBLE = 1) /obj/effect/clockwork/sigil/transgression/sigil_effects(mob/living/L) var/target_flashed = L.flash_act() @@ -94,27 +107,33 @@ light_color = "#FAE48C" stat_affected = UNCONSCIOUS resist_string = "glows faintly yellow" + sigil_name = "Sigil of Submission" + component_refund = list(GEIS_CAPACITOR = 1) var/convert_time = 80 var/delete_on_finish = TRUE - sigil_name = "Sigil of Submission" var/glow_type = /obj/effect/temp_visual/ratvar/sigil/submission /obj/effect/clockwork/sigil/submission/sigil_effects(mob/living/L) + if(istype(L.buckled, /obj/structure/destructible/clockwork/geis_binding)) + if(is_servant_of_ratvar(L.pulledby)) + L.pulledby.stop_pulling() + if(is_servant_of_ratvar(L.buckled.pulledby)) + L.buckled.pulledby.stop_pulling() L.visible_message("[src] begins to glow a piercing magenta!", "You feel something start to invade your mind...") var/oldcolor = color - animate(src, color = "#AF0AAF", time = convert_time, flags_1 = ANIMATION_END_NOW) + animate(src, color = "#AF0AAF", time = convert_time, flags = ANIMATION_END_NOW) var/obj/effect/temp_visual/ratvar/sigil/glow if(glow_type) glow = new glow_type(get_turf(src)) animate(glow, alpha = 255, time = convert_time) var/I = 0 - while(I < convert_time && get_turf(L) == get_turf(src)) + while(I < convert_time && !QDELETED(L) && get_turf(L) == get_turf(src)) I++ sleep(1) - if(get_turf(L) != get_turf(src)) + if(QDELETED(L) || get_turf(L) != get_turf(src)) if(glow) qdel(glow) - animate(src, color = oldcolor, time = 20, flags_1 = ANIMATION_END_NOW) + animate(src, color = oldcolor, time = 20, flags = ANIMATION_END_NOW) addtimer(CALLBACK(src, /atom/proc/update_atom_colour), 20) visible_message("[src] slowly stops glowing!") return @@ -136,7 +155,7 @@ to_chat(M, "[message] you!") else to_chat(M, "[message] [L.real_name]!") - animate(src, color = oldcolor, time = 20, flags_1 = ANIMATION_END_NOW) + animate(src, color = oldcolor, time = 20, flags = ANIMATION_END_NOW) addtimer(CALLBACK(src, /atom/proc/update_atom_colour), 20) visible_message("[src] slowly stops glowing!") @@ -152,6 +171,7 @@ light_color = "#EC8A2D" resist_string = "glows faintly" sigil_name = "Sigil of Transmission" + component_refund = list(HIEROPHANT_ANSIBLE = 1) affects_servants = TRUE var/power_charge = 0 //starts with no power var/drain_range = 14 @@ -296,6 +316,7 @@ stat_affected = DEAD resist_string = "glows shimmering yellow" sigil_name = "Vitality Matrix" + component_refund = list(VANGUARD_COGWHEEL = 1) var/revive_cost = 150 var/sigil_active = FALSE var/animation_number = 3 //each cycle increments this by 1, at 4 it produces an animation and resets @@ -314,7 +335,7 @@ if((is_servant_of_ratvar(L) && L.suiciding) || sigil_active) return visible_message("[src] begins to glow bright blue!") - animate(src, alpha = 255, time = 10, flags_1 = ANIMATION_END_NOW) //we may have a previous animation going. finish it first, then do this one without delay. + animate(src, alpha = 255, time = 10, flags = ANIMATION_END_NOW) //we may have a previous animation going. finish it first, then do this one without delay. sleep(10) //as long as they're still on the sigil and are either not a servant or they're a servant AND it has remaining vitality while(L && (!is_servant_of_ratvar(L) || (is_servant_of_ratvar(L) && (GLOB.ratvar_awakens || GLOB.clockwork_vitality))) && get_turf(L) == get_turf(src)) @@ -380,4 +401,4 @@ animation_number = initial(animation_number) sigil_active = FALSE visible_message("[src] slowly stops glowing!") - animate(src, alpha = initial(alpha), time = 10, flags_1 = ANIMATION_END_NOW) + animate(src, alpha = initial(alpha), time = 10, flags = ANIMATION_END_NOW) diff --git a/code/game/gamemodes/clock_cult/clock_helpers/slab_abilities.dm b/code/game/gamemodes/clock_cult/clock_helpers/slab_abilities.dm index 74d9112fc4..fb3a0c3de2 100644 --- a/code/game/gamemodes/clock_cult/clock_helpers/slab_abilities.dm +++ b/code/game/gamemodes/clock_cult/clock_helpers/slab_abilities.dm @@ -24,15 +24,10 @@ //For the Geis scripture; binds a target to convert. /obj/effect/proc_holder/slab/geis ranged_mousepointer = 'icons/effects/geis_target.dmi' - var/obj/structure/destructible/clockwork/geis_binding/binding //we always have a reference to the binding - var/obj/structure/destructible/clockwork/geis_binding/pulled_binding //we use this to see if we're pulling it or not - -/obj/effect/proc_holder/slab/geis/remove_ranged_ability(msg) - ..() - binding = null - pulled_binding = null /obj/effect/proc_holder/slab/geis/InterceptClickOn(mob/living/caller, params, atom/target) + if(..()) + return TRUE var/turf/T = ranged_ability_user.loc if(!isturf(T)) return TRUE @@ -40,20 +35,6 @@ var/target_is_binding = istype(target, /obj/structure/destructible/clockwork/geis_binding) if((target_is_binding || isliving(target)) && ranged_ability_user.Adjacent(target)) - if(in_progress || ..()) - var/mob/living/L = target - if(!pulled_binding) - if(target == binding || (isliving(target) && L.buckled == binding)) - pulled_binding = binding - ranged_ability_user.start_pulling(binding) - remove_mousepointer(ranged_ability_user.client) - ranged_mousepointer = 'icons/effects/geis_target_remove.dmi' - add_mousepointer(ranged_ability_user.client) - else if(target == pulled_binding || (isliving(target) && L.buckled == pulled_binding)) - ranged_ability_user.visible_message("[ranged_ability_user] dispels [pulled_binding]!", "You dispel the binding!") - binding.take_damage(obj_integrity) - remove_ranged_ability() - return TRUE if(target_is_binding) var/obj/structure/destructible/clockwork/geis_binding/GB = target GB.repair_and_interrupt() @@ -80,42 +61,19 @@ add_logs(ranged_ability_user, L, "rebound with Geis") successful = TRUE else - in_progress = TRUE clockwork_say(ranged_ability_user, text2ratvar("Be bound, heathen!")) - remove_mousepointer(ranged_ability_user.client) - ranged_mousepointer = 'icons/effects/geis_target_remove.dmi' - add_mousepointer(ranged_ability_user.client) add_logs(ranged_ability_user, L, "bound with Geis") - playsound(target, 'sound/magic/blink.ogg', 50, TRUE, frequency = 0.5) + playsound(target, 'sound/magic/blink.ogg', 50, TRUE, -4, frequency = 0.5) if(slab.speed_multiplier >= 0.5) //excuse my debug... ranged_ability_user.notransform = TRUE - addtimer(CALLBACK(src, .proc/reset_user_notransform, ranged_ability_user), 5) //stop us moving for a little bit so we don't break the binding immediately + addtimer(CALLBACK(src, .proc/reset_user_notransform, ranged_ability_user), 4) //stop us moving for a little bit so we don't break the binding immediately if(L.buckled) L.buckled.unbuckle_mob(target, TRUE) - binding = new(get_turf(target)) + var/obj/structure/destructible/clockwork/geis_binding/binding = new(get_turf(target)) binding.setDir(target.dir) binding.buckle_mob(target, TRUE) - pulled_binding = binding ranged_ability_user.start_pulling(binding) - slab.busy = "sustaining Geis" - slab.flags_1 |= NODROP_1 - while(!QDELETED(binding) && !QDELETED(ranged_ability_user)) - if(ranged_ability_user.pulling == binding) - pulled_binding = binding - if(ranged_ability_user.client && ranged_ability_user.client.mouse_pointer_icon == 'icons/effects/geis_target.dmi') - remove_mousepointer(ranged_ability_user.client) - ranged_mousepointer = 'icons/effects/geis_target_remove.dmi' - add_mousepointer(ranged_ability_user.client) - else //if we're not pulling it, swap our mousepointer - pulled_binding = null - if(ranged_ability_user.client && ranged_ability_user.client.mouse_pointer_icon == 'icons/effects/geis_target_remove.dmi') - remove_mousepointer(ranged_ability_user.client) - ranged_mousepointer = 'icons/effects/geis_target.dmi' - add_mousepointer(ranged_ability_user.client) - sleep(1) - if(!QDELETED(slab)) - slab.flags_1 &= ~NODROP_1 - in_progress = FALSE + ranged_ability_user.apply_status_effect(STATUS_EFFECT_GEISTRACKER, binding) successful = TRUE remove_ranged_ability() diff --git a/code/game/gamemodes/clock_cult/clock_scripture.dm b/code/game/gamemodes/clock_cult/clock_scripture.dm index 382aaec10d..318d3e243d 100644 --- a/code/game/gamemodes/clock_cult/clock_scripture.dm +++ b/code/game/gamemodes/clock_cult/clock_scripture.dm @@ -57,6 +57,9 @@ Judgement: 12 servants, 5 caches, 300 CV, and any existing AIs are converted or if(slab.busy) to_chat(invoker, "[slab] refuses to work, displaying the message: \"[slab.busy]!\"") return FALSE + if(invoker.has_status_effect(STATUS_EFFECT_GEISTRACKER)) + to_chat(invoker, "[slab] refuses to work, displaying the message: \"Sustaining Geis!\"") + return FALSE slab.busy = "Invocation ([name]) in progress" if(GLOB.ratvar_awakens) channel_time *= 0.5 //if ratvar has awoken, half channel time and no cost diff --git a/code/game/gamemodes/clock_cult/clock_structures/geis_binding.dm b/code/game/gamemodes/clock_cult/clock_structures/geis_binding.dm index 734ea8eb17..029fd552e2 100644 --- a/code/game/gamemodes/clock_cult/clock_structures/geis_binding.dm +++ b/code/game/gamemodes/clock_cult/clock_structures/geis_binding.dm @@ -2,8 +2,8 @@ /obj/structure/destructible/clockwork/geis_binding name = "glowing ring" desc = "A flickering, glowing purple ring around a target." - clockwork_desc = "A binding ring around a target, preventing them from taking action while they're being converted." - max_integrity = 25 + clockwork_desc = "A binding ring around a target, preventing them from taking action." + max_integrity = 20 light_range = 2 light_power = 0.8 light_color = "#AF0AAF" @@ -18,6 +18,8 @@ can_buckle = TRUE buckle_lying = 0 var/mob_layer = MOB_LAYER + var/last_mob_health = 0 + var/apply_time = 0 /obj/structure/destructible/clockwork/geis_binding/Initialize(mapload, obj/item/clockwork/slab/the_slab) . = ..() @@ -33,21 +35,39 @@ icon_state = "geisbinding" /obj/structure/destructible/clockwork/geis_binding/process() + var/tick_damage = 1 + if(locate(/obj/effect/clockwork/sigil/submission) in loc) + tick_damage *= 0.5 if(LAZYLEN(buckled_mobs)) for(var/V in buckled_mobs) var/mob/living/L = V if(is_servant_of_ratvar(L)) //servants are freed automatically take_damage(obj_integrity) return - var/tick_damage = 1 - if(!is_servant_of_ratvar(pulledby)) - tick_damage++ + if(last_mob_health > L.health) + tick_damage += last_mob_health - L.health + last_mob_health = L.health + if(L.layer != mob_layer) + mob_layer = L.layer + layer = mob_layer - 0.01 + cut_overlays() + add_overlay(mutable_appearance('icons/effects/clockwork_effects.dmi', "geisbinding_top", mob_layer + 0.01)) + break take_damage(tick_damage, sound_effect = FALSE) - playsound(src, 'sound/effects/empulse.ogg', tick_damage * 20, TRUE) + playsound(src, 'sound/effects/empulse.ogg', tick_damage * 40, TRUE, -4) /obj/structure/destructible/clockwork/geis_binding/attack_hand(mob/living/user) return +/obj/structure/destructible/clockwork/geis_binding/attackby(obj/item/I, mob/user, params) + if(is_servant_of_ratvar(user) && istype(I, /obj/item/clockwork/slab)) + user.visible_message("[user] starts to dispel [src]...", "You start to dispel [src]...") + if(do_after(user, 30, target = src)) + user.visible_message("[user] dispels [src]!", "You dispel [src]!") + take_damage(obj_integrity) + return 1 + return ..() + /obj/structure/destructible/clockwork/geis_binding/emp_act(severity) new /obj/effect/temp_visual/emp(loc) qdel(src) @@ -56,16 +76,22 @@ ..() if(M.buckled == src) desc = "A flickering, glowing purple ring around [M]." - clockwork_desc = "A binding ring around [M], preventing [M.p_them()] from taking action while [M.p_theyre()] being converted." + clockwork_desc = "A binding ring around [M], preventing [M.p_them()] from taking action." icon_state = "geisbinding" mob_layer = M.layer - layer = M.layer - 0.01 - add_overlay(mutable_appearance('icons/effects/clockwork_effects.dmi', "geisbinding_top", M.layer + 0.01)) + layer = mob_layer - 0.01 + add_overlay(mutable_appearance('icons/effects/clockwork_effects.dmi', "geisbinding_top", mob_layer + 0.01)) + last_mob_health = M.health + apply_time = world.time for(var/obj/item/I in M.held_items) M.dropItemToGround(I) for(var/i in M.get_empty_held_indexes()) var/obj/item/geis_binding/B = new(M) M.put_in_hands(B, i) + if(iscarbon(M)) + var/mob/living/carbon/C = M + if(!C.handcuffed) + C.handcuffed = new /obj/item/restraints/handcuffs/energy/clock(C) M.regenerate_icons() M.visible_message("A [name] appears around [M]!", "A [name] appears around you!") repair_and_interrupt() @@ -79,8 +105,17 @@ animate(G, transform = matrix()*2, alpha = 0, time = 8, easing = EASE_OUT) animate(T, transform = matrix()*2, alpha = 0, time = 8, easing = EASE_OUT) M.visible_message("[src] snaps into glowing pieces and dissipates!") + M.AdjustStun(-130 + (apply_time - world.time), 1, 1) //remove exactly as much stun as was applied + if(iscarbon(M)) + var/mob/living/carbon/C = M + C.silent = max(C.silent - 7, 0) for(var/obj/item/geis_binding/GB in M.held_items) M.dropItemToGround(GB, TRUE) + if(iscarbon(M)) + var/mob/living/carbon/C = M + if(istype(C.handcuffed, /obj/item/restraints/handcuffs/energy/clock)) + QDEL_NULL(C.handcuffed) + C.update_handcuffed() /obj/structure/destructible/clockwork/geis_binding/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0) playsound(src, 'sound/effects/empulse.ogg', 50, 1) @@ -130,3 +165,10 @@ /obj/item/geis_binding/pre_attackby(atom/target, mob/living/user, params) return FALSE + +/obj/item/restraints/handcuffs/energy/clock + name = "glowing rings" + desc = "Flickering rings preventing you from holding items." + icon = 'icons/effects/clockwork_effects.dmi' + icon_state = "geisbinding_full" + flags_1 = NODROP_1|ABSTRACT_1|DROPDEL_1 diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm index 3b5af86147..0c70ee63c8 100644 --- a/code/game/objects/obj_defense.dm +++ b/code/game/objects/obj_defense.dm @@ -5,7 +5,7 @@ play_attack_sound(damage_amount, damage_type, damage_flag) if(!(resistance_flags & INDESTRUCTIBLE) && obj_integrity > 0) damage_amount = run_obj_armor(damage_amount, damage_type, damage_flag, attack_dir) - if(damage_amount >= 1) + if(damage_amount >= 0.1) . = damage_amount obj_integrity = max(obj_integrity - damage_amount, 0) if(obj_integrity <= 0)