diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index b5affa5007bd..6603816438f8 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -221,7 +221,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// This allows a person who has antimagic to cast spells without getting blocked #define TRAIT_ANTIMAGIC_NO_SELFBLOCK "anti_magic_no_selfblock" /// This mob recently blocked magic with some form of antimagic -/* #define TRAIT_RECENTLY_BLOCKED_MAGIC "recently_blocked_magic" */ +#define TRAIT_RECENTLY_BLOCKED_MAGIC "recently_blocked_magic" /// The user can do things like use magic staffs without penalty #define TRAIT_MAGICALLY_GIFTED "magically_gifted" /// This object innately spawns with fantasy variables already applied (the magical component is given to it on initialize), and thus we never want to give it the component again. diff --git a/code/__DEFINES/~monkestation/antagonists.dm b/code/__DEFINES/~monkestation/antagonists.dm index 52095ecd4619..1fa0ecd55672 100644 --- a/code/__DEFINES/~monkestation/antagonists.dm +++ b/code/__DEFINES/~monkestation/antagonists.dm @@ -19,7 +19,7 @@ // Clock cultist #define IS_CLOCK(mob) ((FACTION_CLOCK in mob.faction) || mob?.mind?.has_antag_datum(/datum/antagonist/clock_cultist)) /// maximum amount of cogscarabs the clock cult can have -#define MAXIMUM_COGSCARABS 9 +#define MAXIMUM_COGSCARABS 6 /// is something a cogscarab #define iscogscarab(checked) (istype(checked, /mob/living/basic/drone/cogscarab)) /// is something an eminence diff --git a/code/__DEFINES/~monkestation/clock_cult.dm b/code/__DEFINES/~monkestation/clock_cult.dm index 2d765bf45a70..d11fd19e960e 100644 --- a/code/__DEFINES/~monkestation/clock_cult.dm +++ b/code/__DEFINES/~monkestation/clock_cult.dm @@ -29,8 +29,14 @@ ///the map path of the reebe map #define REEBE_MAP_PATH "_maps/~monkestation/templates/reebe.dmm" +///how long in seconds do anchoring crystals take to charge after being placed, 6 minutes +#define ANCHORING_CRYSTAL_CHARGE_DURATION 360 SECONDS + ///how long between uses of the anchoring crystal scripture, also how long the hostile environment lasts if the crystal is not destroyed -#define ANCHORING_CRYSTAL_COOLDOWN 7 MINUTES +#define ANCHORING_CRYSTAL_COOLDOWN ANCHORING_CRYSTAL_CHARGE_DURATION + 1 MINUTE ///up to how many tiles away will the ark stop certain things from breaking turfs -#define ARK_TURF_DESTRUCTION_BLOCK_RANGE 9 +#define ARK_TURF_DESTRUCTION_BLOCK_RANGE 10 + +///how many clockwork airlocks is the cult allowed to create on reebe +#define MAXIMUM_REEBE_AIRLOCKS 50 diff --git a/code/__DEFINES/~monkestation/dcs/signals/signals_object.dm b/code/__DEFINES/~monkestation/dcs/signals/signals_object.dm index 7e3bfcc3e769..e388c098f705 100644 --- a/code/__DEFINES/~monkestation/dcs/signals/signals_object.dm +++ b/code/__DEFINES/~monkestation/dcs/signals/signals_object.dm @@ -1,2 +1,8 @@ -//flag to block the qdel that normally happens when a projectile is blocked +///flag to block the qdel that normally happens when a projectile is blocked #define PROJECTILE_INTERRUPT_BLOCK_QDEL (4<<0) + +///sent by the ark SS whenever an anchoring crystal charges (/obj/structure/destructible/clockwork/anchoring_crystal/charged_crystal) +#define COMSIG_ANCHORING_CRYSTAL_CHARGED "anchoring_crystal_charged" + +///sent by the ark SS whenever an anchoring crystal is created (/obj/structure/destructible/clockwork/anchoring_crystal/charged_crystal) +#define COMSIG_ANCHORING_CRYSTAL_CREATED "anchoring_crystal_created" diff --git a/code/__DEFINES/~monkestation/maps.dm b/code/__DEFINES/~monkestation/maps.dm index 5d0724ebcd37..ba1728004e77 100644 --- a/code/__DEFINES/~monkestation/maps.dm +++ b/code/__DEFINES/~monkestation/maps.dm @@ -7,6 +7,10 @@ #define ZTRAIT_FORCED_SAFETY "Forced Safety" ///List of ztraits the reebe Z level has -#define ZTRAITS_REEBE list(ZTRAIT_REEBE = TRUE, ZTRAIT_NOPHASE = TRUE, ZTRAIT_BOMBCAP_MULTIPLIER = 0.5, ZTRAIT_RESERVED = TRUE) +#define ZTRAITS_REEBE list(ZTRAIT_REEBE = TRUE, \ + ZTRAIT_NOPHASE = TRUE, \ + ZTRAIT_BOMBCAP_MULTIPLIER = 0.5, \ + ZTRAIT_RESERVED = TRUE, \ + ZTRAIT_BASETURF = /turf/open/indestructible/reebe_flooring) #define is_safe_level(z) SSmapping.level_trait(z, ZTRAIT_FORCED_SAFETY) diff --git a/code/__HELPERS/~monkestation-helpers/spatial_info.dm b/code/__HELPERS/~monkestation-helpers/spatial_info.dm new file mode 100644 index 000000000000..82b88bb17e09 --- /dev/null +++ b/code/__HELPERS/~monkestation-helpers/spatial_info.dm @@ -0,0 +1,96 @@ +#define EDGE_STATE_SOUTH_BORDER 1 +#define EDGE_STATE_MAP_BOTTOM 2 +#define EDGE_STATE_MAP_TOP 3 +#define SET_DIR_LIST(dir_list, edge_state) \ + switch(edge_state) { \ + if(EDGE_STATE_MAP_BOTTOM) { \ + ##dir_list = GLOB.cardinals - SOUTH;\ + } \ + if(EDGE_STATE_MAP_TOP) { \ + ##dir_list = GLOB.cardinals - NORTH;\ + } \ + else { \ + ##dir_list = GLOB.cardinals;\ + } \ + } + +#define ADD_NEW_AREAS(dir_list, step_turf, step_of, checked, added_to) \ + for(var/dir in dir_list) { \ + ##step_turf = get_step(step_of, dir);\ + if(step_turf && step_turf.loc != checked) { \ + ##added_to |= step_turf.loc;\ + } \ + } + +///Returns all turfs on the border of an area +/proc/get_area_edge_turfs(area/checked, return_adjacent_areas = FALSE) as /list + RETURN_TYPE(/list) + var/list/returned_list = list() + for(var/i in 1 to length(checked.turfs_by_zlevel)) + var/list/z_turfs = checked.turfs_by_zlevel[i] + var/list/new_list = list() + var/last_y = 0 + var/edge_state = FALSE + var/turf/last_checked + returned_list.len++ + returned_list[i] = new_list + for(var/turf/z_turf in z_turfs) + if(z_turf.y != last_y) + last_y = z_turf.y + if(last_checked) + if(return_adjacent_areas) + var/list/dir_list + SET_DIR_LIST(dir_list, edge_state) + var/turf/step_turf + ADD_NEW_AREAS(dir_list, step_turf, last_checked, checked, new_list) + else + new_list += last_checked + + if(z_turf.y == 1) + edge_state = EDGE_STATE_MAP_BOTTOM + else if(last_y == 0) + edge_state = EDGE_STATE_SOUTH_BORDER + else if(z_turf.y == world.maxy) + edge_state = EDGE_STATE_MAP_TOP + else + edge_state = FALSE + + if(return_adjacent_areas) + var/list/dir_list + SET_DIR_LIST(dir_list, edge_state) + var/turf/step_turf + ADD_NEW_AREAS(dir_list, step_turf, z_turf, checked, new_list) + else + new_list += z_turf + last_checked = null + continue + + if(edge_state) + if(return_adjacent_areas) + var/list/dir_list + SET_DIR_LIST(dir_list, edge_state) + var/turf/step_turf + ADD_NEW_AREAS(dir_list, step_turf, z_turf, checked, new_list) + else + new_list += z_turf + continue + + var/turf/north_turf = get_step(z_turf, NORTH) + if(north_turf.loc != checked) //if we dont have a step something else already broke as map borders have already been handled + if(return_adjacent_areas) + var/list/dir_list = GLOB.cardinals - NORTH + if(edge_state == EDGE_STATE_MAP_BOTTOM) + dir_list -= SOUTH + var/turf/step_turf + ADD_NEW_AREAS(dir_list, step_turf, z_turf, checked, new_list) + new_list |= (return_adjacent_areas ? north_turf.loc : z_turf) + last_checked = null + else + last_checked = z_turf + return returned_list + +#undef EDGE_STATE_SOUTH_BORDER +#undef EDGE_STATE_MAP_BOTTOM +#undef EDGE_STATE_MAP_TOP +#undef SET_DIR_LIST +#undef ADD_NEW_AREAS diff --git a/code/controllers/subsystem/machines.dm b/code/controllers/subsystem/machines.dm index 0d132d93d660..88f1d363f8a6 100644 --- a/code/controllers/subsystem/machines.dm +++ b/code/controllers/subsystem/machines.dm @@ -35,13 +35,13 @@ SUBSYSTEM_DEF(machines) all_machines -= machine /// Gets a list of all machines that are either the passed type or a subtype. -/datum/controller/subsystem/machines/proc/get_machines_by_type_and_subtypes(obj/machinery/machine_type) +/datum/controller/subsystem/machines/proc/get_machines_by_type_and_subtypes(obj/machinery/machine_type, list/type_exclusions) //monkestation edit: adds type_exclusions if(!ispath(machine_type)) machine_type = machine_type.type if(!ispath(machine_type, /obj/machinery)) CRASH("called get_machines_by_type_and_subtypes with a non-machine type [machine_type]") var/list/machines = list() - for(var/next_type in typesof(machine_type)) + for(var/next_type in typesof(machine_type) - type_exclusions) //monkestation edit: adds type_exclusions var/list/found_machines = machines_by_type[next_type] if(found_machines) machines += found_machines diff --git a/code/controllers/subsystem/timer.dm b/code/controllers/subsystem/timer.dm index 5bdbe1bc95ee..bc894de9beee 100644 --- a/code/controllers/subsystem/timer.dm +++ b/code/controllers/subsystem/timer.dm @@ -610,8 +610,8 @@ SUBSYSTEM_DEF(timer) * * timer_subsystem the subsystem to insert this timer into */ /proc/_addtimer(datum/callback/callback, wait = 0, flags = 0, datum/controller/subsystem/timer/timer_subsystem, file, line) - if (!callback) - CRASH("addtimer called without a callback") + ASSERT(istype(callback), "addtimer called [callback ? "with an invalid callback ([callback])" : "without a callback"]") + ASSERT(isnum(wait), "addtimer called with a non-numeric wait ([wait])") if (wait < 0) stack_trace("addtimer called with a negative wait. Converting to [world.tick_lag]") diff --git a/code/datums/components/anti_magic.dm b/code/datums/components/anti_magic.dm index 23c37190e88b..9105058e3828 100644 --- a/code/datums/components/anti_magic.dm +++ b/code/datums/components/anti_magic.dm @@ -3,15 +3,17 @@ /// A bitflag with the types of magic resistance on the object var/antimagic_flags /// The amount of times the object can protect the user from magic + /// Set to INFINITY to have, well, infinite charges. var/charges /// The inventory slot the object must be located at in order to activate var/inventory_flags - /// The proc that is triggered when an object has been drained a antimagic charge + /// The callback invoked when we have been drained a antimagic charge var/datum/callback/drain_antimagic - /// The proc that is triggered when the object is depleted of charges + /// The callback invoked when twe have been depleted of all charges var/datum/callback/expiration - /// If we have already sent a notification message to the mob picking up an antimagic item - var/casting_restriction_alert = FALSE + /// Whether we should, on equipping, alert the caster that this item can block any of their spells + /// This changes between true and false on equip and drop, don't set it outright to something + var/alert_caster_on_equip = TRUE /** * Adds magic resistances to an object @@ -36,7 +38,7 @@ charges = INFINITY, inventory_flags = ~ITEM_SLOT_BACKPACK, // items in a backpack won't activate, anywhere else is fine datum/callback/drain_antimagic, - datum/callback/expiration + datum/callback/expiration, ) if(isitem(parent)) @@ -44,10 +46,7 @@ RegisterSignal(parent, COMSIG_ITEM_DROPPED, PROC_REF(on_drop)) RegisterSignals(parent, list(COMSIG_ITEM_ATTACK, COMSIG_ITEM_ATTACK_OBJ), PROC_REF(on_attack)) else if(ismob(parent)) - RegisterSignal(parent, COMSIG_MOB_RECEIVE_MAGIC, PROC_REF(block_receiving_magic), override = TRUE) - RegisterSignal(parent, COMSIG_MOB_RESTRICT_MAGIC, PROC_REF(restrict_casting_magic), override = TRUE) - if(!HAS_TRAIT(parent, TRAIT_ANTIMAGIC_NO_SELFBLOCK)) - to_chat(parent, span_warning("Magic seems to flee from you. You are immune to spells but are unable to cast magic.")) + register_antimagic_signals(parent) else return COMPONENT_INCOMPATIBLE @@ -62,92 +61,66 @@ expiration = null return ..() -/datum/component/anti_magic/proc/on_equip(datum/source, mob/equipper, slot) +/datum/component/anti_magic/proc/register_antimagic_signals(datum/on_what) + RegisterSignal(on_what, COMSIG_MOB_RECEIVE_MAGIC, PROC_REF(block_receiving_magic), override = TRUE) + RegisterSignal(on_what, COMSIG_MOB_RESTRICT_MAGIC, PROC_REF(restrict_casting_magic), override = TRUE) + +/datum/component/anti_magic/proc/unregister_antimagic_signals(datum/on_what) + UnregisterSignal(on_what, list(COMSIG_MOB_RECEIVE_MAGIC, COMSIG_MOB_RESTRICT_MAGIC)) + +/datum/component/anti_magic/proc/on_equip(atom/movable/source, mob/equipper, slot) SIGNAL_HANDLER if(!(inventory_flags & slot)) //Check that the slot is valid for antimagic - UnregisterSignal(equipper, COMSIG_MOB_RECEIVE_MAGIC) - UnregisterSignal(equipper, COMSIG_MOB_RESTRICT_MAGIC) + unregister_antimagic_signals(equipper) + return + + register_antimagic_signals(equipper) + if(!alert_caster_on_equip) return - RegisterSignal(equipper, COMSIG_MOB_RECEIVE_MAGIC, PROC_REF(block_receiving_magic), override = TRUE) - RegisterSignal(equipper, COMSIG_MOB_RESTRICT_MAGIC, PROC_REF(restrict_casting_magic), override = TRUE) - if(!casting_restriction_alert) - // Check to see if we have any spells that are blocked due to antimagic - for(var/datum/action/cooldown/spell/magic_spell in equipper.actions) - if(!(magic_spell.spell_requirements & SPELL_REQUIRES_NO_ANTIMAGIC)) - continue + // Check to see if we have any spells that are blocked due to antimagic + for(var/datum/action/cooldown/spell/magic_spell in equipper.actions) + if(!(magic_spell.spell_requirements & SPELL_REQUIRES_NO_ANTIMAGIC)) + continue + + if(!(antimagic_flags & magic_spell.antimagic_flags)) + continue - if(antimagic_flags & magic_spell.antimagic_flags) - to_chat(equipper, span_warning("[parent] is interfering with your ability to cast magic!")) - casting_restriction_alert = TRUE - break + to_chat(equipper, span_warning("[parent] is interfering with your ability to cast magic!")) + alert_caster_on_equip = FALSE + break -/datum/component/anti_magic/proc/on_drop(datum/source, mob/user) +/datum/component/anti_magic/proc/on_drop(atom/movable/source, mob/user) SIGNAL_HANDLER - UnregisterSignal(user, COMSIG_MOB_RECEIVE_MAGIC) - UnregisterSignal(user, COMSIG_MOB_RESTRICT_MAGIC) - casting_restriction_alert = FALSE + // Reset alert + if(source.loc != user) + alert_caster_on_equip = TRUE + unregister_antimagic_signals(user) -/datum/component/anti_magic/proc/block_receiving_magic(mob/living/carbon/user, casted_magic_flags, charge_cost, list/protection_was_used) +/datum/component/anti_magic/proc/block_receiving_magic(mob/living/carbon/source, casted_magic_flags, charge_cost, list/antimagic_sources) SIGNAL_HANDLER - // if any protection sources exist in our list then we already blocked the magic - if(!istype(user) || protection_was_used.len) - return + // We do not block this type of magic, good day + if(!(casted_magic_flags & antimagic_flags)) + return NONE - // disclaimer - All anti_magic sources will be drained a charge_cost - if(casted_magic_flags & antimagic_flags) - var/mutable_appearance/antimagic_effect - var/antimagic_color - // im a programmer not shakesphere to the future grammar nazis that come after me for this - var/visible_subject = ismob(parent) ? "[user.p_they()]" : "[parent]" - var/self_subject = ismob(parent) ? "you" : "[parent]" - - if(casted_magic_flags & antimagic_flags & MAGIC_RESISTANCE) - user.visible_message( - span_warning("[user] pulses red as [visible_subject] absorbs magic energy!"), - span_userdanger("An intense magical aura pulses around [self_subject] as it dissipates into the air!"), - ) - antimagic_effect = mutable_appearance('icons/effects/effects.dmi', "shield-red", MOB_SHIELD_LAYER) - antimagic_color = LIGHT_COLOR_BLOOD_MAGIC - playsound(user, 'sound/magic/magic_block.ogg', 50, TRUE) - else if(casted_magic_flags & antimagic_flags & MAGIC_RESISTANCE_HOLY) - user.visible_message( - span_warning("[user] starts to glow as [visible_subject] emits a halo of light!"), - span_userdanger("A feeling of warmth washes over [self_subject] as rays of light surround your body and protect you!"), - ) - antimagic_effect = mutable_appearance('icons/effects/genetics.dmi', "servitude", -MUTATIONS_LAYER) - antimagic_color = LIGHT_COLOR_HOLY_MAGIC - playsound(user, 'sound/magic/magic_block_holy.ogg', 50, TRUE) - else if(casted_magic_flags & antimagic_flags & MAGIC_RESISTANCE_MIND) - user.visible_message( - span_warning("[user] forehead shines as [visible_subject] repulses magic from their mind!"), - span_userdanger("A feeling of cold splashes on [self_subject] as your forehead reflects magic usering your mind!"), - ) - antimagic_effect = mutable_appearance('icons/effects/genetics.dmi', "telekinesishead", MOB_SHIELD_LAYER) - antimagic_color = LIGHT_COLOR_DARK_BLUE - playsound(user, 'sound/magic/magic_block_mind.ogg', 50, TRUE) - - user.mob_light(range = 2, color = antimagic_color, duration = 5 SECONDS) - user.add_overlay(antimagic_effect) - addtimer(CALLBACK(user, TYPE_PROC_REF(/atom, cut_overlay), antimagic_effect), 50) - - if(ismob(parent)) - return COMPONENT_MAGIC_BLOCKED - - var/has_limited_charges = !(charges == INFINITY) - var/charge_was_drained = charge_cost > 0 - if(has_limited_charges && charge_was_drained) - protection_was_used += parent - drain_antimagic?.Invoke(user, parent) - charges -= charge_cost - if(charges <= 0) - expiration?.Invoke(user, parent) - qdel(src) - return COMPONENT_MAGIC_BLOCKED - return NONE + // We have already blocked this spell + if(parent in antimagic_sources) + return NONE + + // Block success! Add this parent to the list of antimagic sources + antimagic_sources += parent + + if((charges != INFINITY) && charge_cost > 0) + drain_antimagic?.Invoke(source, parent) + charges -= charge_cost + if(charges <= 0) + expiration?.Invoke(source, parent) + qdel(src) // no more antimagic + + return COMPONENT_MAGIC_BLOCKED /// cannot cast magic with the same type of antimagic present /datum/component/anti_magic/proc/restrict_casting_magic(mob/user, magic_flags) diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 534c8d3bb2a6..b9694f1d4754 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -85,7 +85,7 @@ glass_color = new_color if(fulltile) color = glass_color - if(mapload && fulltile) + if(mapload && fulltile && has_sill) new /obj/structure/window_sill(get_turf(src)) //monkestation edit end diff --git a/code/modules/admin/verbs/adminevents.dm b/code/modules/admin/verbs/adminevents.dm index b03d050a88d1..cd66c47468c2 100644 --- a/code/modules/admin/verbs/adminevents.dm +++ b/code/modules/admin/verbs/adminevents.dm @@ -224,6 +224,7 @@ SSshuttle.admin_emergency_no_recall = TRUE SSshuttle.emergency.setTimer(0) SSshuttle.emergency.mode = SHUTTLE_DISABLED + SSshuttle.admin_emergency_disabled = TRUE //monkestation edit priority_announce( text = "Emergency Shuttle uplink failure, shuttle disabled until further notice.", title = "Uplink Failure", @@ -249,6 +250,7 @@ message_admins(span_adminnotice("[key_name_admin(usr)] enabled the emergency shuttle.")) SSshuttle.admin_emergency_no_recall = FALSE SSshuttle.emergency_no_recall = FALSE + SSshuttle.admin_emergency_disabled = FALSE //monkestation edit if(SSshuttle.last_mode == SHUTTLE_DISABLED) //If everything goes to shit, fix it. SSshuttle.last_mode = SHUTTLE_IDLE diff --git a/code/modules/antagonists/wizard/wizard.dm b/code/modules/antagonists/wizard/wizard.dm index f3f6c810baa9..7589dae86256 100644 --- a/code/modules/antagonists/wizard/wizard.dm +++ b/code/modules/antagonists/wizard/wizard.dm @@ -281,7 +281,7 @@ GLOBAL_LIST_EMPTY(wizard_spellbook_purchases_by_key) if(APPRENTICE_DESTRUCTION) spells_to_grant = list( /datum/action/cooldown/spell/aoe/magic_missile, - /datum/action/cooldown/spell/pointed/projectile/fireball/bouncy, //monkestation edit: adds the bouncy subtype + /datum/action/cooldown/spell/pointed/projectile/fireball, ) to_chat(owner, span_bold("Your service has not gone unrewarded, however. \ Studying under [master.current.real_name], you have learned powerful, \ diff --git a/code/modules/clothing/head/tinfoilhat.dm b/code/modules/clothing/head/tinfoilhat.dm index 772219a6d1cd..4b265778e237 100644 --- a/code/modules/clothing/head/tinfoilhat.dm +++ b/code/modules/clothing/head/tinfoilhat.dm @@ -15,16 +15,19 @@ /obj/item/clothing/head/costume/foilhat/Initialize(mapload) . = ..() - if(!warped) - AddComponent(/datum/component/anti_magic, \ - antimagic_flags = MAGIC_RESISTANCE_MIND, \ - inventory_flags = ITEM_SLOT_HEAD, \ - charges = 6, \ - drain_antimagic = CALLBACK(src, PROC_REF(drain_antimagic)), \ - expiration = CALLBACK(src, PROC_REF(warp_up)) \ - ) - else + if(warped) warp_up() + return + + AddComponent( + /datum/component/anti_magic, \ + antimagic_flags = MAGIC_RESISTANCE_MIND, \ + inventory_flags = ITEM_SLOT_HEAD, \ + charges = 6, \ + drain_antimagic = CALLBACK(src, PROC_REF(drain_antimagic)), \ + expiration = CALLBACK(src, PROC_REF(warp_up)) \ + ) + /obj/item/clothing/head/costume/foilhat/equipped(mob/living/carbon/human/user, slot) . = ..() diff --git a/code/modules/mob/living/damage_procs.dm b/code/modules/mob/living/damage_procs.dm index 67821b54b701..ef2ca5635489 100644 --- a/code/modules/mob/living/damage_procs.dm +++ b/code/modules/mob/living/damage_procs.dm @@ -391,12 +391,12 @@ /mob/living/proc/adjustToxLoss(amount, updating_health = TRUE, forced = FALSE, required_biotype = ALL) var/area/target_area = get_area(src) - if(target_area) + if(target_area && !forced) //monkestation edit if((target_area.area_flags & PASSIVE_AREA) && amount > 0) return FALSE if(!can_adjust_tox_loss(amount, forced, required_biotype)) return FALSE - if(amount < 0 && HAS_TRAIT(src, TRAIT_NO_HEALS)) + if(!forced && amount < 0 && HAS_TRAIT(src, TRAIT_NO_HEALS)) //monkestation edit return FALSE if(!forced && (status_flags & GODMODE)) return FALSE @@ -551,4 +551,3 @@ amount -= amount_to_heal //remove what we healed from our current amount if(!amount) break - . -= amount //if there's leftover healing, remove it from what we return diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 7c7b24e72984..18f273ed03d3 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -990,16 +990,65 @@ if(casted_magic_flags == NONE) // magic with the NONE flag is immune to blocking return FALSE - var/list/protection_was_used = list() // this is a janky way of interrupting signals using lists - var/is_magic_blocked = SEND_SIGNAL(src, COMSIG_MOB_RECEIVE_MAGIC, casted_magic_flags, charge_cost, protection_was_used) & COMPONENT_MAGIC_BLOCKED + // A list of all things which are providing anti-magic to us + var/list/antimagic_sources = list() + var/is_magic_blocked = FALSE - if(casted_magic_flags && HAS_TRAIT(src, TRAIT_ANTIMAGIC)) + if(SEND_SIGNAL(src, COMSIG_MOB_RECEIVE_MAGIC, casted_magic_flags, charge_cost, antimagic_sources) & COMPONENT_MAGIC_BLOCKED) + is_magic_blocked = TRUE + if(HAS_TRAIT(src, TRAIT_ANTIMAGIC)) is_magic_blocked = TRUE if((casted_magic_flags & MAGIC_RESISTANCE_HOLY) && HAS_TRAIT(src, TRAIT_HOLY)) is_magic_blocked = TRUE + if(is_magic_blocked && charge_cost > 0 && !HAS_TRAIT(src, TRAIT_RECENTLY_BLOCKED_MAGIC)) + on_block_magic_effects(casted_magic_flags, antimagic_sources) + return is_magic_blocked +/// Called whenever a magic effect with a charge cost is blocked and we haven't recently blocked magic. +/mob/proc/on_block_magic_effects(magic_flags, list/antimagic_sources) + return + +/mob/living/on_block_magic_effects(magic_flags, list/antimagic_sources) + ADD_TRAIT(src, TRAIT_RECENTLY_BLOCKED_MAGIC, MAGIC_TRAIT) + addtimer(TRAIT_CALLBACK_REMOVE(src, TRAIT_RECENTLY_BLOCKED_MAGIC, MAGIC_TRAIT), 6 SECONDS) + + var/mutable_appearance/antimagic_effect + var/antimagic_color + var/atom/antimagic_source = length(antimagic_sources) ? pick(antimagic_sources) : src + + if(magic_flags & MAGIC_RESISTANCE) + visible_message( + span_warning("[src] pulses red as [ismob(antimagic_source) ? p_they() : antimagic_source] absorbs magic energy!"), + span_userdanger("An intense magical aura pulses around [ismob(antimagic_source) ? "you" : antimagic_source] as it dissipates into the air!"), + ) + antimagic_effect = mutable_appearance('icons/effects/effects.dmi', "shield-red", MOB_SHIELD_LAYER) + antimagic_color = LIGHT_COLOR_BLOOD_MAGIC + playsound(src, 'sound/magic/magic_block.ogg', 50, TRUE) + + else if(magic_flags & MAGIC_RESISTANCE_HOLY) + visible_message( + span_warning("[src] starts to glow as [ismob(antimagic_source) ? p_they() : antimagic_source] emits a halo of light!"), + span_userdanger("A feeling of warmth washes over [ismob(antimagic_source) ? "you" : antimagic_source] as rays of light surround your body and protect you!"), + ) + antimagic_effect = mutable_appearance('icons/effects/genetics.dmi', "servitude", -MUTATIONS_LAYER) //monkestation edit: removes the icons/mobs/ icon pathing + antimagic_color = LIGHT_COLOR_HOLY_MAGIC + playsound(src, 'sound/magic/magic_block_holy.ogg', 50, TRUE) + + else if(magic_flags & MAGIC_RESISTANCE_MIND) + visible_message( + span_warning("[src] forehead shines as [ismob(antimagic_source) ? p_they() : antimagic_source] repulses magic from their mind!"), + span_userdanger("A feeling of cold splashes on [ismob(antimagic_source) ? "you" : antimagic_source] as your forehead reflects magic usering your mind!"), + ) + antimagic_effect = mutable_appearance('icons/effects/genetics.dmi', "telekinesishead", MOB_SHIELD_LAYER) //monkestation edit: removes the icons/mobs/ icon pathing + antimagic_color = LIGHT_COLOR_DARK_BLUE + playsound(src, 'sound/magic/magic_block_mind.ogg', 50, TRUE) + + mob_light(range = 2, color = antimagic_color, duration = 5 SECONDS) + add_overlay(antimagic_effect) + addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, cut_overlay), antimagic_effect), 5 SECONDS) + /** * Buckle a living mob to this mob. Also turns you to face the other mob * diff --git a/code/modules/power/apc/apc_main.dm b/code/modules/power/apc/apc_main.dm index de83bf31fe9d..f3e50b6978d6 100644 --- a/code/modules/power/apc/apc_main.dm +++ b/code/modules/power/apc/apc_main.dm @@ -610,9 +610,9 @@ chargecount = 0 // MONKESTATION ADDITION START - CLOCK CULT - if(integration_cog && GLOB.clock_power < GLOB.max_clock_power) + if(integration_cog && SSthe_ark.clock_power < SSthe_ark.max_clock_power) var/power_delta = clamp(cell.charge - 10, 0, 10) - GLOB.clock_power = min(round(GLOB.clock_power + (power_delta)), GLOB.max_clock_power) + SSthe_ark.clock_power = min(round(SSthe_ark.clock_power + (power_delta)), SSthe_ark.max_clock_power) cell.charge -= power_delta // MONKESTATION ADDITION END diff --git a/code/modules/spells/spell.dm b/code/modules/spells/spell.dm index 7b05e2f6b56f..0e1a61e43171 100644 --- a/code/modules/spells/spell.dm +++ b/code/modules/spells/spell.dm @@ -103,7 +103,7 @@ if(spell_requirements & SPELL_REQUIRES_STATION) RegisterSignal(owner, COMSIG_MOVABLE_Z_CHANGED, PROC_REF(update_status_on_signal)) if(spell_requirements & (SPELL_REQUIRES_NO_ANTIMAGIC|SPELL_REQUIRES_WIZARD_GARB)) - RegisterSignal(owner, COMSIG_MOB_EQUIPPED_ITEM, PROC_REF(update_status_on_signal)) + RegisterSignals(owner, list(COMSIG_MOB_EQUIPPED_ITEM, COMSIG_MOB_UNEQUIPPED_ITEM), PROC_REF(update_status_on_signal)) if(invocation_type == INVOCATION_EMOTE) RegisterSignals(owner, list(SIGNAL_ADDTRAIT(TRAIT_EMOTEMUTE), SIGNAL_REMOVETRAIT(TRAIT_EMOTEMUTE)), PROC_REF(update_status_on_signal)) if(invocation_type == INVOCATION_SHOUT || invocation_type == INVOCATION_WHISPER) @@ -119,6 +119,7 @@ COMSIG_MOB_AFTER_EXIT_JAUNT, COMSIG_MOB_ENTER_JAUNT, COMSIG_MOB_EQUIPPED_ITEM, + COMSIG_MOB_UNEQUIPPED_ITEM, COMSIG_MOVABLE_Z_CHANGED, SIGNAL_ADDTRAIT(TRAIT_EMOTEMUTE), SIGNAL_REMOVETRAIT(TRAIT_EMOTEMUTE), diff --git a/code/modules/spells/spell_types/self/spacetime_distortion.dm b/code/modules/spells/spell_types/self/spacetime_distortion.dm index 976d83e8a30a..78b69448ff89 100644 --- a/code/modules/spells/spell_types/self/spacetime_distortion.dm +++ b/code/modules/spells/spell_types/self/spacetime_distortion.dm @@ -47,8 +47,8 @@ for(var/turf/swap_a as anything in to_switcharoo) var/turf/swap_b = to_switcharoo[swap_a] - var/obj/effect/cross_action/spacetime_dist/effect_a = new /obj/effect/cross_action/spacetime_dist(swap_a, antimagic_flags) - var/obj/effect/cross_action/spacetime_dist/effect_b = new /obj/effect/cross_action/spacetime_dist(swap_b, antimagic_flags) + var/obj/effect/cross_action/spacetime_dist/effect_a = new spawned_effect_type(swap_a, antimagic_flags) //monkestation edit: replaces the typing with spawned_effect_type + var/obj/effect/cross_action/spacetime_dist/effect_b = new spawned_effect_type(swap_b, antimagic_flags) //monkestation edit: same as above effect_a.linked_dist = effect_b effect_a.add_overlay(swap_b.photograph()) effect_b.linked_dist = effect_a diff --git a/code/modules/tooltip/tooltip.html b/code/modules/tooltip/tooltip.html index cb7923322539..f67653ee11e4 100644 --- a/code/modules/tooltip/tooltip.html +++ b/code/modules/tooltip/tooltip.html @@ -54,6 +54,9 @@ .cult .wrap {border-color: #292222;} .cult .content {color: #FF0000; border-color: #4C4343; background-color: #3C3434;} + .clockwork .wrap {border-color: #170800;} /* monkestation edit */ + .clockwork .content {color: #B18B25; border-color: #000000; background-color: #5F380E;} + .pod .wrap {border-color: #052401;} .pod .content {border-color: #326D29; background-color: #569F4B;} diff --git a/monkestation/code/_onclick/hud/alert.dm b/monkestation/code/_onclick/hud/alert.dm index 95c3a84b0908..942bb24a0919 100644 --- a/monkestation/code/_onclick/hud/alert.dm +++ b/monkestation/code/_onclick/hud/alert.dm @@ -4,11 +4,17 @@ desc = "Shows infomation about the Ark of the Clockwork Justicar" icon = 'monkestation/icons/hud/screen_alert.dmi' icon_state = "clockinfo" -// alerttooltipstyle = "clockwork" //clockwork tooltips are currently broken, this is a known issue on TG + alerttooltipstyle = "clockwork" + ///The static info we use so we only have to actually update our data once each tick + var/static/static_desc /atom/movable/screen/alert/clockwork/clocksense/Initialize(mapload) . = ..() - START_PROCESSING(SSprocessing, src) + if(!static_desc) + static_desc = get_static_desc() + desc = static_desc + if(!GLOB.ratvar_risen) + START_PROCESSING(SSprocessing, src) /atom/movable/screen/alert/clockwork/clocksense/Destroy() STOP_PROCESSING(SSprocessing, src) @@ -17,24 +23,39 @@ /atom/movable/screen/alert/clockwork/clocksense/process() if(GLOB.ratvar_risen) desc = "RAT'VAR HAS RISEN." + return PROCESS_KILL + + var/static/last_process_tick + if(!last_process_tick || world.time - last_process_tick > 1 SECOND) + static_desc = get_static_desc() + last_process_tick = world.time + desc = static_desc + +/atom/movable/screen/alert/clockwork/clocksense/proc/get_static_desc() + if(GLOB.ratvar_risen) + return "RAT'VAR HAS RISEN." + + var/new_desc = "Stored Power - [display_power(SSthe_ark.clock_power)].
" + new_desc += "Stored Vitality - [GLOB.clock_vitality].
" + if(!GLOB.main_clock_cult) return - desc = "Stored Power - [display_power(GLOB.clock_power)].
" - desc += "Stored Vitality - [GLOB.clock_vitality].
" - desc += "We current have [GLOB.main_clock_cult?.human_servants.len] human servants out of [GLOB.main_clock_cult?.max_human_servants] maximum human servants, \ - as well as [GLOB.main_clock_cult?.members.len] servants all together.
" + + new_desc += "We current have [length(GLOB.main_clock_cult.human_servants)] human servants out of [GLOB.main_clock_cult.max_human_servants] maximum human servants, \ + as well as [length(GLOB.main_clock_cult.members)] servants all together.
" if(GLOB.clock_ark?.charging_for) - desc += "The Ark will open in [600 - GLOB.clock_ark?.charging_for] seconds!
" + new_desc += "The Ark will open in [600 - GLOB.clock_ark.charging_for] seconds!
" return //we dont care about anchoring crystals at this point - if(get_charged_anchor_crystals()) //only put this here if we need to use it - var/datum/objective/anchoring_crystals/crystals_objective = locate() in GLOB.main_clock_cult?.objectives - if(!crystals_objective) - return - - var/list/area_list = list() - for(var/area/added_area in crystals_objective.valid_areas) - area_list += added_area.get_original_area_name() - desc += "Additional Anchoring Crystals can be summoned in [english_list(area_list)].
" - else - desc += "We must summon and protect an Anchoring crystal before the ark may open.
" + var/static/list/cached_valid_areas + if(length(cached_valid_areas) != length(SSthe_ark.valid_crystal_areas)) //using length due to the cache being area names and not areas themselves + cached_valid_areas = list() + for(var/area/added_area in SSthe_ark.valid_crystal_areas) + cached_valid_areas += SSthe_ark.valid_crystal_areas[added_area] + new_desc += "Anchoring Crystals can be summoned in [english_list(cached_valid_areas)].
" + + var/crystal_diff = ANCHORING_CRYSTALS_TO_SUMMON - length(SSthe_ark.anchoring_crystals) + if(crystal_diff > 0) + new_desc += "We must summon [crystal_diff] more Anchoring Crystal[crystal_diff > 1 ? "s" : ""] before the ark may open.
" + return new_desc + diff --git a/monkestation/code/controllers/subsystem/shuttle.dm b/monkestation/code/controllers/subsystem/shuttle.dm new file mode 100644 index 000000000000..f5681fd43949 --- /dev/null +++ b/monkestation/code/controllers/subsystem/shuttle.dm @@ -0,0 +1,3 @@ +/datum/controller/subsystem/shuttle + ///Are we disabled due to admins + var/admin_emergency_disabled = FALSE diff --git a/monkestation/code/datums/components/enchantments/_enchanted.dm b/monkestation/code/datums/components/enchantments/_enchanted.dm new file mode 100644 index 000000000000..a29163355fe7 --- /dev/null +++ b/monkestation/code/datums/components/enchantments/_enchanted.dm @@ -0,0 +1,129 @@ +GLOBAL_LIST_EMPTY(enchantment_datums_by_type) + +/datum/component/enchanted + dupe_mode = COMPONENT_DUPE_ALLOWED + ///Current enchantment level + var/level + ///The span we warp our examine text in + var/used_span + ///A ref to the enchantment datum we are using + var/datum/enchantment/used_enchantment + ///A list of all enchantments + var/static/list/all_enchantments = list() + +/datum/component/enchanted/Initialize(list/select_enchants_from = subtypesof(/datum/enchantment), used_span = "", level_override) + if(!isitem(parent)) + return COMPONENT_INCOMPATIBLE + + if(!length(select_enchants_from)) + stack_trace("[src.type] calling Initialize with unset select_enchants_from.") + return COMPONENT_INCOMPATIBLE + + if(!length(all_enchantments)) + generate_enchantment_datums() + + for(var/entry in select_enchants_from) + if(ispath(entry)) + select_enchants_from -= entry + select_enchants_from += GLOB.enchantment_datums_by_type[entry] + + used_enchantment = pick(select_enchants_from) + src.used_span = used_span + level = level_override || rand(1, used_enchantment.max_level) + +/datum/component/enchanted/RegisterWithParent() + var/list/component_list = used_enchantment.components_by_parent[parent] + if(!component_list) + used_enchantment.components_by_parent[parent] = list(text_ref(used_enchantment) = src) //used_enchantment is not being taken as a ref? + else + component_list[used_enchantment] = src + used_enchantment.apply_effect(parent, level) + RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) + +/datum/component/enchanted/UnregisterFromParent() + UnregisterSignal(parent, COMSIG_ATOM_EXAMINE) + var/list/component_list = used_enchantment.components_by_parent[parent] + component_list -= used_enchantment + if(!length(component_list)) + used_enchantment.components_by_parent -= parent + +/datum/component/enchanted/Destroy(force) + used_enchantment = null + return ..() + +/datum/component/enchanted/proc/on_examine(datum/source, mob/user, list/examine_list) + SIGNAL_HANDLER + + if(!used_enchantment.examine_description) + return + + if(isobserver(user) || HAS_MIND_TRAIT(user, TRAIT_MAGICALLY_GIFTED)) + if(used_span) + examine_list += "[used_span][used_enchantment.examine_description]" + examine_list += "[used_span]It's blessing has a power of [level]!
" + return + examine_list += "[used_enchantment.examine_description]" + examine_list += "It's blessing has a power of [level]!
" + else + examine_list += "It is glowing slightly!" + var/mob/living/living_user = user + if(istype(living_user.get_item_by_slot(ITEM_SLOT_EYES), /obj/item/clothing/glasses/science)) + examine_list += "It emits a readable EMF factor of [level]." + +/datum/enchantment + ///Examine text + var/examine_description + ///Maximum enchantment level + var/max_level = 1 + ///Typecache of items we are allowed on, generation handled in get_allowed_on + var/list/allowed_on + ///A recursive assoc list keyed as: [parent] = list(text_ref(enchant_component.used_enchantment) = enchant_component) + var/static/list/list/datum/component/enchanted/components_by_parent = list() + +/datum/enchantment/New() + . = ..() + allowed_on = get_allowed_on() + +/** + * Because of dumb BYOND reasons in order to get fine manual control we need to handle generation of allowed_on this way(via setting the default passed values) + * + * allowed_on_base - Typecache of items we are allowed on + * + * denied_from - Anything in this list will be set to FALSE in allowed_on + * + * overriden_types - Any values in this list will override allowed_on, this is handled last + */ +/datum/enchantment/proc/get_allowed_on(list/allowed_on_base = typecacheof(/obj/item), list/denied_from = typesof(/obj/item/clothing), list/overriden_types = list()) //AHHHHH + if(denied_from) + for(var/denied_entry in denied_from) + allowed_on_base[denied_entry] = 0 + if(overriden_types) + for(var/entry in overriden_types) + allowed_on_base[entry] = overriden_types[entry] + return allowed_on_base + +/datum/enchantment/proc/get_component_from_parent(obj/item/parent) as /datum/component/enchanted + RETURN_TYPE(/datum/component/enchanted) + var/list/parent_list = components_by_parent[parent] + if(!parent_list) + return FALSE + return parent_list[text_ref(src)] + +/datum/enchantment/proc/can_apply_to(obj/item/checked) + return allowed_on[checked.type] && examine_description + +/datum/enchantment/proc/apply_effect(obj/item/target, level) + register_item(target) + +///Handle comsig reg here +/datum/enchantment/proc/register_item(obj/item/target) + return + +///Handle comsig unreg here +/datum/enchantment/proc/unregister_item(obj/item/target) + return + +/datum/enchantment/clothing + +/datum/enchantment/clothing/get_allowed_on(list/allowed_on_base = typecacheof(/obj/item/clothing), list/denied_from = list(), list/overriden_types) + return ..() diff --git a/monkestation/code/datums/components/enchantments/_helpers.dm b/monkestation/code/datums/components/enchantments/_helpers.dm new file mode 100644 index 000000000000..230a1ca9be1c --- /dev/null +++ b/monkestation/code/datums/components/enchantments/_helpers.dm @@ -0,0 +1,23 @@ +/proc/attempt_enchantment(obj/item/enchanted, list/valid_enchant_types = subtypesof(/datum/enchantment), description_span = "", level_override) + if(!isitem(enchanted)) + return FALSE + + if(!length(GLOB.enchantment_datums_by_type)) + generate_enchantment_datums() + + if(!islist(valid_enchant_types)) + valid_enchant_types = list(valid_enchant_types) + + for(var/datum/enchantment/enchant as anything in valid_enchant_types) + valid_enchant_types -= enchant + enchant = GLOB.enchantment_datums_by_type[enchant] + if(enchant.can_apply_to(enchanted)) + valid_enchant_types += enchant + + if(!length(valid_enchant_types)) + return FALSE + return enchanted.AddComponent(/datum/component/enchanted, valid_enchant_types, description_span, level_override) + +/proc/generate_enchantment_datums() + for(var/datum/enchantment/enchant as anything in subtypesof(/datum/enchantment)) + GLOB.enchantment_datums_by_type[enchant] = new enchant() diff --git a/monkestation/code/modules/antagonists/clock_cult/enchantments/antimagic.dm b/monkestation/code/datums/components/enchantments/antimagic.dm similarity index 65% rename from monkestation/code/modules/antagonists/clock_cult/enchantments/antimagic.dm rename to monkestation/code/datums/components/enchantments/antimagic.dm index 49622a1194b2..86b95b69ef64 100644 --- a/monkestation/code/modules/antagonists/clock_cult/enchantments/antimagic.dm +++ b/monkestation/code/datums/components/enchantments/antimagic.dm @@ -1,6 +1,6 @@ -/datum/component/enchantment/anti_magic +/datum/enchantment/anti_magic examine_description = "It has been blessed with the gift of magic protection, preventing all magic from affecting the wielder." max_level = 1 -/datum/component/enchantment/anti_magic/apply_effect(obj/item/target) +/datum/enchantment/anti_magic/apply_effect(obj/item/target) target.AddComponent(/datum/component/anti_magic, TRUE, TRUE) diff --git a/monkestation/code/datums/components/enchantments/blinding.dm b/monkestation/code/datums/components/enchantments/blinding.dm new file mode 100644 index 000000000000..492f3701072b --- /dev/null +++ b/monkestation/code/datums/components/enchantments/blinding.dm @@ -0,0 +1,15 @@ +/datum/enchantment/blinding + examine_description = "It has been blessed with the power to emit a blinding light when striking a target." + max_level = 1 + +/datum/enchantment/blinding/register_item(obj/item/target) + RegisterSignal(target, COMSIG_ITEM_ATTACK, PROC_REF(flash_target)) + +/datum/enchantment/blinding/unregister_item(obj/item/target) + UnregisterSignal(target, COMSIG_ITEM_ATTACK) + +/datum/enchantment/blinding/proc/flash_target(obj/item/source, mob/living/target, mob/living/user) + if(!istype(target)) + return + source.visible_message(span_danger("\The [source] emits a blinding light!")) + target.flash_act(2, affect_silicon = TRUE, length = 3 SECONDS) //might want to make this not effect borgs diff --git a/monkestation/code/modules/antagonists/clock_cult/enchantments/blocking.dm b/monkestation/code/datums/components/enchantments/blocking.dm similarity index 64% rename from monkestation/code/modules/antagonists/clock_cult/enchantments/blocking.dm rename to monkestation/code/datums/components/enchantments/blocking.dm index 25c408d5dabf..242b9536c41b 100644 --- a/monkestation/code/modules/antagonists/clock_cult/enchantments/blocking.dm +++ b/monkestation/code/datums/components/enchantments/blocking.dm @@ -1,7 +1,7 @@ //might have to change this due to us having TG instead of bee blocking -/datum/component/enchantment/blocking +/datum/enchantment/blocking examine_description = "It has been blessed with the gift of blocking." max_level = 3 -/datum/component/enchantment/blocking/apply_effect(obj/item/target) +/datum/enchantment/blocking/apply_effect(obj/item/target, level) target.block_chance += 5 * level diff --git a/monkestation/code/datums/components/enchantments/burn.dm b/monkestation/code/datums/components/enchantments/burn.dm new file mode 100644 index 000000000000..2b3a1ede0b97 --- /dev/null +++ b/monkestation/code/datums/components/enchantments/burn.dm @@ -0,0 +1,25 @@ +/datum/enchantment/burn + examine_description = "It has been blessed with the power of fire and will set struck targets on fire." + max_level = 3 + +/datum/enchantment/burn/apply_effect(obj/item/target, level) + . = ..() + target.damtype = BURN + +/datum/enchantment/burn/register_item(obj/item/target) + RegisterSignal(target, COMSIG_ITEM_ATTACK, PROC_REF(burn_target)) + +/datum/enchantment/burn/unregister_item(obj/item/target) + UnregisterSignal(target, COMSIG_ITEM_ATTACK) + return ..() + +/datum/enchantment/burn/proc/burn_target(obj/item/source, atom/movable/target, mob/living/user) + if(!isliving(target)) + return + var/datum/component/enchanted/comp = get_component_from_parent(source) + if(!comp) + return + + var/mob/living/living_target = target + living_target.adjust_fire_stacks(comp.level) + living_target.ignite_mob() diff --git a/monkestation/code/datums/components/enchantments/electricution.dm b/monkestation/code/datums/components/enchantments/electricution.dm new file mode 100644 index 000000000000..6e959d4d96f7 --- /dev/null +++ b/monkestation/code/datums/components/enchantments/electricution.dm @@ -0,0 +1,21 @@ +/datum/enchantment/electricution + max_level = 3 + examine_description = "It has been blessed with the power of electricity and will shock targets." + +/datum/enchantment/electricution/register_item(obj/item/target) + RegisterSignal(target, COMSIG_ITEM_ATTACK, PROC_REF(shock_target)) + +/datum/enchantment/electricution/unregister_item(obj/item/target) + UnregisterSignal(target, COMSIG_ITEM_ATTACK) + +/datum/enchantment/electricution/proc/shock_target(obj/item/source, atom/movable/target, mob/living/user) + user.Beam(target, icon_state = "lightning[rand(1,12)]", time = 2, maxdistance = 32) + if(!iscarbon(target)) + return + var/datum/component/enchanted/comp = get_component_from_parent(source) + if(!comp) + return + + var/mob/living/carbon/carbon_target = target + if(carbon_target.electrocute_act(comp.level * 3, user, 1, SHOCK_NOSTUN)) //need to make this ark, also this seems to work on any living mob + carbon_target.visible_message(span_danger("[user] electrocutes [target]!"), span_userdanger("[user] electrocutes you!")) diff --git a/monkestation/code/datums/components/enchantments/hardened.dm b/monkestation/code/datums/components/enchantments/hardened.dm new file mode 100644 index 000000000000..8b137891791f --- /dev/null +++ b/monkestation/code/datums/components/enchantments/hardened.dm @@ -0,0 +1 @@ + diff --git a/monkestation/code/modules/antagonists/clock_cult/enchantments/haste.dm b/monkestation/code/datums/components/enchantments/haste.dm similarity index 66% rename from monkestation/code/modules/antagonists/clock_cult/enchantments/haste.dm rename to monkestation/code/datums/components/enchantments/haste.dm index d6e36aeaa653..3e747765cade 100644 --- a/monkestation/code/modules/antagonists/clock_cult/enchantments/haste.dm +++ b/monkestation/code/datums/components/enchantments/haste.dm @@ -1,6 +1,6 @@ -/datum/component/enchantment/haste +/datum/enchantment/haste examine_description = "It has been blessed with the ability to warp time around it so that it's user may attack faster with it." max_level = 1 -/datum/component/enchantment/haste/apply_effect(obj/item/target) +/datum/enchantment/haste/apply_effect(obj/item/target) target.attack_speed = max(1, target.attack_speed - 2) diff --git a/monkestation/code/modules/antagonists/clock_cult/enchantments/penetration.dm b/monkestation/code/datums/components/enchantments/penetration.dm similarity index 65% rename from monkestation/code/modules/antagonists/clock_cult/enchantments/penetration.dm rename to monkestation/code/datums/components/enchantments/penetration.dm index 2ed66718131d..a1c26158850b 100644 --- a/monkestation/code/modules/antagonists/clock_cult/enchantments/penetration.dm +++ b/monkestation/code/datums/components/enchantments/penetration.dm @@ -1,6 +1,6 @@ -/datum/component/enchantment/penetration +/datum/enchantment/penetration examine_description = "It has been blessed with the gift of armor penetration, allowing it to cut through targets with ease." max_level = 5 -/datum/component/enchantment/penetration/apply_effect(obj/item/target) +/datum/enchantment/penetration/apply_effect(obj/item/target, level) target.armour_penetration = max(15 * level, target.armour_penetration) diff --git a/monkestation/code/modules/antagonists/clock_cult/enchantments/sharpness.dm b/monkestation/code/datums/components/enchantments/sharpness.dm similarity index 51% rename from monkestation/code/modules/antagonists/clock_cult/enchantments/sharpness.dm rename to monkestation/code/datums/components/enchantments/sharpness.dm index 8cf8d99064da..4441541462ba 100644 --- a/monkestation/code/modules/antagonists/clock_cult/enchantments/sharpness.dm +++ b/monkestation/code/datums/components/enchantments/sharpness.dm @@ -1,6 +1,6 @@ -/datum/component/enchantment/sharpness +/datum/enchantment/sharpness examine_description = "It has been blessed with the gift of sharpness." max_level = 5 -/datum/component/enchantment/sharpness/apply_effect(obj/item/target) +/datum/enchantment/sharpness/apply_effect(obj/item/target, level) target.force += 2 * level diff --git a/monkestation/code/datums/components/enchantments/soul_tap.dm b/monkestation/code/datums/components/enchantments/soul_tap.dm new file mode 100644 index 000000000000..523cd75303b1 --- /dev/null +++ b/monkestation/code/datums/components/enchantments/soul_tap.dm @@ -0,0 +1,19 @@ +/datum/enchantment/soul_tap + examine_description = "It has been blessed with the power of ripping the energy from target's souls and will heal the wielder when a target is struck." + max_level = 3 + +/datum/enchantment/soul_tap/unregister_item(obj/item/target) + UnregisterSignal(target, COMSIG_ITEM_ATTACK) + +/datum/enchantment/soul_tap/register_item(obj/item/target) + RegisterSignal(target, COMSIG_ITEM_ATTACK, PROC_REF(tap_soul)) + +/datum/enchantment/soul_tap/proc/tap_soul(obj/item/source, mob/living/target, mob/living/user) + if(!istype(target) || target.stat != CONSCIOUS) + return + var/datum/component/enchanted/comp = get_component_from_parent(source) + if(!comp) + return + var/health_back = CEILING(comp.level * source.force * 0.1, 1) + user.heal_overall_damage(health_back, health_back) + new /obj/effect/temp_visual/heal(get_turf(user), "#eeba6b") diff --git a/monkestation/code/datums/components/enchantments/tiny.dm b/monkestation/code/datums/components/enchantments/tiny.dm new file mode 100644 index 000000000000..f0bcbfdff144 --- /dev/null +++ b/monkestation/code/datums/components/enchantments/tiny.dm @@ -0,0 +1,9 @@ +/datum/enchantment/tiny + examine_description = "It has been blessed and distorts reality into a tiny space around it." + max_level = 1 + +/datum/enchantment/tiny/get_allowed_on(list/allowed_on_base, list/denied_from = list(), list/overriden_types) + . = ..() + +/datum/enchantment/tiny/apply_effect(obj/item/target) + target.w_class = WEIGHT_CLASS_TINY diff --git a/monkestation/code/datums/components/multi_area_bound.dm b/monkestation/code/datums/components/multi_area_bound.dm new file mode 100644 index 000000000000..1eb6fb3bc2b3 --- /dev/null +++ b/monkestation/code/datums/components/multi_area_bound.dm @@ -0,0 +1,56 @@ +/// Movables with this component will automatically return to their original turf if moved outside a valid area +/datum/component/multi_area_bound + ///List of valid area instances/types, formatted as a typecache + var/list/valid_areas + ///Do we use instances instead of types + var/use_instances + ///Do we do a key value search instead of an (x in list) seach + var/check_as_typecache + ///The turf we send our parent back to if they move out of allowed areas + var/turf/reset_turf + ///Our area tracker datum + var/datum/movement_detector/move_tracker + var/moving = FALSE //Used to prevent infinite recursion if your reset turf places you somewhere on enter or something + +/datum/component/multi_area_bound/Initialize(_valid_areas = list(), _use_instances = FALSE, _check_as_typecache = TRUE) + if(!ismovable(parent)) + return COMPONENT_INCOMPATIBLE + + if(!length(_valid_areas)) //I guess if you have something that you want to behave this way then you can add a flag to ignore this check + stack_trace("[src.type] initializing with an empty valid_areas.") + return COMPONENT_INCOMPATIBLE + + valid_areas = _valid_areas + use_instances = _use_instances + check_as_typecache = _check_as_typecache + reset_turf = get_turf(parent) + move_tracker = new(parent, CALLBACK(src, PROC_REF(check_bounds))) + check_bounds() + +/datum/component/multi_area_bound/Destroy(force) + QDEL_NULL(move_tracker) + valid_areas = null + return ..() + +/datum/component/multi_area_bound/proc/check_bounds(atom/movable/source, atom/movable/mover, atom/oldloc, direction) + SIGNAL_HANDLER //not technically a sig handler but it pretty much is + var/area/current = get_area(source) + if(!current) + return + + if(!(check_as_typecache ? valid_areas[use_instances ? current : current.type] : ((use_instances ? current : current.type) in valid_areas))) //fun + if(moving) + stack_trace("Moved during a reset move, giving up to prevent infinite recursion. \ + [reset_turf ? "Turf: [reset_turf.type] at [reset_turf.x], [reset_turf.y], [reset_turf.z]" : "No reset_turf"]") + return + if(!reset_turf) //if unset then just move them to their last turf + moving = TRUE + source.forceMove(oldloc) + moving = FALSE + stack_trace("multi_area_bound without set reset_turf") //qdel(src) + return + + moving = TRUE + source.forceMove(reset_turf) + moving = FALSE + reset_turf = get_turf(source) diff --git a/monkestation/code/datums/components/turf_healing.dm b/monkestation/code/datums/components/turf_healing.dm index 2acaacb2de74..5daf540a75ac 100644 --- a/monkestation/code/datums/components/turf_healing.dm +++ b/monkestation/code/datums/components/turf_healing.dm @@ -21,7 +21,7 @@ /datum/component/turf_healing/UnregisterFromParent() UnregisterSignal(parent, COMSIG_LIVING_LIFE) -/datum/component/turf_healing/proc/handle_healing(seconds_per_tick) +/datum/component/turf_healing/proc/handle_healing(mob/living/owner, seconds_per_tick) SIGNAL_HANDLER var/mob/living/healed_mob = parent diff --git a/monkestation/code/datums/status_effects/buffs.dm b/monkestation/code/datums/status_effects/buffs.dm index e5da8e526408..93ae4d544ac9 100644 --- a/monkestation/code/datums/status_effects/buffs.dm +++ b/monkestation/code/datums/status_effects/buffs.dm @@ -10,8 +10,8 @@ multiplicative_slowdown = -0.6 /atom/movable/screen/alert/status_effect/mayhem - name = "Mayhem" - desc = "RIP AND TEAR!!" + name = span_cult("Mayhem") + desc = span_bolddanger("RIP AND TEAR!!") icon = 'icons/obj/weapons/chainsaw.dmi' icon_state = "chainsaw_on" alerttooltipstyle = "cult" diff --git a/monkestation/code/datums/status_effects/debuffs/clock_warp_sickness.dm b/monkestation/code/datums/status_effects/debuffs/clock_warp_sickness.dm new file mode 100644 index 000000000000..addc9bfc340f --- /dev/null +++ b/monkestation/code/datums/status_effects/debuffs/clock_warp_sickness.dm @@ -0,0 +1,39 @@ +/datum/status_effect/clock_warp_sickness + id = "clock_warp_sickness" + alert_type = /atom/movable/screen/alert/status_effect/clock_warp_sickness + +/datum/status_effect/clock_warp_sickness/on_creation(mob/living/new_owner, _duration = 1 SECOND) + duration = _duration + return ..() + +/datum/status_effect/clock_warp_sickness/on_apply() + . = ..() + owner.add_actionspeed_modifier(/datum/actionspeed_modifier/clock_warp_sickness) + owner.add_movespeed_modifier(/datum/movespeed_modifier/clock_warp_sickness) + owner.adjust_confusion(duration) + owner.adjust_dizzy(duration) + owner.add_client_colour(/datum/client_colour/clock_warp) + +/datum/status_effect/clock_warp_sickness/on_remove() + . = ..() + owner.remove_actionspeed_modifier(/datum/actionspeed_modifier/clock_warp_sickness) + owner.remove_movespeed_modifier(/datum/movespeed_modifier/clock_warp_sickness) + owner.remove_client_colour(/datum/client_colour/clock_warp) + +/atom/movable/screen/alert/status_effect/clock_warp_sickness + name = "Warp Sickness" + desc = "You are disoriented from recently teleporting." + icon = 'monkestation/icons/mob/clock_cult/actions_clock.dmi' + icon_state = "warp_down" + alerttooltipstyle = "clockwork" + +/datum/movespeed_modifier/clock_warp_sickness + multiplicative_slowdown = 1 + +/datum/actionspeed_modifier/clock_warp_sickness + multiplicative_slowdown = 0.6 + +/datum/client_colour/clock_warp + colour = LIGHT_COLOR_CLOCKWORK + priority = 2 + fade_out = 5 diff --git a/monkestation/code/game/machinery/cloning.dm b/monkestation/code/game/machinery/cloning.dm index d392623d835b..abcd27599025 100644 --- a/monkestation/code/game/machinery/cloning.dm +++ b/monkestation/code/game/machinery/cloning.dm @@ -361,7 +361,7 @@ /obj/machinery/clonepod/emag_act(mob/user) if(!occupant) return - to_chat(user, "You corrupt the genetic compiler.") + to_chat(user, span_warning("You corrupt the genetic compiler.")) malfunction() add_fingerprint(user) log_cloning("[key_name(user)] emagged [src] at [AREACOORD(src)], causing it to malfunction.") diff --git a/monkestation/code/game/objects/items/turf_demolisher.dm b/monkestation/code/game/objects/items/turf_demolisher.dm index f4f0a9d3eb07..0c6d241757c9 100644 --- a/monkestation/code/game/objects/items/turf_demolisher.dm +++ b/monkestation/code/game/objects/items/turf_demolisher.dm @@ -19,6 +19,10 @@ var/devastate = TRUE ///How long is our recharge time between uses var/recharge_time = 0 + ///How long after our first turf broken do our resonances detonate + var/resonance_delay = 5 SECONDS + ///How many tiles out from out demolished turf do we spawn resonances, set to 0 for no resonances + var/resonance_range = 0 COOLDOWN_DECLARE(recharge) /obj/item/turf_demolisher/afterattack(atom/target, mob/user, proximity_flag, click_parameters) @@ -26,19 +30,20 @@ if(!proximity_flag || !isturf(target) || (user.istate & ISTATE_HARM)) return - if(!check_breakble(target, user, click_parameters)) + if(!check_breakble(target, user)) return if(try_demolish(target, user)) return -/obj/item/turf_demolisher/proc/check_breakble(turf/attacked_turf, mob/living/user, params) - if(recharge_time && !COOLDOWN_FINISHED(src, recharge)) - balloon_alert(user, "\The [src] is still recharging.") +/obj/item/turf_demolisher/proc/check_breakble(turf/attacked_turf, mob/living/user, silent = FALSE, ignore_cooldown = FALSE) + if(recharge_time && !ignore_cooldown && !COOLDOWN_FINISHED(src, recharge)) + if(!silent) + balloon_alert(user, "\The [src] is still recharging.") return FALSE if((allowed_types && !is_type_in_list(attacked_turf, allowed_types)) || is_type_in_list(attacked_turf, blacklisted_types) || (attacked_turf.resistance_flags & INDESTRUCTIBLE)) - if(unbreakable_alert) + if(unbreakable_alert && !silent) balloon_alert(user, unbreakable_alert) return FALSE return TRUE @@ -56,14 +61,76 @@ if(recharge_time) COOLDOWN_START(src, recharge, recharge_time) + if(!resonance_range) + return TRUE + + var/tiles_out = 0 + var/list/checked_turfs = list(attacked_turf) + var/list/resonate_from = list(attacked_turf) + while(tiles_out < resonance_range) + tiles_out++ + for(var/turf/resonated_from in resonate_from) + resonate_from -= resonated_from + var/list/step_turfs = list(get_step(resonated_from, NORTH), get_step(resonated_from, SOUTH), get_step(resonated_from, EAST), get_step(resonated_from, WEST)) + for(var/turf/checked_turf in step_turfs) + if(!(checked_turf in checked_turfs) && check_breakble(checked_turf, silent = TRUE, ignore_cooldown = TRUE)) + if(tiles_out < resonance_range) + resonate_from += checked_turf + new /obj/effect/temp_visual/turf_demolisher_resonance(checked_turf, resonance_delay, checked_turf) + checked_turfs += checked_turf return TRUE +/obj/effect/temp_visual/turf_demolisher_resonance + name = "resonance field" + desc = "A resonating field that will destroy any nearby surface." + icon_state = "shield2" + layer = ABOVE_ALL_MOB_LAYER + plane = ABOVE_GAME_PLANE + duration = 5 SECONDS + ///The turf that we are on + var/turf/holder_turf + +/obj/effect/temp_visual/turf_demolisher_resonance/Initialize(mapload, _duration = 5 SECONDS, holder) + duration = _duration + holder_turf = holder || get_turf(src) + . = ..() + if(!holder_turf) + return INITIALIZE_HINT_QDEL + + transform = matrix()*0.75 + animate(src, transform = matrix()*1.5, time = duration) + RegisterSignal(holder_turf, COMSIG_ATOM_DESTRUCTION, PROC_REF(on_holder_destruction)) + +/obj/effect/temp_visual/turf_demolisher_resonance/Destroy() + if(holder_turf) + UnregisterSignal(holder_turf, COMSIG_ATOM_DESTRUCTION) + collapse() + holder_turf = null + return ..() + +/obj/effect/temp_visual/turf_demolisher_resonance/proc/on_holder_destruction() + SIGNAL_HANDLER + UnregisterSignal(holder_turf, COMSIG_ATOM_DESTRUCTION) + holder_turf = null + qdel(src) + +/obj/effect/temp_visual/turf_demolisher_resonance/proc/collapse() + new /obj/effect/temp_visual/resonance_crush(holder_turf) + playsound(holder_turf, 'sound/weapons/resonator_blast.ogg', 50, TRUE) + if(iswallturf(holder_turf)) + var/turf/closed/wall/wall_turf = holder_turf + wall_turf.dismantle_wall() + else + holder_turf.ScrapeAway() + /obj/item/turf_demolisher/reebe desc = "An exprimental able to quickly deconstruct any surface. This one seems to be calibrated to only work on reebe." break_time = 5 SECONDS recharge_time = 5 SECONDS + resonance_delay = 5 SECONDS + resonance_range = 2 -/obj/item/turf_demolisher/reebe/check_breakble(turf/attacked_turf, mob/living/user, params) +/obj/item/turf_demolisher/reebe/check_breakble(turf/attacked_turf, mob/living/user, silent, ignore_cooldown) . = ..() if(!.) return diff --git a/monkestation/code/modules/aesthetics/objects/windows.dm b/monkestation/code/modules/aesthetics/objects/windows.dm index 8f4a8148e424..4598d4b9aa31 100644 --- a/monkestation/code/modules/aesthetics/objects/windows.dm +++ b/monkestation/code/modules/aesthetics/objects/windows.dm @@ -2,7 +2,10 @@ var/glass_color var/glass_color_blend_to_color var/glass_color_blend_to_ratio + ///Do we use random coloration var/uses_color = TRUE + ///Do we start with a window sill if maploaded + var/has_sill = TRUE /obj/structure/window/proc/change_color(new_color) if(glass_color_blend_to_color && glass_color_blend_to_ratio) diff --git a/monkestation/code/modules/aesthetics/subsystem/coloring.dm b/monkestation/code/modules/aesthetics/subsystem/coloring.dm index a2c1c972f9a5..94300cfdb8be 100644 --- a/monkestation/code/modules/aesthetics/subsystem/coloring.dm +++ b/monkestation/code/modules/aesthetics/subsystem/coloring.dm @@ -40,8 +40,9 @@ SUBSYSTEM_DEF(station_coloring) /datum/controller/subsystem/station_coloring/proc/color_area_objects(list/possible_areas, color) // paint in areas for(var/type in possible_areas) - for(var/obj/structure/window/W in GLOB.areas_by_type[type]) // for in area is slow by refs, but we have a time while in lobby so just to-do-sometime - W.change_color(color) + for(var/obj/structure/window/window in GLOB.areas_by_type[type]) // for in area is slow by refs, but we have a time while in lobby so just to-do-sometime + if(window.uses_color) + window.change_color(color) if(wall_trims) for(var/turf/closed/wall/wall in GLOB.areas_by_type[type]) if(wall.wall_trim) diff --git a/monkestation/code/modules/antagonists/clock_cult/actions/_action.dm b/monkestation/code/modules/antagonists/clock_cult/actions/_action.dm index 9ab4c66b9277..8551d897fd63 100644 --- a/monkestation/code/modules/antagonists/clock_cult/actions/_action.dm +++ b/monkestation/code/modules/antagonists/clock_cult/actions/_action.dm @@ -4,7 +4,6 @@ background_icon_state = "bg_clock" check_flags = AB_CHECK_HANDS_BLOCKED|AB_CHECK_IMMOBILE|AB_CHECK_CONSCIOUS - /datum/action/innate/clockcult/quick_bind name = "Quick Bind" button_icon_state = "telerune" @@ -14,33 +13,27 @@ /// Ref to the relevant scripture var/datum/scripture/scripture - /datum/action/innate/clockcult/quick_bind/Destroy() scripture = null return ..() - /datum/action/innate/clockcult/quick_bind/Grant(mob/living/recieving_mob) name = scripture.name desc = scripture.tip button_icon_state = scripture.button_icon_state - if(scripture.power_cost) desc += "
Draws [scripture.power_cost]W from the ark per use." - return ..(recieving_mob) /datum/action/innate/clockcult/quick_bind/Remove(mob/losing_mob) var/obj/item/clockwork/clockwork_slab/activation_slab = slab_weakref.resolve() if(activation_slab.invoking_scripture == scripture) activation_slab.invoking_scripture = null - return ..(losing_mob) /datum/action/innate/clockcult/quick_bind/IsAvailable(feedback) if(!IS_CLOCK(owner) || owner.incapacitated()) return FALSE - return ..() /datum/action/innate/clockcult/quick_bind/Activate() @@ -48,10 +41,8 @@ return var/obj/item/clockwork/clockwork_slab/activation_slab = slab_weakref.resolve() - if(!activation_slab.invoking_scripture) scripture.begin_invoke(owner, activation_slab) - else to_chat(owner, span_brass("You fail to invoke [name].")) @@ -59,12 +50,17 @@ button_icon = 'monkestation/icons/mob/clock_cult/background_clock.dmi' background_icon_state = "bg_clock" -/datum/action/cooldown/eminence +/datum/action/cooldown/clock_cult button_icon = 'monkestation/icons/mob/clock_cult/actions_clock.dmi' background_icon = 'monkestation/icons/mob/clock_cult/background_clock.dmi' background_icon_state = "bg_clock" -/datum/action/cooldown/eminence/Activate(atom/target) +/datum/action/cooldown/clock_cult/IsAvailable(feedback) + return IS_CLOCK(owner) && ..() + +/datum/action/cooldown/clock_cult/eminence + +/datum/action/cooldown/clock_cult/eminence/Activate(atom/target) . = ..() if(!iseminence(usr)) to_chat(usr, span_boldwarning("You are not an eminence and should not have this! Please report this as a bug.")) diff --git a/monkestation/code/modules/antagonists/clock_cult/actions/add_warp_area.dm b/monkestation/code/modules/antagonists/clock_cult/actions/add_warp_area.dm index ba3087ca27b0..3fd49551a841 100644 --- a/monkestation/code/modules/antagonists/clock_cult/actions/add_warp_area.dm +++ b/monkestation/code/modules/antagonists/clock_cult/actions/add_warp_area.dm @@ -1,24 +1,19 @@ -///How much do we subtract from the base cose of adding a new area -#define AREAS_TO_IGNORE_FOR_COST 10 ///How many areas are observation consoles able to warp to at the start #define STARTING_WARP_AREAS 8 +///how much vitality does each already marked area increase the cost by +#define COST_PER_AREA 4 /datum/action/innate/clockcult/add_warp_area name = "Add Warp Area" desc = "Add an additional area observation consoles can warp to." button_icon_state = "Spatial Warp" ///a cache of areas we can are to the warpable list - var/static/list/cached_addable_areas + var/static/list/cached_addable_areas //rename this to markable areas ///what area types are we blocked from warping to var/static/list/blocked_areas = typecacheof(list(/area/station/service/chapel, /area/station/ai_monitored)) ///what area types cost double var/static/list/costly_areas = typecacheof(list(/area/station/command, /area/station/security)) -/datum/action/innate/clockcult/add_warp_area/New(Target) - . = ..() - if(!cached_addable_areas) - build_addable_areas() - /datum/action/innate/clockcult/add_warp_area/IsAvailable(feedback) if(!IS_CLOCK(owner)) return FALSE @@ -32,26 +27,28 @@ if(!input_area) return - var/cost = max((length(GLOB.clock_warp_areas) * 3) - (STARTING_WARP_AREAS * 3), 0) + var/cost = max((length(SSthe_ark.marked_areas) * COST_PER_AREA) - (STARTING_WARP_AREAS * COST_PER_AREA), 0) if(is_type_in_typecache(input_area.type, costly_areas)) cost *= 2 if(tgui_alert(owner, "Are you sure you want to add [input_area]? It will cost [cost] vitality.", "Add Area", list("Yes", "No")) == "Yes") if(GLOB.clock_vitality < cost) - to_chat(span_brass("Not enough vitality.")) + to_chat(owner, span_brass("Not enough vitality.")) return - if(input_area in GLOB.clock_warp_areas) + if(SSthe_ark.marked_areas[input_area]) return - GLOB.clock_warp_areas += input_area + SSthe_ark.marked_areas[input_area] = TRUE cached_addable_areas -= input_area send_clock_message(null, "[input_area] added to warpable areas.") /datum/action/innate/clockcult/add_warp_area/proc/choose_starting_warp_areas() - if(!cached_addable_areas || !length(cached_addable_areas)) + if(!length(cached_addable_areas)) return + if(!SSthe_ark.initialized) + SSthe_ark.Initialize() //shuffle_inplace(cached_addable_areas) //this is so our picked maint areas are random without needing to do anything weird var/sanity = 0 var/added_areas = 0 @@ -62,7 +59,7 @@ var/area/station/maintenance/maint_area = locate() in cached_addable_areas if(maint_area) cached_addable_areas -= maint_area - GLOB.clock_warp_areas += maint_area + SSthe_ark.marked_areas += maint_area continue*/ //for if I implement abscond restrictions var/area/picked_area = pick(temp_list) temp_list -= picked_area @@ -70,14 +67,14 @@ continue added_areas++ - GLOB.clock_warp_areas += picked_area + SSthe_ark.marked_areas[picked_area] = TRUE cached_addable_areas -= picked_area /datum/action/innate/clockcult/add_warp_area/proc/build_addable_areas() cached_addable_areas = list() for(var/area/station_area as anything in GLOB.the_station_areas) station_area = GLOB.areas_by_type[station_area] - if(station_area.outdoors || (station_area.area_flags & ABDUCTOR_PROOF) || is_type_in_typecache(station_area, blocked_areas) || (station_area in GLOB.clock_warp_areas)) + if(station_area.outdoors || (station_area.area_flags & ABDUCTOR_PROOF) || is_type_in_typecache(station_area, blocked_areas) || (SSthe_ark.marked_areas[station_area])) continue cached_addable_areas += station_area @@ -87,8 +84,9 @@ button_icon_state = "console_info" /datum/action/innate/clockcult/show_warpable_areas/Activate() - to_chat(owner, boxed_message(span_brass("Current areas observation consoles can warp to: [english_list(GLOB.clock_warp_areas)]
\ + if(!SSthe_ark.initialized) + SSthe_ark.Initialize() + to_chat(owner, boxed_message(span_brass("Current areas observation consoles can warp to: [english_list(SSthe_ark.marked_areas)]
\ You can add additional areas with the \"Add Warp Area\" action."))) //anyone who has this action should also have add warp area -#undef AREAS_TO_IGNORE_FOR_COST #undef STARTING_WARP_AREAS diff --git a/monkestation/code/modules/antagonists/clock_cult/actions/clockmob_warp.dm b/monkestation/code/modules/antagonists/clock_cult/actions/clockmob_warp.dm new file mode 100644 index 000000000000..a91968616253 --- /dev/null +++ b/monkestation/code/modules/antagonists/clock_cult/actions/clockmob_warp.dm @@ -0,0 +1,36 @@ +/datum/action/cooldown/clock_cult/clockmob_warp + name = "Clockwork Warp" + desc = "Warp to and from marked areas on the station and reebe." + cooldown_time = 30 SECONDS + button_icon_state = "warp_down" + +/datum/action/cooldown/clock_cult/clockmob_warp/Grant(mob/granted_to) + . = ..() + if(!on_reebe(granted_to)) + button_icon_state = "Abscond" + +/datum/action/cooldown/clock_cult/clockmob_warp/Activate(atom/target) + var/turf/selected_turf + var/new_icon_state + if(on_reebe(owner)) + if(!length(SSthe_ark.marked_areas)) + return FALSE + var/area/selection = tgui_input_list(owner, "Where do you want to warp?", "Warping", SSthe_ark.marked_areas) + if(!isarea(selection)) + return FALSE + selected_turf = pick(selection.get_turfs_from_all_zlevels()) + new_icon_state = "Abscond" + else + if(!length(GLOB.abscond_markers)) + return FALSE + selected_turf = get_turf(pick(GLOB.abscond_markers)) + new_icon_state = "warp_down" + + if(!selected_turf || !do_after(owner, cooldown_time, owner)) + return FALSE + + try_servant_warp(owner, selected_turf) + if(new_icon_state) + button_icon_state = new_icon_state + build_all_button_icons(UPDATE_BUTTON_ICON) + return ..() diff --git a/monkestation/code/modules/antagonists/clock_cult/actions/emience_teleports/linked_abscond.dm b/monkestation/code/modules/antagonists/clock_cult/actions/emience_teleports/linked_abscond.dm index 212b608072a5..9b0fa6c32a0a 100644 --- a/monkestation/code/modules/antagonists/clock_cult/actions/emience_teleports/linked_abscond.dm +++ b/monkestation/code/modules/antagonists/clock_cult/actions/emience_teleports/linked_abscond.dm @@ -1,14 +1,10 @@ -/datum/action/cooldown/eminence/linked_abscond +/datum/action/cooldown/clock_cult/eminence/linked_abscond name = "Linked Abscond" desc = "Absconds a fellow servant and whomever they may be pulling back to reebe if they stand still for 7 seconds." button_icon_state = "Linked Abscond" cooldown_time = 4 MINUTES -/datum/action/cooldown/eminence/linked_abscond/Activate(atom/target) - . = ..() - if(!.) - return FALSE - +/datum/action/cooldown/clock_cult/eminence/linked_abscond/Activate(atom/target) var/mob/living/eminence/em_user = usr if(!em_user.marked_servant) to_chat(em_user, span_notice("You dont currently have a marked servant!")) @@ -19,6 +15,10 @@ to_chat(em_user, span_warning("Holy water inside [teleported] is blocking you from absconding them, use reagent purge!")) return FALSE + . = ..() + if(!.) + return FALSE + to_chat(em_user, span_brass("You begin to recall [teleported].")) to_chat(teleported, span_bigbrass("You are being recalled by the eminence.")) teleported.visible_message(span_warning("[teleported] flares briefly.")) diff --git a/monkestation/code/modules/antagonists/clock_cult/actions/purge_reagents.dm b/monkestation/code/modules/antagonists/clock_cult/actions/purge_reagents.dm index b13167b0b5f2..21591a225872 100644 --- a/monkestation/code/modules/antagonists/clock_cult/actions/purge_reagents.dm +++ b/monkestation/code/modules/antagonists/clock_cult/actions/purge_reagents.dm @@ -1,10 +1,10 @@ -/datum/action/cooldown/eminence/purge_reagents +/datum/action/cooldown/clock_cult/eminence/purge_reagents name = "Purge Reagents" desc = "Purges all reagents from the bloodstream of a marked servant, useful for if they have been given holy water." button_icon_state = "Mending Mantra" cooldown_time = 30 SECONDS -/datum/action/cooldown/eminence/purge_reagents/Activate(atom/target) +/datum/action/cooldown/clock_cult/eminence/purge_reagents/Activate(atom/target) . = ..() if(!.) return FALSE diff --git a/monkestation/code/modules/antagonists/clock_cult/actions/recall_slab.dm b/monkestation/code/modules/antagonists/clock_cult/actions/recall_slab.dm index bedf53c1c9db..c5578274d0e7 100644 --- a/monkestation/code/modules/antagonists/clock_cult/actions/recall_slab.dm +++ b/monkestation/code/modules/antagonists/clock_cult/actions/recall_slab.dm @@ -6,13 +6,11 @@ ///The slab marked for recall var/obj/item/clockwork/clockwork_slab/marked_slab - /// Set the passed object as our marked item /datum/action/innate/clockcult/recall_slab/proc/mark_item(obj/to_mark) marked_slab = to_mark RegisterSignal(marked_slab, COMSIG_QDELETING, PROC_REF(on_marked_item_deleted)) - /// Unset our current marked item /datum/action/innate/clockcult/recall_slab/proc/unmark_item() if(!marked_slab) @@ -21,7 +19,6 @@ UnregisterSignal(marked_slab, COMSIG_QDELETING) marked_slab = null - /// Signal proc for COMSIG_QDELETING on our marked item, unmarks our item if it's deleted /datum/action/innate/clockcult/recall_slab/proc/on_marked_item_deleted(datum/source) SIGNAL_HANDLER @@ -31,11 +28,9 @@ unmark_item() - /datum/action/innate/clockcult/recall_slab/Activate() try_recall_item() - /// Recalls our marked item to the caster. May bring some unexpected things along. /datum/action/innate/clockcult/recall_slab/proc/try_recall_item() var/obj/item_to_retrieve = marked_slab @@ -97,8 +92,9 @@ item_to_retrieve.loc?.visible_message(span_warning("[item_to_retrieve] suddenly disappears!")) if(isitem(item_to_retrieve) && usr.put_in_hands(item_to_retrieve)) + var/obj/item/typed_item = item_to_retrieve + typed_item.pickup(usr) //might be good to standardize this being on put_in_hands() item_to_retrieve.loc.visible_message(span_warning("[item_to_retrieve] suddenly appears in [usr]'s hand!")) - else item_to_retrieve.forceMove(usr.drop_location()) item_to_retrieve.loc.visible_message(span_warning("[item_to_retrieve] suddenly appears!")) diff --git a/monkestation/code/modules/antagonists/clock_cult/actions/space_fold.dm b/monkestation/code/modules/antagonists/clock_cult/actions/space_fold.dm index c79cfa56e852..f5358b8a1e1b 100644 --- a/monkestation/code/modules/antagonists/clock_cult/actions/space_fold.dm +++ b/monkestation/code/modules/antagonists/clock_cult/actions/space_fold.dm @@ -1,9 +1,9 @@ ///list of events eminence can trigger as well as their cost in cogs, most likely gonna have to set limits on these, might do it based on cost, unsure if I should use a .txt for this -#define EMINENCE_EVENTS list(/datum/round_event_control/brand_intelligence = 5, /datum/round_event_control/bureaucratic_error = 3, /datum/round_event_control/gravity_generator_blackout = 3, \ - /datum/round_event_control/communications_blackout = 5, /datum/round_event_control/electrical_storm = 2, /datum/round_event_control/ion_storm = 5, \ - /datum/round_event_control/grey_tide = 3, /datum/round_event_control/grid_check = 5, /datum/round_event_control/scrubber_overflow/catastrophic = 4, \ - /datum/round_event_control/radiation_storm = 7, /datum/round_event_control/scrubber_clog/critical = 3, /datum/round_event_control/carp_migration = 6, \ - /datum/round_event_control/wormholes = 5, /datum/round_event_control/immovable_rod = 8, /datum/round_event_control/anomaly/anomaly_dimensional = 2, \ +#define EMINENCE_EVENTS list(/datum/round_event_control/brand_intelligence = 5, /datum/round_event_control/bureaucratic_error = 3, /datum/round_event_control/gravity_generator_blackout = 4, \ + /datum/round_event_control/communications_blackout = 6, /datum/round_event_control/electrical_storm = 2, /datum/round_event_control/ion_storm = 6, \ + /datum/round_event_control/grey_tide = 3, /datum/round_event_control/grid_check = 6, /datum/round_event_control/scrubber_overflow/catastrophic = 4, \ + /datum/round_event_control/radiation_storm = 8, /datum/round_event_control/scrubber_clog/critical = 3, /datum/round_event_control/carp_migration = 6, \ + /datum/round_event_control/wormholes = 6, /datum/round_event_control/immovable_rod = 9, /datum/round_event_control/anomaly/anomaly_dimensional = 2, \ /datum/round_event_control/anomaly/anomaly_bluespace = 4, /datum/round_event_control/anomaly/anomaly_ectoplasm = 4, \ /datum/round_event_control/anomaly/anomaly_flux = 3, /datum/round_event_control/anomaly/anomaly_pyro = 5) diff --git a/monkestation/code/modules/antagonists/clock_cult/antag_datums/clock_cult_team.dm b/monkestation/code/modules/antagonists/clock_cult/antag_datums/clock_cult_team.dm index 50563e408926..cf0b88f8bac6 100644 --- a/monkestation/code/modules/antagonists/clock_cult/antag_datums/clock_cult_team.dm +++ b/monkestation/code/modules/antagonists/clock_cult/antag_datums/clock_cult_team.dm @@ -1,7 +1,7 @@ GLOBAL_DATUM(main_clock_cult, /datum/team/clock_cult) //this is effectively 2 higher due to the first anchoring crystal always allowing 2 more servants -#define DEFAULT_MAX_HUMAN_SERVANTS 10 +#define DEFAULT_MAX_HUMAN_SERVANTS 8 #define CONVERSION_WARNING_NONE 0 #define CONVERSION_WARNING_HALFWAY 1 #define CONVERSION_WARNING_THREEQUARTERS 2 @@ -72,7 +72,7 @@ GLOBAL_DATUM(main_clock_cult, /datum/team/clock_cult) max_human_servants = round(max((get_active_player_count() / 8), max_human_servants)) var/human_servant_count = length(human_servants) var/main_message = "The Ark will be torn open if [max_human_servants - human_servant_count] more minds are converted to the faith of Rat'var\ - [get_charged_anchor_crystals() >= ANCHORING_CRYSTALS_TO_SUMMON ? "." : " and \ + [SSthe_ark.charged_anchoring_crystals >= ANCHORING_CRYSTALS_TO_SUMMON ? "." : " and \ [ANCHORING_CRYSTALS_TO_SUMMON] Anchoring Crystal[ANCHORING_CRYSTALS_TO_SUMMON > 1 ? "s are" : " is"] summoned and protected on the station."]" if((human_servant_count * 2) > max_human_servants && warning_stage < CONVERSION_WARNING_HALFWAY) @@ -84,13 +84,13 @@ GLOBAL_DATUM(main_clock_cult, /datum/team/clock_cult) sent_sound = 'sound/magic/clockwork/scripture_tier_up.ogg') warning_stage = CONVERSION_WARNING_THREEQUARTERS - else if((human_servant_count == max_human_servants - 1) && warning_stage < CONVERSION_WARNING_CRITIAL && get_charged_anchor_crystals() >= 2) + else if((human_servant_count == max_human_servants - 1) && warning_stage < CONVERSION_WARNING_CRITIAL && SSthe_ark.charged_anchoring_crystals >= ANCHORING_CRYSTALS_TO_SUMMON) send_clock_message(span_bigbrass("The internal cogs of the Ark begin spinning, ready for activation.
\ Upon the next conversion, the dimensional barrier will become too weak for The Ark to remain closed and it will be forced open."), \ sent_sound = 'sound/magic/clockwork/scripture_tier_up.ogg') warning_stage = CONVERSION_WARNING_CRITIAL - else if((human_servant_count >= max_human_servants) && get_charged_anchor_crystals() >= ANCHORING_CRYSTALS_TO_SUMMON) + else if((human_servant_count >= max_human_servants) && SSthe_ark.charged_anchoring_crystals >= ANCHORING_CRYSTALS_TO_SUMMON) GLOB.clock_ark?.prepare_ark() ///check that our human_servants and non_human_servants lists are correct and if not then set them to be correct @@ -131,27 +131,34 @@ GLOBAL_DATUM(main_clock_cult, /datum/team/clock_cult) #define POSSIBLE_CRYSTAL_AREAS 6 /datum/objective/anchoring_crystals - var/list/valid_areas = list() /datum/objective/anchoring_crystals/New() . = ..() + if(SSthe_ark.valid_crystal_areas) + return + SSthe_ark.valid_crystal_areas = list() var/sanity = 0 - while(length(valid_areas) < POSSIBLE_CRYSTAL_AREAS && sanity < 100) - var/area/summon_area = pick(GLOB.areas - valid_areas) + var/list/areas_copy = GLOB.areas.Copy() + while(length(SSthe_ark.valid_crystal_areas) < POSSIBLE_CRYSTAL_AREAS && sanity < 100) + var/area/summon_area = pick_n_take(areas_copy) if(summon_area && is_station_level(summon_area.z) && (summon_area.area_flags & VALID_TERRITORY)) - valid_areas += summon_area + SSthe_ark.valid_crystal_areas[summon_area] = summon_area.get_original_area_name() sanity++ update_explanation_text() /datum/objective/anchoring_crystals/update_explanation_text() var/plural = ANCHORING_CRYSTALS_TO_SUMMON > 1 - explanation_text = "Summon [ANCHORING_CRYSTALS_TO_SUMMON] anchoring crystal[plural ? "s" : ""] on the station and protect [plural ? "them" : "it"] for 5 \ - minutes to allow the ark to open. Crystals after the first one must be summoned in [english_list(valid_areas)]. \ - Up to 2 additional crystals can be created for extra power." + var/list/names = list() + for(var/area/valid_area in SSthe_ark.valid_crystal_areas) + names += SSthe_ark.valid_crystal_areas[valid_area] + + explanation_text = "Summon [ANCHORING_CRYSTALS_TO_SUMMON] anchoring crystal[plural ? "s" : ""] on the station and protect [plural ? "them" : "it"] for \ + [DisplayTimeText(ANCHORING_CRYSTAL_CHARGE_DURATION)] to allow the ark to open. \ + Crystals after the first one must be summoned in [english_list(names)]. Up to 2 additional crystals can be created for extra power." /datum/objective/anchoring_crystals/check_completion() - return get_charged_anchor_crystals() >= ANCHORING_CRYSTALS_TO_SUMMON || completed + return SSthe_ark.charged_anchoring_crystals >= ANCHORING_CRYSTALS_TO_SUMMON || completed /datum/objective/ratvar explanation_text = "Protect The Ark so that Rat'var may enlighten this world!" diff --git a/monkestation/code/modules/antagonists/clock_cult/antag_datums/clock_cultist.dm b/monkestation/code/modules/antagonists/clock_cult/antag_datums/clock_cultist.dm index 9a91d197d64c..21f4d8b81215 100644 --- a/monkestation/code/modules/antagonists/clock_cult/antag_datums/clock_cultist.dm +++ b/monkestation/code/modules/antagonists/clock_cult/antag_datums/clock_cultist.dm @@ -27,6 +27,7 @@ /datum/antagonist/clock_cultist/Destroy() QDEL_NULL(communicate) + QDEL_NULL(recall) return ..() /datum/antagonist/clock_cultist/on_gain() @@ -39,6 +40,7 @@ if(issilicon(current)) handle_silicon_conversion(current) . = ..() //have to call down here so objectives display correctly + ADD_TRAIT(owner, TRAIT_MAGICALLY_GIFTED, REF(src)) /datum/antagonist/clock_cultist/greet() . = ..() @@ -77,8 +79,7 @@ if(ishuman(current) || iscogscarab(current)) //only human and cogscarabs would need a recall ability recall.Grant(current) - owner_turf_healing = current.AddComponent(/datum/component/turf_healing, healing_types = list(TOX = 4), \ - healing_turfs = GLOB.clock_turf_types) + owner_turf_healing = current.AddComponent(/datum/component/turf_healing, healing_types = list(TOX = (iscarbon(current) ? 4 : 1)), healing_turfs = GLOB.clock_turf_types) RegisterSignal(current, COMSIG_CLOCKWORK_SLAB_USED, PROC_REF(switch_recall_slab)) handle_clown_mutation(current, mob_override ? null : "The light of Rat'var allows you to overcome your clownish nature, allowing you to wield weapons without harming yourself.") add_forbearance(current) @@ -97,6 +98,11 @@ QDEL_NULL(owner_turf_healing) handle_clown_mutation(current, removing = FALSE) +/datum/antagonist/clock_cultist/ui_data(mob/user) + var/list/data = list() + data["marked_areas"] = english_list(SSthe_ark.marked_areas) + return data + /datum/antagonist/clock_cultist/can_be_owned(datum/mind/new_owner) . = ..() if(.) @@ -108,6 +114,7 @@ span_userdanger("As the ticking fades from the back of your mind, you forget all memories you had as a servant of Rat'var.")) owner.current.log_message("has renounced the cult of Rat'var!", LOG_ATTACK, color="#960000") handle_equipment_removal() + REMOVE_TRAIT(owner, TRAIT_MAGICALLY_GIFTED, REF(src)) return ..() /datum/antagonist/clock_cultist/get_preview_icon() @@ -201,57 +208,6 @@ if(GLOB.clock_ark?.current_state >= ARK_STATE_ACTIVE) apply_to.add_filter("forbearance", 3, list("type" = "outline", "color" = "#FAE48E", "size" = 2, "alpha" = 100)) -/datum/antagonist/clock_cultist/eminence - name = "Eminence" - antag_flags = parent_type::antag_flags | FLAG_ANTAG_CAP_IGNORE - give_slab = FALSE - antag_moodlet = null - communicate = null - recall = null - ///The list of our actions - var/list/action_list = list( - /datum/action/innate/clockcult/space_fold, - /datum/action/cooldown/eminence/purge_reagents, - /datum/action/cooldown/eminence/linked_abscond, - /datum/action/innate/clockcult/teleport_to_servant, - /datum/action/innate/clockcult/teleport_to_station, - /datum/action/innate/clockcult/eminence_abscond, - /datum/action/innate/clockcult/show_warpable_areas, - /datum/action/innate/clockcult/add_warp_area, - ) - -/datum/antagonist/clock_cultist/eminence/Destroy() - QDEL_LIST(action_list) - return ..() - -/datum/antagonist/clock_cultist/eminence/greet() - to_chat(owner.current, boxed_message("[span_bigbrass("You are the Eminence, a being bound to Rat'var. By his light you are able to influence nearby space and time.")]
\ - [span_brass("As the Eminence you have access to various abilities, they are as follows.
\ - You may click on various machines to interface with them or a servant to mark them.
\ - Purge Reagents: Remove all reagents from the bloodstream of a marked servant, this is useful for a servant who is being deconverted by holy water.
\ - Linked Abscond: Return a marked servant and anything they are pulling to reebe, this has a lengthy cooldown and they must remain still for 7 seconds.
\ - Space Fold: Fold local spacetime to ensure certain \"events\" are inflicted upon the station, while doing this will cost cogs, \ - these cogs are not taken from the cult itself. The cooldown is based on the cog cost of the event.
\ - You can also teleport yourself to any other servant, useful for servants who need to be absconded like those which are dead or being deconverted.")]")) - -/datum/antagonist/clock_cultist/eminence/apply_innate_effects(mob/living/mob_override) - . = ..() - var/mob/living/current = owner.current - add_team_hud(current, /datum/antagonist/clock_cultist) - for(var/datum/action/our_action as anything in action_list) - if(ispath(our_action)) - our_action = new our_action() - our_action.Grant(current) - -/datum/antagonist/clock_cultist/eminence/remove_innate_effects(mob/living/mob_override) - . = ..() - for(var/datum/action/removed_action in action_list) - removed_action.Remove(owner.current) - -/datum/antagonist/clock_cultist/eminence/on_removal() //this should never happen without an admin being involved, something has gone wrong - to_chat(owner.current, span_userdanger("You lost your eminence antagonist status! This should not happen and you should ahelp(f1) unless you are already talking to an admin.")) - return ..() - /datum/outfit/clock/preview name = "Clock Cultist (Preview only)" @@ -260,7 +216,6 @@ head = /obj/item/clothing/head/helmet/clockwork l_hand = /obj/item/clockwork/weapon/brass_sword - //these can just solo invoke things that normally take multiple servants /datum/antagonist/clock_cultist/solo name = "Servant of Rat'var (Solo)" diff --git a/monkestation/code/modules/antagonists/clock_cult/antag_datums/clockmob_antag_datum.dm b/monkestation/code/modules/antagonists/clock_cult/antag_datums/clockmob_antag_datum.dm new file mode 100644 index 000000000000..921062abd97d --- /dev/null +++ b/monkestation/code/modules/antagonists/clock_cult/antag_datums/clockmob_antag_datum.dm @@ -0,0 +1,23 @@ +/datum/antagonist/clock_cultist/clockmob + show_in_antagpanel = FALSE + ///Our warp action + var/datum/action/cooldown/clock_cult/clockmob_warp/warp_action = new + ///A ref to our area bound component + var/datum/component/multi_area_bound/area_bound_component + +/datum/antagonist/clock_cultist/clockmob/Destroy() + QDEL_NULL(warp_action) + return ..() + +/datum/antagonist/clock_cultist/clockmob/apply_innate_effects(mob/living/mob_override) + . = ..() + warp_action.Grant(owner.current) + if(area_bound_component) + QDEL_NULL(area_bound_component) + stack_trace("[src.type] calling apply_innate_effects while still having an old area_bound_component.") + area_bound_component = owner.current.AddComponent(/datum/component/multi_area_bound, _valid_areas = SSthe_ark.marked_areas + SSthe_ark.reebe_areas, _use_instances = TRUE) + +/datum/antagonist/clock_cultist/clockmob/remove_innate_effects(mob/living/mob_override) + . = ..() + warp_action.Remove(owner.current) + QDEL_NULL(area_bound_component) diff --git a/monkestation/code/modules/antagonists/clock_cult/antag_datums/eminence_antag_datum.dm b/monkestation/code/modules/antagonists/clock_cult/antag_datums/eminence_antag_datum.dm new file mode 100644 index 000000000000..b3b9dc07b95e --- /dev/null +++ b/monkestation/code/modules/antagonists/clock_cult/antag_datums/eminence_antag_datum.dm @@ -0,0 +1,50 @@ +/datum/antagonist/clock_cultist/eminence + name = "Eminence" + antag_flags = parent_type::antag_flags | FLAG_ANTAG_CAP_IGNORE + give_slab = FALSE + antag_moodlet = null + communicate = null + recall = null + ///The list of our actions + var/list/action_list = list( + /datum/action/innate/clockcult/space_fold, + /datum/action/cooldown/clock_cult/eminence/purge_reagents, + /datum/action/cooldown/clock_cult/eminence/linked_abscond, + /datum/action/innate/clockcult/teleport_to_servant, + /datum/action/innate/clockcult/teleport_to_station, + /datum/action/innate/clockcult/eminence_abscond, + /datum/action/innate/clockcult/show_warpable_areas, + /datum/action/innate/clockcult/add_warp_area, + ) + +/datum/antagonist/clock_cultist/eminence/Destroy() + QDEL_LIST(action_list) + return ..() + +/datum/antagonist/clock_cultist/eminence/greet() + to_chat(owner.current, boxed_message("[span_bigbrass("You are the Eminence, a being bound to Rat'var. By his light you are able to influence nearby space and time.")]
\ + [span_brass("As the Eminence you have access to various abilities, they are as follows.
\ + You may click on various machines to interface with them or a servant to mark them.
\ + Purge Reagents: Remove all reagents from the bloodstream of a marked servant, this is useful for a servant who is being deconverted by holy water.
\ + Linked Abscond: Return a marked servant and anything they are pulling to reebe, this has a lengthy cooldown and they must remain still for 7 seconds.
\ + Space Fold: Fold local spacetime to ensure certain \"events\" are inflicted upon the station, while doing this will cost cogs, \ + these cogs are not taken from the cult itself. The cooldown is based on the cog cost of the event.
\ + You can also teleport yourself to any other servant, useful for servants who need to be absconded like those which are dead or being deconverted.")]")) + +/datum/antagonist/clock_cultist/eminence/apply_innate_effects(mob/living/mob_override) + . = ..() + var/mob/living/current = owner.current + add_team_hud(current, /datum/antagonist/clock_cultist) + for(var/datum/action/our_action as anything in action_list) + if(ispath(our_action)) + our_action = new our_action() + our_action.Grant(current) + +/datum/antagonist/clock_cultist/eminence/remove_innate_effects(mob/living/mob_override) + . = ..() + for(var/datum/action/removed_action in action_list) + removed_action.Remove(owner.current) + +/datum/antagonist/clock_cultist/eminence/on_removal() //this should never happen without an admin being involved, something has gone wrong + to_chat(owner.current, span_userdanger("You lost your eminence antagonist status! This should not happen and you should ahelp(f1) unless you are already talking to an admin.")) + return ..() diff --git a/monkestation/code/modules/antagonists/clock_cult/area.dm b/monkestation/code/modules/antagonists/clock_cult/area.dm index 66a88fd549fb..6b5b03d1e21e 100644 --- a/monkestation/code/modules/antagonists/clock_cult/area.dm +++ b/monkestation/code/modules/antagonists/clock_cult/area.dm @@ -1,12 +1,12 @@ /area/ruin/powered/reebe - name = "Outpost of Cogs" + name = "Reebe" ambience_index = AMBIENCE_REEBE area_flags = UNIQUE_AREA | CULT_PERMITTED | NOTELEPORT static_lighting = FALSE base_lighting_alpha = 200 /area/ruin/powered/reebe/space - name = "Outpost of Cogs Space" + name = "Reebe Space" base_lighting_alpha = 255 /area/ruin/powered/reebe/city diff --git a/monkestation/code/modules/antagonists/clock_cult/ark_subsystem/_ark_subsystem.dm b/monkestation/code/modules/antagonists/clock_cult/ark_subsystem/_ark_subsystem.dm new file mode 100644 index 000000000000..3a138461d45e --- /dev/null +++ b/monkestation/code/modules/antagonists/clock_cult/ark_subsystem/_ark_subsystem.dm @@ -0,0 +1,182 @@ +///A subsystem to manage the global effects of clock cult +//#define SERVANT_CAPACITY_TO_GIVE 2 //how many extra servant slots do we give on first charged crystal +SUBSYSTEM_DEF(the_ark) + name = "The Clockwork Ark" + wait = 1 SECOND + flags = SS_KEEP_TIMING | SS_NO_INIT + runlevels = RUNLEVEL_GAME + + ///The list of anchoring crystals, value is 0 is uncharged and 1 if charged + var/list/anchoring_crystals + ///How many charged anchoring crystals are there + var/charged_anchoring_crystals = 0 + ///Dimension theme used for transforming turfs + var/datum/dimension_theme/clockwork/clock_dimension_theme + ///Assoc list of the original names of areas that are valid to summon anchoring crystals keyed to its area + var/list/valid_crystal_areas + ///The pool of hallucinations we can trigger + var/list/hallucination_pool + ///How many clockwork airlocks have been created on reebe, used for limiting airlock spam + var/reebe_clockwork_airlock_count = 0 + ///How much power does the cult have stored + var/clock_power = 2500 + ///What is the maximum amount of power the cult can have stored + var/max_clock_power = 2500 + ///The list of areas that has been marked by the cult, formatted as a filled with 1s for anti duplication + var/list/marked_areas = list() + ///A list of all cogscarabs + var/list/cogscarabs = list() + ///A list of all clockwork marauders + var/list/clockwork_marauders = list() + ///A list of all the areas on reebe + var/list/reebe_areas = list() + +/datum/controller/subsystem/the_ark/Initialize() + initialized = TRUE + anchoring_crystals = list() + clock_dimension_theme = new(is_cult = TRUE) + hallucination_pool = list( + /datum/hallucination/fake_item/clockwork_slab = 2, + /datum/hallucination/nearby_fake_item/clockwork_slab = 2, + /datum/hallucination/hazard/clockwork_skewer = 1, + /datum/hallucination/delusion/preset/clock_cultists = 1, + /datum/hallucination/fake_sound/weird/clockcult_kindle = 2, + /datum/hallucination/fake_sound/weird/clockcult_warp = 2, + ) + var/datum/action/innate/clockcult/add_warp_area/warp_action = new //my brain is dying + warp_action.build_addable_areas() + warp_action.choose_starting_warp_areas() + qdel(warp_action) + +/datum/controller/subsystem/the_ark/fire(resumed) + if(!initialized) //we are not currently being used so just return + return + + if(charged_anchoring_crystals) + handle_charged_crystals() + +///try and adjust our clock_power, returns FALSE if it would put us above our max_clock_power or below 0, set always_adjust to TRUE to make us instead just adjust to be within bounds +/datum/controller/subsystem/the_ark/proc/adjust_clock_power(amount, always_adjust = FALSE) + var/new_total = clock_power + amount + if(always_adjust) + clock_power = clamp(new_total, 0, max_clock_power) + return TRUE + + if(new_total > max_clock_power || new_total < 0) + return FALSE + clock_power = new_total + return TRUE + +///set up timed do_turf_conversion calls for the turfs in an area +/datum/controller/subsystem/the_ark/proc/convert_area_turfs(area/converted_area, conversion_percent = 100, counter_override) + var/timer_counter = counter_override || 1 //used by the addtimer() + var/list/turfs_to_transform = list() + for(var/i in 1 to length(converted_area.turfs_by_zlevel)) + turfs_to_transform += converted_area.turfs_by_zlevel[i] + + var/transformed_length = length(turfs_to_transform) + var/converted_amount = round(transformed_length * (conversion_percent * 0.01)) + while(transformed_length && transformed_length > converted_amount) + pick_n_take(turfs_to_transform) + transformed_length = length(turfs_to_transform) + + shuffle_inplace(turfs_to_transform) + for(var/turf/turf_to_transform in turfs_to_transform) + if(!clock_dimension_theme.can_convert(turf_to_transform)) + continue + addtimer(CALLBACK(src, PROC_REF(do_turf_conversion), turf_to_transform), 3 * timer_counter) + timer_counter++ + return timer_counter //so you can do stuff once the conversion ends + +///convert a turf to our dimension theme +/datum/controller/subsystem/the_ark/proc/do_turf_conversion(turf/converted_turf) + if(QDELETED(src) || !clock_dimension_theme.can_convert(converted_turf)) + return + + clock_dimension_theme.apply_theme(converted_turf) + new /obj/effect/temp_visual/ratvar/beam(converted_turf) + if(istype(converted_turf, /turf/closed/wall)) + new /obj/effect/temp_visual/ratvar/wall(converted_turf) + else if(istype(converted_turf, /turf/open/floor)) + new /obj/effect/temp_visual/ratvar/floor(converted_turf) + +///called when an anchoring crystal is charged +/datum/controller/subsystem/the_ark/proc/on_crystal_charged(obj/structure/destructible/clockwork/anchoring_crystal/charged_crystal) + charged_anchoring_crystals++ + anchoring_crystals[charged_crystal] = 1 + SEND_SIGNAL(src, COMSIG_ANCHORING_CRYSTAL_CHARGED, charged_crystal) + var/datum/scripture/create_structure/anchoring_crystal/crystal_script + addtimer(CALLBACK(src, PROC_REF(clear_shuttle_interference), charged_crystal), \ + (ANCHORING_CRYSTAL_COOLDOWN - ANCHORING_CRYSTAL_CHARGE_DURATION) + initial(crystal_script.invocation_time)) + + /*if(1) //add 2 more max servants and increase replica fabricator build speed + GLOB.main_clock_cult.max_human_servants += SERVANT_CAPACITY_TO_GIVE*/ + if(charged_anchoring_crystals == ANCHORING_CRYSTALS_TO_SUMMON + 1) //create a steam helios on reebe + if(length(GLOB.abscond_markers)) + var/turf/created_at = get_turf(pick(GLOB.abscond_markers)) + new /obj/vehicle/sealed/mecha/steam_helios(created_at) + new /obj/effect/temp_visual/steam(created_at) + else if(GLOB.clock_ark) + new /obj/vehicle/sealed/mecha/steam_helios(get_turf(GLOB.clock_ark)) + else + message_admins("No valid location for Steam Helios creation.") + +///fully disables the shuttle similar to the admin verb +/datum/controller/subsystem/the_ark/proc/block_shuttle(datum/blocker) + if(SSshuttle.admin_emergency_disabled || SSshuttle.emergency.mode == SHUTTLE_DISABLED || SSshuttle.emergency.mode == SHUTTLE_ESCAPE) + return + + SSshuttle.last_mode = SSshuttle.emergency.mode + SSshuttle.last_call_time = SSshuttle.emergency.timeLeft(1) + SSshuttle.emergency_no_recall = TRUE + SSshuttle.emergency.setTimer(0) + SSshuttle.emergency.mode = SHUTTLE_DISABLED + +///renables the shuttle +/datum/controller/subsystem/the_ark/proc/clear_shuttle_interference(datum/unblocker) + if(SSshuttle.admin_emergency_disabled || SSshuttle.emergency.mode != SHUTTLE_DISABLED || \ + (unblocker && GLOB.clock_ark && GLOB.clock_ark.current_state >= ARK_STATE_CHARGING && istype(unblocker, /obj/structure/destructible/clockwork/anchoring_crystal))) + return + + SSshuttle.emergency_no_recall = FALSE + if(SSshuttle.last_mode == SHUTTLE_DISABLED) + SSshuttle.last_mode = SHUTTLE_IDLE + + SSshuttle.emergency.mode = SSshuttle.last_mode + if(SSshuttle.last_call_time < 10 SECONDS && SSshuttle.last_mode != SHUTTLE_IDLE) + SSshuttle.last_call_time = 10 SECONDS //Make sure no insta departures. + SSshuttle.emergency.setTimer(SSshuttle.last_call_time) + priority_announce("Emergency shuttle uplink connection regained.", "Higher Dimensional Affairs", ANNOUNCER_SPANOMALIES, has_important_message = TRUE) + +///returns how many charged anchor crystals there are +/datum/controller/subsystem/the_ark/proc/get_charged_anchor_crystals() + var/charged_count = 0 + for(var/crystal in SSthe_ark.anchoring_crystals) + charged_count += SSthe_ark.anchoring_crystals[crystal] + return charged_count + +//#undef SERVANT_CAPACITY_TO_GIVE + +/datum/action/cooldown/spell/spacetime_dist + ///The type of effect we actually spawn + var/obj/effect/cross_action/spacetime_dist/spawned_effect_type = /obj/effect/cross_action/spacetime_dist + +/datum/action/cooldown/spell/spacetime_dist/clock_ark + name = "Clockwork Spacetime Dist" + cooldown_time = 0 + scramble_radius = 2 + duration = 1 MINUTE + spawned_effect_type = /obj/effect/cross_action/spacetime_dist/clock_ark + +/obj/effect/cross_action/spacetime_dist/clock_ark + +/obj/effect/cross_action/spacetime_dist/clock_ark/walk_link(atom/movable/AM) + if(isliving(AM)) + var/mob/living/living_mob = AM + if(IS_CLOCK(living_mob)) + return + return ..() + +/obj/effect/timestop/magic/clock_ark + icon_state = "" + hidden = TRUE diff --git a/monkestation/code/modules/antagonists/clock_cult/ark_subsystem/warp_effects.dm b/monkestation/code/modules/antagonists/clock_cult/ark_subsystem/warp_effects.dm new file mode 100644 index 000000000000..ba803656af56 --- /dev/null +++ b/monkestation/code/modules/antagonists/clock_cult/ark_subsystem/warp_effects.dm @@ -0,0 +1,159 @@ +//boy this sure is some fun code +/datum/controller/subsystem/the_ark/proc/handle_charged_crystals() + if(prob(charged_anchoring_crystals)) + crystal_warp_minds() + + if(charged_anchoring_crystals >= 2 && prob(charged_anchoring_crystals)) + crystal_warp_machines() + + if(charged_anchoring_crystals >= 3 && prob(charged_anchoring_crystals)) + crystal_warp_space() + +/datum/controller/subsystem/the_ark/proc/crystal_warp_minds() + var/list/players = GLOB.alive_player_list.Copy() + var/mob/living/selected_player = pick_n_take(players) + var/sanity = 0 + if(!selected_player) + return + + while(sanity < 100 && (IS_CLOCK(selected_player) || !is_station_level(selected_player.z))) + if(!length(players)) + return + sanity++ + selected_player = pick_n_take(players) + + if(prob(50)) + selected_player.cause_hallucination(pick_weight(hallucination_pool), "The Clockwork Ark") + else + to_chat(selected_player, span_warning(pick(list("You hear a faint ticking in the back of your mind", "You smell something metallic", \ + "You see a flash of light out of the corner of your eye", "You feel an otherworldly presence", "You feel like your forgetting something")))) + +//making these their own procs for eaiser to read code +/datum/controller/subsystem/the_ark/proc/crystal_warp_machines() + switch(rand(1, 3)) + if(1) //randomly mess with the settings of an APC with a low chance to emag it + var/list/apcs = SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/power/apc, /obj/machinery/power/apc/worn_out) + var/obj/machinery/power/apc/picked_apc = pick_n_take(apcs) //pick_n_take() handles length checking + if(!picked_apc) + return + var/sanity = 0 + while(sanity < 100 && length(apcs) && !is_station_level(picked_apc.z)) + picked_apc = pick_n_take(apcs) + sanity++ + if(picked_apc) + if(prob(30)) + picked_apc.overload_lighting() + else + picked_apc.lighting = picked_apc.setsubsystem(1) + if(prob(30)) + picked_apc.equipment = picked_apc.setsubsystem(1) + if(prob(30)) + picked_apc.environ = picked_apc.setsubsystem(1) + addtimer(CALLBACK(picked_apc, TYPE_PROC_REF(/obj/machinery/power/apc, setsubsystem), rand(2, 3)), 1 MINUTE) + if(!(picked_apc.obj_flags & EMAGGED) && prob(10)) + playsound(src, SFX_SPARKS, 75, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + picked_apc.obj_flags |= EMAGGED + picked_apc.locked = FALSE + picked_apc.update_appearance() + if(2) //force open an airlock and bolt it + var/list/airlocks = SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/door/airlock, \ + typesof(/obj/machinery/door/airlock/maintenance) + typesof(/obj/machinery/door/airlock/bronze/clock) + /obj/machinery/door/airlock/maintenance_hatch) + var/obj/machinery/door/airlock/picked_airlock = pick_n_take(airlocks) + if(!picked_airlock) + return + var/sanity = 0 + while(sanity < 100 && length(airlocks) && (!picked_airlock.hasPower() || !is_station_level(picked_airlock.z) || picked_airlock.is_probably_external_airlock())) + picked_airlock = pick_n_take(airlocks) + sanity++ + if(picked_airlock) + picked_airlock.unbolt() + picked_airlock.open(FORCING_DOOR_CHECKS) + picked_airlock.bolt() + if(3) //emag a random atom from our list of valid types + var/list/valid_emag_targets = list( + /mob/living/simple_animal/bot, + /mob/living/basic/bot, + /obj/machinery/announcement_system, + /obj/machinery/barsign, + /obj/machinery/computer/communications, + /obj/machinery/medical_kiosk, + /obj/machinery/sleeper, + /obj/machinery/computer/slot_machine, + /obj/machinery/computer/cargo/express, + /obj/machinery/computer/cargo, + /obj/machinery/destructive_scanner, + /obj/machinery/fishing_portal_generator, + /obj/machinery/computer/holodeck, + /obj/machinery/elevator_control_panel, + /obj/machinery/crossing_signal, + /obj/machinery/fax, + /obj/machinery/chem_dispenser, + /obj/machinery/research/anomaly_refinery, + /obj/machinery/plumbing/growing_vat, + /obj/machinery/computer/bsa_control, + /obj/machinery/vending, + /obj/machinery/clonepod, + /obj/machinery/clonepod/experimental, + /obj/machinery/artifact_xray, + /obj/machinery/artifact_zapper, + /obj/machinery/computer/operating, + /obj/machinery/composters, + ) + var/atom/selected_type = pick_n_take(valid_emag_targets) + var/list/valid_type_instances = get_emag_target_type_instances(selected_type) + var/sanity = 0 + var/obj/machinery/selected_atom + while(!selected_atom && sanity < 10) + sanity++ + while(!length(valid_type_instances)) + if(!length(valid_emag_targets)) + return + selected_type = pick_n_take(valid_emag_targets) + valid_type_instances = get_emag_target_type_instances(selected_type) + while(!selected_atom || bot_v_machine_check(selected_atom) || !is_station_level(selected_atom.z)) + if(!length(valid_type_instances)) + selected_atom = null + break + selected_atom = pick_n_take(valid_type_instances) + if(!selected_atom) + return + if(isbasicbot(selected_atom)) + var/mob/living/basic/bot/basic_bot = selected_atom + basic_bot.bot_access_flags &= ~BOT_CONTROL_PANEL_OPEN | ~BOT_MAINTS_PANEL_OPEN + else if(isbot(selected_atom)) + var/mob/living/simple_animal/bot/simple_bot = selected_atom + simple_bot.bot_cover_flags &= BOT_COVER_OPEN | ~BOT_COVER_LOCKED + selected_atom.emag_act() + +/datum/controller/subsystem/the_ark/proc/crystal_warp_space() + switch(rand(1, 2)) + if(1) + var/datum/action/cooldown/spell/spacetime_dist/clock_ark/dist_spell = new + var/turf/turf = get_random_station_turf() + dist_spell.cast(turf) + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(qdel), dist_spell), dist_spell.duration) + if(2) + var/list/servants = list() //technically we could adjust this everytime someone joins or leaves the cult but these last for 30 seconds so eh + if(GLOB.main_clock_cult) + for(var/datum/mind/servant_mind in GLOB.main_clock_cult.members) + servants += servant_mind.current + new /obj/effect/timestop/magic/clock_ark(get_random_station_turf(), 1, 30 SECONDS, servants) + return + +/datum/controller/subsystem/the_ark/proc/get_emag_target_type_instances(input_path) + if(ispath(input_path, /obj/machinery)) + return SSmachines.get_machines_by_type(input_path) + if(ispath(input_path, /mob/living/simple_animal/bot) || ispath(input_path, /mob/living/basic/bot)) + return GLOB.bots_list.Copy() + +//OH YEAH I LOVE GOOD CODE +/datum/controller/subsystem/the_ark/proc/bot_v_machine_check(atom/checked_atom) + if(ismachinery(checked_atom)) + var/obj/machinery/checked_machine = checked_atom + return checked_machine.obj_flags & EMAGGED + if(isbasicbot(checked_atom)) + var/mob/living/basic/bot/checked_basic_bot = checked_atom + return checked_basic_bot.bot_access_flags & BOT_COVER_EMAGGED + if(istype(checked_atom, /mob/living/simple_animal/bot)) + var/mob/living/simple_animal/bot/checked_bot = checked_atom + return checked_bot.bot_cover_flags & BOT_COVER_EMAGGED diff --git a/monkestation/code/modules/antagonists/clock_cult/enchantments/_enchantment.dm b/monkestation/code/modules/antagonists/clock_cult/enchantments/_enchantment.dm deleted file mode 100644 index 7a94e9d598e6..000000000000 --- a/monkestation/code/modules/antagonists/clock_cult/enchantments/_enchantment.dm +++ /dev/null @@ -1,41 +0,0 @@ -/datum/component/enchantment - //Examine text - var/examine_description - //Maximum enchantment level - var/max_level = 1 - //Current enchantment level - var/level - -/datum/component/enchantment/Initialize() - if(!isitem(parent)) - return COMPONENT_INCOMPATIBLE - - if(on_reebe(parent)) //currently this is only added by stargazers so this should work fine - max_level = 1 - //Get random level - level = rand(1, max_level) - //Apply effect - apply_effect(parent) - //Add in examine effect - RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) - -/datum/component/enchantment/Destroy() - UnregisterSignal(parent, COMSIG_ATOM_EXAMINE) - return ..() - -/datum/component/enchantment/proc/apply_effect(obj/item/target) - return - -/datum/component/enchantment/proc/on_examine(datum/source, mob/user, list/examine_list) - SIGNAL_HANDLER - - if(!examine_description) - return - if(IS_CLOCK(user) || isobserver(user)) - examine_list += span_brass("[examine_description]") - examine_list += span_brass("It's blessing has a power of [level]!") - else - examine_list += "It is glowing slightly!" - var/mob/living/living_user = user - if(istype(living_user.get_item_by_slot(ITEM_SLOT_EYES), /obj/item/clothing/glasses/science)) - examine_list += "It emits a readable EMF factor of [level]." diff --git a/monkestation/code/modules/antagonists/clock_cult/enchantments/blinding.dm b/monkestation/code/modules/antagonists/clock_cult/enchantments/blinding.dm deleted file mode 100644 index b9c33db999de..000000000000 --- a/monkestation/code/modules/antagonists/clock_cult/enchantments/blinding.dm +++ /dev/null @@ -1,17 +0,0 @@ -/datum/component/enchantment/blinding - examine_description = "It has been blessed with the power to emit a blinding light when striking a target." - max_level = 1 - -/datum/component/enchantment/blinding/Destroy() - UnregisterSignal(parent, COMSIG_ITEM_ATTACK) - return ..() - -/datum/component/enchantment/blinding/apply_effect(obj/item/target) - RegisterSignal(target, COMSIG_ITEM_ATTACK, PROC_REF(flash_target)) - -/datum/component/enchantment/blinding/proc/flash_target(datum/source, mob/living/target, mob/living/user) - if(!istype(target)) - return - var/obj/item/parent_item = parent - parent_item.visible_message(span_danger("\The [parent_item] emits a blinding light!")) - target.flash_act(2, affect_silicon = TRUE, length = 3 SECONDS) //might want to make this not effect borgs diff --git a/monkestation/code/modules/antagonists/clock_cult/enchantments/burn.dm b/monkestation/code/modules/antagonists/clock_cult/enchantments/burn.dm deleted file mode 100644 index 4494abd60880..000000000000 --- a/monkestation/code/modules/antagonists/clock_cult/enchantments/burn.dm +++ /dev/null @@ -1,18 +0,0 @@ -/datum/component/enchantment/burn - examine_description = "It has been blessed with the power of fire and will set struck targets on fire." - max_level = 3 - -/datum/component/enchantment/burn/Destroy() - UnregisterSignal(parent, COMSIG_ITEM_ATTACK) - return ..() - -/datum/component/enchantment/burn/apply_effect(obj/item/target) - target.damtype = BURN - RegisterSignal(target, COMSIG_ITEM_ATTACK, PROC_REF(burn_target)) - -/datum/component/enchantment/burn/proc/burn_target(datum/source, atom/movable/target, mob/living/user) - if(!isliving(target)) - return - var/mob/living/living_target = target - living_target.adjust_fire_stacks(level) - living_target.ignite_mob() diff --git a/monkestation/code/modules/antagonists/clock_cult/enchantments/electricution.dm b/monkestation/code/modules/antagonists/clock_cult/enchantments/electricution.dm deleted file mode 100644 index cba091575901..000000000000 --- a/monkestation/code/modules/antagonists/clock_cult/enchantments/electricution.dm +++ /dev/null @@ -1,19 +0,0 @@ -/datum/component/enchantment/electricution - max_level = 3 - examine_description = "It has been blessed with the power of electricity and will shock targets." - -/datum/component/enchantment/electricution/Destroy() - UnregisterSignal(parent, COMSIG_ITEM_ATTACK) - return ..() - -/datum/component/enchantment/electricution/apply_effect(obj/item/target) - RegisterSignal(target, COMSIG_ITEM_ATTACK, PROC_REF(shock_target)) - -/datum/component/enchantment/electricution/proc/shock_target(datum/source, atom/movable/target, mob/living/user) - user.Beam(target, icon_state = "lightning[rand(1,12)]", time = 2, maxdistance = 32) - if(!iscarbon(target)) - return - - var/mob/living/carbon/carbon_target = target - if(carbon_target.electrocute_act(level * 3, user, 1, SHOCK_NOSTUN)) - carbon_target.visible_message(span_danger("[user] electrocutes [target]!"), span_userdanger("[user] electrocutes you!")) diff --git a/monkestation/code/modules/antagonists/clock_cult/enchantments/soul_tap.dm b/monkestation/code/modules/antagonists/clock_cult/enchantments/soul_tap.dm deleted file mode 100644 index cb872cae2232..000000000000 --- a/monkestation/code/modules/antagonists/clock_cult/enchantments/soul_tap.dm +++ /dev/null @@ -1,18 +0,0 @@ -/datum/component/enchantment/soul_tap - examine_description = "It has been blessed with the power of ripping the energy from target's souls and will heal the wielder when a target is struck." - max_level = 3 - -/datum/component/enchantment/soul_tap/Destroy() - UnregisterSignal(parent, COMSIG_ITEM_ATTACK) - return ..() - -/datum/component/enchantment/soul_tap/apply_effect(obj/item/target) - RegisterSignal(target, COMSIG_ITEM_ATTACK, PROC_REF(tap_soul)) - -/datum/component/enchantment/soul_tap/proc/tap_soul(datum/source, mob/living/target, mob/living/user) - if(!istype(target) || target.stat != CONSCIOUS) - return - var/obj/item/parentItem = parent - var/health_back = CEILING(level * parentItem.force * 0.1, 1) - user.heal_overall_damage(health_back, health_back) - new /obj/effect/temp_visual/heal(get_turf(user), "#eeba6b") diff --git a/monkestation/code/modules/antagonists/clock_cult/enchantments/tiny.dm b/monkestation/code/modules/antagonists/clock_cult/enchantments/tiny.dm deleted file mode 100644 index a1068f56bfcb..000000000000 --- a/monkestation/code/modules/antagonists/clock_cult/enchantments/tiny.dm +++ /dev/null @@ -1,6 +0,0 @@ -/datum/component/enchantment/tiny - examine_description = "It has been blessed and distorts reality into a tiny space around it." - max_level = 1 - -/datum/component/enchantment/tiny/apply_effect(obj/item/target) - target.w_class = WEIGHT_CLASS_TINY diff --git a/monkestation/code/modules/antagonists/clock_cult/globals.dm b/monkestation/code/modules/antagonists/clock_cult/globals.dm index b3839ff9f8ff..3eedc6ea983e 100644 --- a/monkestation/code/modules/antagonists/clock_cult/globals.dm +++ b/monkestation/code/modules/antagonists/clock_cult/globals.dm @@ -2,7 +2,7 @@ GLOBAL_VAR_INIT(clock_power, 2500) GLOBAL_VAR_INIT(max_clock_power, 2500) // Increases with every APC cogged GLOBAL_VAR_INIT(clock_vitality, 100) //start with only a bit of vitality GLOBAL_VAR_INIT(clock_installed_cogs, 0) -GLOBAL_LIST_INIT(clock_turf_types, typesof(/turf/open/floor/bronze, /turf/open/indestructible/reebe_flooring, /turf/closed/wall/clockwork)) +GLOBAL_LIST_INIT(clock_turf_types, typesof(/turf/open/floor/bronze, /turf/open/indestructible/reebe_flooring, /turf/closed/wall/clockwork, /turf/open/floor/engine/clockwork)) GLOBAL_LIST_EMPTY(types_to_drop_on_clock_deonversion) //list of types to check for dropping on deconversion //CONVERT TO GLOBAL DATUM GLOBAL_VAR_INIT(narsie_breaching_rune, FALSE) //rune where nar'sie is trying to summon from, if it gets destroyed somehow then just summon her on a random station turf diff --git a/monkestation/code/modules/antagonists/clock_cult/helpers.dm b/monkestation/code/modules/antagonists/clock_cult/helpers.dm index 945eb2e1de0f..f6b32b69b00a 100644 --- a/monkestation/code/modules/antagonists/clock_cult/helpers.dm +++ b/monkestation/code/modules/antagonists/clock_cult/helpers.dm @@ -24,11 +24,18 @@ do_sparks(3, TRUE, servant) do_sparks(3, TRUE, target_turf) do_teleport(servant, target_turf, 0, no_effects = TRUE, channel = TELEPORT_CHANNEL_CULT, forced = TRUE) + to_chat(servant, "You warp to [get_area(target_turf)].") + if(!IS_CLOCK(servant) || !on_reebe(servant)) + servant.apply_status_effect(/datum/status_effect/clock_warp_sickness, 15 SECONDS) + if(ishuman(servant)) //looks weird on non-humanoids new /obj/effect/temp_visual/ratvar/warp(target_turf) - to_chat(servant, "You warp to [get_area(target_turf)].") + if(istype(pulled)) do_teleport(pulled, target_turf, 0, no_effects = TRUE, channel = TELEPORT_CHANNEL_CULT, forced = TRUE) if(!IS_CLOCK(pulled)) pulled.Paralyze(3 SECONDS) to_chat(pulled, span_warning("You feel sick and confused.")) + pulled.apply_status_effect(/datum/status_effect/clock_warp_sickness, 15 SECONDS) + else if(!on_reebe(pulled)) + pulled.apply_status_effect(/datum/status_effect/clock_warp_sickness, 15 SECONDS) diff --git a/monkestation/code/modules/antagonists/clock_cult/items/clock_stock_parts.dm b/monkestation/code/modules/antagonists/clock_cult/items/clock_stock_parts.dm index 17f52cb9b5e8..9cfe68b04b02 100644 --- a/monkestation/code/modules/antagonists/clock_cult/items/clock_stock_parts.dm +++ b/monkestation/code/modules/antagonists/clock_cult/items/clock_stock_parts.dm @@ -1,4 +1,4 @@ -//power cell that gets its power from GLOB.clock_power +//power cell that gets its power from SSthe_ark.clock_power /obj/item/stock_parts/cell/clock name = "Wound Power Cell" desc = "A bronze colored power cell. Is that a winding crank on the side?" //might make a real wind up powercell at some point for a joke item @@ -15,19 +15,19 @@ return ..() /obj/item/stock_parts/cell/clock/process(seconds_per_tick) - charge = GLOB.clock_power - maxcharge = GLOB.max_clock_power + charge = SSthe_ark.clock_power + maxcharge = SSthe_ark.max_clock_power //technically this means these cant be rigged with plasma /obj/item/stock_parts/cell/clock/use(used, force) - if(istype(loc, /obj/machinery/power/apc) || GLOB.clock_power < used) + if(istype(loc, /obj/machinery/power/apc) || SSthe_ark.clock_power < used) return FALSE SSblackbox.record_feedback("tally", "cell_used", 1, type) - GLOB.clock_power = max(GLOB.clock_power - used, 0) + SSthe_ark.clock_power = max(SSthe_ark.clock_power - used, 0) return TRUE /obj/item/stock_parts/cell/clock/percent() - return 100 * GLOB.clock_power / GLOB.max_clock_power + return 100 * SSthe_ark.clock_power / SSthe_ark.max_clock_power /obj/item/stock_parts/cell/clock/give(amount) //no return FALSE diff --git a/monkestation/code/modules/antagonists/clock_cult/items/clockwork_slab.dm b/monkestation/code/modules/antagonists/clock_cult/items/clockwork_slab.dm index 50aee2692681..bd2919958883 100644 --- a/monkestation/code/modules/antagonists/clock_cult/items/clockwork_slab.dm +++ b/monkestation/code/modules/antagonists/clock_cult/items/clockwork_slab.dm @@ -7,13 +7,14 @@ GLOBAL_LIST_INIT(clockwork_slabs, list()) icon = 'monkestation/icons/obj/clock_cult/clockwork_objects.dmi' /// Extra info to give clock cultists, added via the /datum/element/clockwork_description element var/clockwork_desc = "" - + /// Does this item get the clockwork_pickup element + var/has_pickup_element = TRUE /obj/item/clockwork/Initialize(mapload) . = ..() AddElement(/datum/element/clockwork_description, clockwork_desc) - AddElement(/datum/element/clockwork_pickup) - + if(has_pickup_element) + AddElement(/datum/element/clockwork_pickup) /obj/item/clockwork/clockwork_slab name = "Clockwork Slab" @@ -24,6 +25,7 @@ GLOBAL_LIST_INIT(clockwork_slabs, list()) lefthand_file = 'monkestation/icons/mob/clock_cult/clockwork_lefthand.dmi' righthand_file = 'monkestation/icons/mob/clock_cult/clockwork_righthand.dmi' w_class = WEIGHT_CLASS_TINY + has_pickup_element = FALSE /// The scripture currently being invoked var/datum/scripture/invoking_scripture @@ -132,10 +134,11 @@ GLOBAL_LIST_INIT(clockwork_slabs, list()) quickbound.Grant(binder) // UI things below - /obj/item/clockwork/clockwork_slab/attack_self(mob/living/user) if(!IS_CLOCK(user)) - to_chat(user, span_warning("You cannot figure out what the device is used for!")) + to_chat(user, span_warning("As you try and fiddle with \the [src] you feel a shock course through you!")) + user.dropItemToGround(user, TRUE) + user.electrocute_act((IS_CULTIST(user) ? 40 : 20), src, 1, SHOCK_NOGLOVES|SHOCK_SUPPRESS_MESSAGE) return if(active_scripture) @@ -163,8 +166,8 @@ GLOBAL_LIST_INIT(clockwork_slabs, list()) data["cogs"] = cogs data["vitality"] = GLOB.clock_vitality data["max_vitality"] = MAX_CLOCK_VITALITY - data["power"] = GLOB.clock_power - data["max_power"] = GLOB.max_clock_power + data["power"] = SSthe_ark.clock_power + data["max_power"] = SSthe_ark.max_clock_power data["scriptures"] = list() //2 scriptures accessible at the same time will cause issues @@ -194,7 +197,7 @@ GLOBAL_LIST_INIT(clockwork_slabs, list()) return var/mob/living/living_user = usr - if(!istype(living_user)) + if(!istype(living_user) || !IS_CLOCK(living_user)) return FALSE switch(action) @@ -209,7 +212,7 @@ GLOBAL_LIST_INIT(clockwork_slabs, list()) living_user.balloon_alert(living_user, "failed to invoke!") return FALSE - if(owned_scripture.power_cost > GLOB.clock_power) + if(owned_scripture.power_cost > SSthe_ark.clock_power) living_user.balloon_alert(living_user, "[owned_scripture.power_cost]W required!") return FALSE diff --git a/monkestation/code/modules/antagonists/clock_cult/items/integration_cog.dm b/monkestation/code/modules/antagonists/clock_cult/items/integration_cog.dm index 70ba4f780d84..d290742406cd 100644 --- a/monkestation/code/modules/antagonists/clock_cult/items/integration_cog.dm +++ b/monkestation/code/modules/antagonists/clock_cult/items/integration_cog.dm @@ -43,7 +43,7 @@ playsound(get_turf(user), 'sound/machines/clockcult/integration_cog_install.ogg', 20) if(!cogger_apc.clock_cog_rewarded) GLOB.clock_installed_cogs++ - GLOB.max_clock_power += MAX_POWER_PER_COG + SSthe_ark.max_clock_power += MAX_POWER_PER_COG cogger_apc.clock_cog_rewarded = TRUE send_clock_message(null, span_brass(span_bold("[user.real_name] has installed an integration cog into [cogger_apc].")), msg_ghosts = TRUE) //Update the cog counts diff --git a/monkestation/code/modules/antagonists/clock_cult/items/replica_fabricator.dm b/monkestation/code/modules/antagonists/clock_cult/items/replica_fabricator.dm index ab31f805f4ec..b0a9a17fd1a7 100644 --- a/monkestation/code/modules/antagonists/clock_cult/items/replica_fabricator.dm +++ b/monkestation/code/modules/antagonists/clock_cult/items/replica_fabricator.dm @@ -1,7 +1,5 @@ #define BRASS_POWER_COST 10 #define REGULAR_POWER_COST (BRASS_POWER_COST / 2) -//how much to add to the creation_delay while the cult lacks a charged anchoring crystal -#define SLOWDOWN_FROM_NO_ANCHOR_CRYSTAL 0.2 /obj/item/clockwork/replica_fabricator name = "replica fabricator" @@ -37,7 +35,7 @@ /obj/item/clockwork/replica_fabricator/examine(mob/user) . = ..() if(IS_CLOCK(user)) - . += span_brass("Current power: [display_power(GLOB.clock_power)]") + . += span_brass("Current power: [display_power(SSthe_ark.clock_power)]") . += span_brass("Use on brass to convert it into power.") . += span_brass("Use on other materials to convert them into power, but less efficiently.") . += span_brass("Use in-hand to select what to fabricate.") @@ -57,12 +55,12 @@ if(!selected_output) // Now we handle objects return - if(GLOB.clock_power < selected_output.cost) + if(SSthe_ark.clock_power < selected_output.cost) to_chat(user, span_clockyellow("[src] needs at least [selected_output.cost]W of power to create this.")) return var/turf/creation_turf = get_turf(target) - var/atom/movable/possible_replaced + var/atom/movable/replaced if(locate(selected_output.to_create_path) in creation_turf) to_chat(user, span_clockyellow("There is already one of these on this tile!")) return @@ -74,35 +72,37 @@ for(var/checked_type in selected_output.replace_types_of) var/atom/movable/found_replaced = locate(checked_type) in creation_turf if(found_replaced) - possible_replaced = found_replaced + replaced = found_replaced break - if(!possible_replaced && !isopenturf(target)) + if(!replaced && !isopenturf(target)) return else if(!isopenturf(target)) return - var/calculated_creation_delay = 1 + if(!selected_output.extra_checks(target, creation_turf, user)) + return + + var/creation_delay_mult = 1 if(on_reebe(user)) - calculated_creation_delay = selected_output.reebe_mult - if(!get_charged_anchor_crystals()) - calculated_creation_delay += SLOWDOWN_FROM_NO_ANCHOR_CRYSTAL - else if(GLOB.clock_ark?.current_state >= ARK_STATE_ACTIVE) - calculated_creation_delay += (iscogscarab(user) ? 2.5 : 5) - calculated_creation_delay = selected_output.creation_delay * calculated_creation_delay - - var/obj/effect/temp_visual/ratvar/constructing_effect/effect = new(creation_turf, calculated_creation_delay) - if(!do_after(user, calculated_creation_delay, target)) + creation_delay_mult += selected_output.reebe_mult + if(GLOB.clock_ark?.current_state >= ARK_STATE_ACTIVE) + creation_delay_mult += (iscogscarab(user) ? 2.5 : 5) + if(replaced) + creation_delay_mult += selected_output.replacement_mult + + var/selected_creation_delay = selected_output.creation_delay * max(creation_delay_mult, 0.1) + var/obj/effect/temp_visual/ratvar/constructing_effect/effect = new(creation_turf, selected_creation_delay) + if(!do_after(user, selected_creation_delay, target)) qdel(effect) return - if(GLOB.clock_power < selected_output.cost) // Just in case + if(!SSthe_ark.adjust_clock_power(-selected_output.cost)) return - GLOB.clock_power -= selected_output.cost var/atom/created - if(!istype(selected_output, /datum/replica_fabricator_output/turf_output)) - if(possible_replaced) - qdel(possible_replaced) + if(!ispath(selected_output.to_create_path, /turf)) + if(replaced) + qdel(replaced) created = new selected_output.to_create_path(creation_turf) selected_output.on_create(created, creation_turf, user) @@ -121,15 +121,15 @@ if(!IS_CLOCK(user)) return - if(GLOB.clock_power < BRASS_POWER_COST) + if(SSthe_ark.clock_power < BRASS_POWER_COST) to_chat(user, span_clockyellow("You need at least [BRASS_POWER_COST]W of power to fabricate bronze.")) return - var/sheets = tgui_input_number(user, "How many sheets do you want to fabricate?", "Sheet Fabrication", 0, round(GLOB.clock_power / BRASS_POWER_COST), 0) + var/sheets = tgui_input_number(user, "How many sheets do you want to fabricate?", "Sheet Fabrication", 0, round(SSthe_ark.clock_power / BRASS_POWER_COST), 0) if(!sheets) return - GLOB.clock_power -= sheets * BRASS_POWER_COST + SSthe_ark.clock_power -= sheets * BRASS_POWER_COST var/obj/item/stack/sheet/bronze/sheet_stack = new(null, sheets) user.put_in_hands(sheet_stack) @@ -140,7 +140,6 @@ /obj/item/clockwork/replica_fabricator/attack_self(mob/user, modifiers) . = ..() var/choice = show_radial_menu(user, src, crafting_possibilities, radius = 36, custom_check = PROC_REF(check_menu), require_near = TRUE) - if(!choice) return @@ -149,35 +148,32 @@ /// Standard confirmation for the radial menu proc /obj/item/clockwork/replica_fabricator/proc/check_menu(mob/user) - if(!istype(user)) - return FALSE - - if(user.incapacitated()) + if(!istype(user) || user.incapacitated()) return FALSE return TRUE /// Attempt to convert the targeted item into power, if it's a sheet item /obj/item/clockwork/replica_fabricator/proc/attempt_convert_materials(atom/attacking_item, mob/user) - if(GLOB.clock_power >= GLOB.max_clock_power) + if(SSthe_ark.clock_power >= SSthe_ark.max_clock_power) to_chat(user, span_clockyellow("We are already at maximum power!")) return if(istype(attacking_item, /obj/item/stack/sheet/bronze)) var/obj/item/stack/bronze_stack = attacking_item - if((GLOB.clock_power + bronze_stack.amount * BRASS_POWER_COST) > GLOB.max_clock_power) - var/amount_to_take = clamp(round((GLOB.max_clock_power - GLOB.clock_power) / BRASS_POWER_COST), 0, bronze_stack.amount) + if((SSthe_ark.clock_power + bronze_stack.amount * BRASS_POWER_COST) > SSthe_ark.max_clock_power) + var/amount_to_take = clamp(round((SSthe_ark.max_clock_power - SSthe_ark.clock_power) / BRASS_POWER_COST), 0, bronze_stack.amount) if(!amount_to_take) to_chat(user, span_clockyellow("[src] can't be powered further using this!")) return bronze_stack.use(amount_to_take) - GLOB.clock_power += amount_to_take * BRASS_POWER_COST + SSthe_ark.clock_power += amount_to_take * BRASS_POWER_COST else - GLOB.clock_power += bronze_stack.amount * BRASS_POWER_COST + SSthe_ark.clock_power += bronze_stack.amount * BRASS_POWER_COST qdel(bronze_stack) playsound(src, 'sound/machines/click.ogg', 50, 1) @@ -188,18 +184,18 @@ else if(istype(attacking_item, /obj/item/stack/sheet)) var/obj/item/stack/stack = attacking_item - if((GLOB.clock_power + stack.amount * REGULAR_POWER_COST) > GLOB.max_clock_power) - var/amount_to_take = clamp(round((GLOB.max_clock_power - GLOB.clock_power) / REGULAR_POWER_COST), 0, stack.amount) + if((SSthe_ark.clock_power + stack.amount * REGULAR_POWER_COST) > SSthe_ark.max_clock_power) + var/amount_to_take = clamp(round((SSthe_ark.max_clock_power - SSthe_ark.clock_power) / REGULAR_POWER_COST), 0, stack.amount) if(!amount_to_take) to_chat(user, span_clockyellow("[src] can't be powered further using this!")) return stack.use(amount_to_take) - GLOB.clock_power += amount_to_take * REGULAR_POWER_COST + SSthe_ark.clock_power += amount_to_take * REGULAR_POWER_COST else - GLOB.clock_power += stack.amount * REGULAR_POWER_COST + SSthe_ark.clock_power += stack.amount * REGULAR_POWER_COST qdel(stack) playsound(src, 'sound/machines/click.ogg', 50, 1) @@ -228,8 +224,10 @@ var/creation_delay = 1 SECONDS /// List of objs this output can replace, normal walls for clock walls, windows for clock windows, ETC var/list/replace_types_of - /// Multiplier for creation_delay when used on reebe - var/reebe_mult = 1 + /// Multiplier to add to creation_delay when used on reebe + var/reebe_mult = 0 + /// Multiplier to add to creation_delay when replacing an object in replace_types_of + var/replacement_mult = 0 /// Any extra actions that need to be taken when an object is created /datum/replica_fabricator_output/proc/on_create(atom/created_atom, turf/creation_turf, mob/creator) @@ -237,31 +235,51 @@ playsound(creation_turf, 'sound/machines/clockcult/integration_cog_install.ogg', 50, 1) // better sound? to_chat(creator, span_clockyellow("You create \an [name] for [cost]W of power.")) +/datum/replica_fabricator_output/proc/extra_checks(atom/target, turf/created_at, mob/user) + return TRUE + +/datum/replica_fabricator_output/turf_output/extra_checks(atom/target, turf/creation_turf, mob/user) + return !(creation_turf.resistance_flags & INDESTRUCTIBLE) + /datum/replica_fabricator_output/turf_output/on_create(atom/created_atom, turf/creation_turf, mob/creator) - creation_turf.ChangeTurf(to_create_path) + creation_turf.ChangeTurf(to_create_path, flags = CHANGETURF_INHERIT_AIR) return ..() /datum/replica_fabricator_output/turf_output/brass_floor name = "floor" cost = BRASS_POWER_COST * 0.25 // 1/4th the cost, since one sheet = 4 floor tiles - to_create_path = /turf/open/floor/bronze + creation_delay = 3 SECONDS + to_create_path = /turf/open/floor/engine/clockwork -/datum/replica_fabricator_output/turf_output/brass_floor/on_create(obj/created_object, turf/creation_turf, mob/creator) - . = ..() +/datum/replica_fabricator_output/turf_output/brass_floor/extra_checks(atom/target, turf/creation_turf, mob/user) + return !isindestructiblefloor(creation_turf) && !istype(creation_turf, /turf/open/floor/cult) && !istype(creation_turf, /turf/open/floor/engine/clockwork) && ..() +/datum/replica_fabricator_output/turf_output/brass_floor/on_create(atom/created_atom, turf/creation_turf, mob/creator, looping = FALSE) + . = ..() new /obj/effect/temp_visual/ratvar/floor(creation_turf) new /obj/effect/temp_visual/ratvar/beam(creation_turf) + if(looping) + return + + for(var/turf/open/floor/floor_turf in RANGE_TURFS(1, creation_turf)) //NOT WORKING? + if(extra_checks(created_atom, floor_turf, creator)) + if(!SSthe_ark.adjust_clock_power(-cost)) + break + on_create(created_atom, floor_turf, creator, TRUE) + /datum/replica_fabricator_output/turf_output/brass_wall name = "wall" cost = BRASS_POWER_COST * 4 to_create_path = /turf/closed/wall/clockwork creation_delay = 14 SECONDS - replace_types_of = list(/turf/closed/wall) + replace_types_of = list(/turf/closed/wall, /turf/closed/wall/r_wall) + replacement_mult = -0.2 /datum/replica_fabricator_output/turf_output/brass_wall/on_create(obj/created_object, turf/creation_turf, mob/creator) . = ..() new /obj/effect/temp_visual/ratvar/wall(creation_turf) new /obj/effect/temp_visual/ratvar/beam(creation_turf) + /datum/replica_fabricator_output/wall_gear name = "wall gear" cost = BRASS_POWER_COST * 2 @@ -280,7 +298,7 @@ to_create_path = /obj/structure/window/reinforced/clockwork/fulltile creation_delay = 10 SECONDS replace_types_of = list(/obj/structure/window) - reebe_mult = 1.2 + reebe_mult = 0.2 /datum/replica_fabricator_output/brass_window/on_create(obj/created_object, turf/creation_turf, mob/creator) new /obj/effect/temp_visual/ratvar/window(creation_turf) @@ -292,6 +310,14 @@ cost = BRASS_POWER_COST * 5 // Breaking it only gets 2 but this is the exception to the rule of equivalent exchange, due to all the small parts inside to_create_path = /obj/machinery/door/airlock/bronze/clock creation_delay = 10 SECONDS + replace_types_of = list(/obj/machinery/door) + replacement_mult = 1 + +/datum/replica_fabricator_output/pinion_airlock/extra_checks(atom/target, turf/created_at, mob/user) + if(on_reebe(created_at) && SSthe_ark.reebe_clockwork_airlock_count > MAXIMUM_REEBE_AIRLOCKS) + to_chat(user, span_warning("Reebe cannot support the power drain of any more clockwork airlocks.")) + return FALSE + return TRUE /datum/replica_fabricator_output/pinion_airlock/on_create(obj/created_object, turf/creation_turf, mob/creator) new /obj/effect/temp_visual/ratvar/door(creation_turf) @@ -304,4 +330,3 @@ #undef BRASS_POWER_COST #undef REGULAR_POWER_COST -#undef SLOWDOWN_FROM_NO_ANCHOR_CRYSTAL diff --git a/monkestation/code/modules/antagonists/clock_cult/items/soul_vessel.dm b/monkestation/code/modules/antagonists/clock_cult/items/soul_vessel.dm index c512a9dffc5a..b9150357c17a 100644 --- a/monkestation/code/modules/antagonists/clock_cult/items/soul_vessel.dm +++ b/monkestation/code/modules/antagonists/clock_cult/items/soul_vessel.dm @@ -1,6 +1,6 @@ /obj/item/mmi/posibrain/soul_vessel name = "Soul Vessel" - desc = "A cube made of gear, made to capture and store the vitality of living beings." + desc = "A cube of gears, made to capture and store the vitality of living beings." icon = 'monkestation/icons/obj/clock_cult/clockwork_objects.dmi' icon_state = "soul_vessel" base_icon_state = "soul_vessel" @@ -16,6 +16,7 @@ /obj/item/mmi/posibrain/soul_vessel/Initialize(mapload, autoping) . = ..() + AddElement(/datum/element/clockwork_description, span_brass("A vessel used to hold the souls of the dead, can be converted into a cogscarab shell.")) laws = new /datum/ai_laws/ratvar() radio.set_on(FALSE) if(!brainmob) //we might be forcing someone into it right away @@ -30,6 +31,41 @@ brainmob?.mind?.add_antag_datum(/datum/antagonist/clock_cultist) /obj/item/mmi/posibrain/soul_vessel/activate(mob/user) - if(is_banned_from(user.ckey, ROLE_CLOCK_CULTIST)) + if(is_banned_from(user.ckey, list(JOB_CYBORG, ROLE_CLOCK_CULTIST))) return - . = ..() + return ..() + +/obj/item/mmi/posibrain/soul_vessel/attack_self(mob/user) + if(!IS_CLOCK(user)) + balloon_alert(user, "You can't seem to figure out how \the [src] works!") + return + + if(brainmob.key && brainmob.mind) + if(length(SSthe_ark.cogscarabs) > MAXIMUM_COGSCARABS) + balloon_alert(user, "The Ark cannot support any more cogscarabs.") + return + + if(!SSthe_ark.marked_areas[get_area(src)] && !on_reebe(src)) + to_chat(user, span_notice("Soul vessels can only be converted in marked areas or on reebe.")) + return + + balloon_alert(user, "You start converting the vessel into a cogscarab shell.") + if(do_after(user, 30 SECONDS, src)) + var/mob/living/basic/drone/cogscarab/new_scarab = new(get_turf(src)) + brainmob.mind.transfer_to(new_scarab, TRUE) + if(!IS_CLOCK(new_scarab)) + new_scarab.mind.add_antag_datum(/datum/antagonist/clock_cultist) + balloon_alert(user, "You reform [src] into a cogscarab shell.") + qdel(src) + return + + if(next_ask > world.time) + balloon_alert(user, recharge_message) + return + + balloon_alert(user, begin_activation_message) + ping_ghosts("requested", FALSE) + next_ask = world.time + ask_delay + searching = TRUE + update_appearance() + addtimer(CALLBACK(src, PROC_REF(check_success)), ask_delay) diff --git a/monkestation/code/modules/antagonists/clock_cult/items/weaponry.dm b/monkestation/code/modules/antagonists/clock_cult/items/weaponry.dm index 46272ff1f3c5..b7a66c80c199 100644 --- a/monkestation/code/modules/antagonists/clock_cult/items/weaponry.dm +++ b/monkestation/code/modules/antagonists/clock_cult/items/weaponry.dm @@ -179,6 +179,7 @@ desc = "A brass hammer glowing with energy." base_icon_state = "ratvarian_hammer" icon_state = "ratvarian_hammer0" + force = 15 throwforce = 25 armour_penetration = 6 attack_verb_simple = list("bash", "hammer", "attack", "smash") diff --git a/monkestation/code/modules/antagonists/clock_cult/structures/airlock.dm b/monkestation/code/modules/antagonists/clock_cult/machines/airlock.dm similarity index 77% rename from monkestation/code/modules/antagonists/clock_cult/structures/airlock.dm rename to monkestation/code/modules/antagonists/clock_cult/machines/airlock.dm index 03f2b7979419..da3afce49efd 100644 --- a/monkestation/code/modules/antagonists/clock_cult/structures/airlock.dm +++ b/monkestation/code/modules/antagonists/clock_cult/machines/airlock.dm @@ -9,12 +9,19 @@ hackProof = TRUE aiControlDisabled = AI_WIRE_DISABLED req_access = list(ACCESS_CLOCKCULT) - damage_deflection = 10 + damage_deflection = 7 /obj/machinery/door/airlock/bronze/clock/Initialize(mapload) . = ..() if(on_reebe(src)) damage_deflection = 0 + if(!mapload) + SSthe_ark.reebe_clockwork_airlock_count++ + +/obj/machinery/door/airlock/bronze/clock/Destroy() + if(on_reebe(src)) + SSthe_ark.reebe_clockwork_airlock_count-- + return ..() /obj/machinery/door/airlock/bronze/clock/canAIControl(mob/user) return (IS_CLOCK(user) && !isAllPowerCut()) @@ -39,14 +46,17 @@ return TRUE else if(!on_reebe(src)) - user.Paralyze(2 SECONDS) - user.electrocute_act(20, src, 1, SHOCK_NOGLOVES|SHOCK_SUPPRESS_MESSAGE) + user.Paralyze(1 SECONDS) + user.electrocute_act(10, src, 1, SHOCK_NOGLOVES|SHOCK_SUPPRESS_MESSAGE) to_chat(user, span_warning("You feel a sudden jolt as you touch [src]!")) return FALSE /obj/machinery/door/airlock/bronze/clock/emp_act(severity) return +/obj/machinery/door/airlock/bronze/clock/emag_act(mob/user, obj/item/card/emag/emag_card) //emags are magical but not THAT magical + return FALSE + /obj/machinery/door/airlock/bronze/clock/glass name = "clear bronze airlock" assemblytype = /obj/structure/door_assembly/door_assembly_bronze/seethru/clock diff --git a/monkestation/code/modules/antagonists/clock_cult/machines/observation_console.dm b/monkestation/code/modules/antagonists/clock_cult/machines/observation_console.dm index 072a13c80225..bd58a7055584 100644 --- a/monkestation/code/modules/antagonists/clock_cult/machines/observation_console.dm +++ b/monkestation/code/modules/antagonists/clock_cult/machines/observation_console.dm @@ -1,6 +1,3 @@ -//if its not enough I could also make it so it takes longer to abscond from other areas -GLOBAL_LIST_EMPTY(clock_warp_areas) - /obj/machinery/computer/camera_advanced/ratvar name = "Ratvarian Observation Console" desc = "Used by the servants of Rat'var to conduct operations on Nanotrasen property." @@ -17,10 +14,7 @@ GLOBAL_LIST_EMPTY(clock_warp_areas) START_PROCESSING(SSobj, src) actions += new /datum/action/innate/clockcult/warp(src) actions += new /datum/action/innate/clockcult/show_warpable_areas(src) - var/datum/action/innate/clockcult/add_warp_area/add_area = new(src) - actions += add_area - if(!length(GLOB.clock_warp_areas)) - add_area.choose_starting_warp_areas() //slightly hacky but handling it on the action is cheaper as it lets us just build our warpable areas once without needing globals + actions += new /datum/action/innate/clockcult/add_warp_area(src) /obj/machinery/computer/camera_advanced/ratvar/Destroy() STOP_PROCESSING(SSobj, src) @@ -76,8 +70,8 @@ GLOBAL_LIST_EMPTY(clock_warp_areas) var/mob/camera/ai_eye/remote/cam = cam_user.remote_control var/turf/target_loc = get_turf(cam) var/area/target_area = get_area(target_loc) - if(!(target_area in GLOB.clock_warp_areas)) - to_chat(owner, span_brass("This area is not currently warpable.")) + if(!(SSthe_ark.marked_areas[target_area])) + to_chat(owner, span_brass("This area is not marked.")) return if(isclosedturf(target_loc)) diff --git a/monkestation/code/modules/antagonists/clock_cult/mobs/clock_borgs/clock_borg_modules.dm b/monkestation/code/modules/antagonists/clock_cult/mobs/clock_borgs/clock_borg_modules.dm index 50dea311e05c..a735acedfa4c 100644 --- a/monkestation/code/modules/antagonists/clock_cult/mobs/clock_borgs/clock_borg_modules.dm +++ b/monkestation/code/modules/antagonists/clock_cult/mobs/clock_borgs/clock_borg_modules.dm @@ -38,7 +38,7 @@ to_chat(user, span_userdanger("You dont have an internal slab, this should not be the case and you should tell an admin with an ahelp(f1).")) return FALSE - if(internal_slab.invoking_scripture || (scripture_datum.power_cost > GLOB.clock_power)) + if(internal_slab.invoking_scripture || (scripture_datum.power_cost > SSthe_ark.clock_power)) to_chat(user, span_brass("You fail to invoke [name].")) return FALSE diff --git a/monkestation/code/modules/antagonists/clock_cult/mobs/clockwork_marauder.dm b/monkestation/code/modules/antagonists/clock_cult/mobs/clockwork_marauder.dm index ca83e7193259..85dd61597bde 100644 --- a/monkestation/code/modules/antagonists/clock_cult/mobs/clockwork_marauder.dm +++ b/monkestation/code/modules/antagonists/clock_cult/mobs/clockwork_marauder.dm @@ -1,21 +1,17 @@ #define MARAUDER_SHIELD_MAX 5 -#define WELDER_REPAIR_AMOUNT 15 - -GLOBAL_LIST_EMPTY(clockwork_marauders) - +#define WELDER_REPAIR_AMOUNT 25 /mob/living/basic/clockwork_marauder name = "clockwork marauder" desc = "A brass machine of destruction." icon = 'monkestation/icons/mob/clock_cult/clockwork_mobs.dmi' icon_state = "clockwork_marauder" icon_living = "clockwork_marauder" - mob_biotypes = MOB_ORGANIC|MOB_HUMANOID + mob_biotypes = MOB_HUMANOID|MOB_ROBOTIC|MOB_SPIRIT sentience_type = SENTIENCE_HUMANOID - maxHealth = 140 - health = 140 + maxHealth = 150 + health = 150 basic_mob_flags = DEL_ON_DEATH - speed = 1.25 - environment_smash = ENVIRONMENT_SMASH_STRUCTURES + speed = 1.2 melee_damage_lower = 24 melee_damage_upper = 24 attack_verb_continuous = "slices" @@ -46,10 +42,10 @@ GLOBAL_LIST_EMPTY(clockwork_marauders) . = ..() if(length(loot)) AddElement(/datum/element/death_drops, loot) - GLOB.clockwork_marauders += src + SSthe_ark.clockwork_marauders += src /mob/living/basic/clockwork_marauder/Destroy() - GLOB.clockwork_marauders -= src + SSthe_ark.clockwork_marauders -= src return ..() /mob/living/basic/clockwork_marauder/examine(mob/user) @@ -61,22 +57,22 @@ GLOBAL_LIST_EMPTY(clockwork_marauders) . += span_brass("It can be repaired with a welding tool.") /mob/living/basic/clockwork_marauder/UnarmedAttack(atom/attack_target, proximity_flag) - var/obj/structure/destructible/clockwork/structure = attack_target - if(istype(structure) && structure.immune_to_servant_attacks) + var/obj/structure/destructible/clockwork/gear_base/powered/structure = attack_target + if(istype(structure) && istate != ISTATE_HARM) + structure.try_toggle_power(src) return ATTACK_DO_NOTHING - . = ..() + return ..() /mob/living/basic/clockwork_marauder/attacked_by(obj/item/attacking_item, mob/living/user) - if(shield_health) + if(shield_health && attacking_item.force > 0) damage_shield() - playsound(src, 'sound/hallucinations/veryfar_noise.ogg', 40, 1) + return if(attacking_item == TOOL_WELDER) welder_act(user, attacking_item) return - return ..() /mob/living/basic/clockwork_marauder/bullet_act(obj/projectile/proj) diff --git a/monkestation/code/modules/antagonists/clock_cult/mobs/cogscarab.dm b/monkestation/code/modules/antagonists/clock_cult/mobs/cogscarab.dm index 54d9d8c89249..f6935f6fbdc8 100644 --- a/monkestation/code/modules/antagonists/clock_cult/mobs/cogscarab.dm +++ b/monkestation/code/modules/antagonists/clock_cult/mobs/cogscarab.dm @@ -1,5 +1,3 @@ -GLOBAL_LIST_EMPTY(cogscarabs) - #define CLOCK_DRONE_MAX_ITEM_FORCE 15 //====Cogscarab==== @@ -12,6 +10,7 @@ GLOBAL_LIST_EMPTY(cogscarabs) icon_dead = "drone_clock_dead" health = 35 maxHealth = 35 + speed = 1 faction = list(FACTION_NEUTRAL, FACTION_SILICON, FACTION_TURRET, FACTION_CLOCK) default_storage = /obj/item/storage/belt/utility/clock/drone visualAppearance = CLOCKDRONE @@ -27,34 +26,45 @@ GLOBAL_LIST_EMPTY(cogscarabs) chat_color = LIGHT_COLOR_CLOCKWORK initial_language_holder = /datum/language_holder/clockmob shy = FALSE - ///var for in case admins want a cogsarab to stay off reebe for some reason - var/stay_on_reebe = TRUE + var/is_on_reebe = TRUE //No you can't go wielding guns like that. /mob/living/basic/drone/cogscarab/Initialize(mapload) . = ..() ADD_TRAIT(src, TRAIT_NOGUNS, "cogscarab") - GLOB.cogscarabs += src - add_actionspeed_modifier(/datum/actionspeed_modifier/cogscarab) - -/datum/actionspeed_modifier/cogscarab - multiplicative_slowdown = 0.6 + SSthe_ark.cogscarabs += src + add_actionspeed_modifier(/datum/actionspeed_modifier/cogscarab, TRUE) + check_on_reebe() /mob/living/basic/drone/cogscarab/death(gibbed) - GLOB.cogscarabs -= src + SSthe_ark.cogscarabs -= src return ..() -/mob/living/basic/drone/cogscarab/Life(seconds, times_fired) - if(!on_reebe(src) && !GLOB.ratvar_risen && length(GLOB.abscond_markers) && stay_on_reebe) - try_servant_warp(src, get_turf(pick(GLOB.abscond_markers))) - . = ..() - /mob/living/basic/drone/cogscarab/Destroy() - GLOB.cogscarabs -= src + SSthe_ark.cogscarabs -= src return ..() /mob/living/basic/drone/cogscarab/transferItemToLoc(obj/item/item, newloc, force, silent) //ideally I would handle this on attacking instead - return (item.force <= CLOCK_DRONE_MAX_ITEM_FORCE) && ..() + return (force || (item.force <= CLOCK_DRONE_MAX_ITEM_FORCE)) && ..() + +/mob/living/basic/drone/cogscarab/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change) + . = ..() + check_on_reebe() + +/mob/living/basic/drone/cogscarab/proc/check_on_reebe() + var/old_value = is_on_reebe + is_on_reebe = on_reebe(src) + if(old_value != is_on_reebe) + if(is_on_reebe) + remove_movespeed_modifier(/datum/movespeed_modifier/cogscarab_off_reebe, TRUE) + else + add_movespeed_modifier(/datum/movespeed_modifier/cogscarab_off_reebe, TRUE) + +/datum/actionspeed_modifier/cogscarab + multiplicative_slowdown = 0.6 + +/datum/movespeed_modifier/cogscarab_off_reebe + multiplicative_slowdown = 0.7 //====Shell==== @@ -72,14 +82,27 @@ GLOBAL_LIST_EMPTY(cogscarabs) you have a set of quick tools, as well as a replica fabricator that can create brass for construction. Work with the servants of Rat'var \ to construct and maintain defenses at the City of Cogs." +/obj/effect/mob_spawn/ghost_role/drone/cogscarab/Initialize(mapload) + . = ..() + SSthe_ark.cogscarabs += src + AddElement(/datum/element/clockwork_description, "Cogscarabs can only gain a soul in marked areas.") + +/obj/effect/mob_spawn/ghost_role/drone/cogscarab/Destroy() + SSthe_ark.cogscarabs -= src + return ..() + /obj/effect/mob_spawn/ghost_role/drone/cogscarab/special(mob/living/spawned_mob, mob/mob_possessor) . = ..() spawned_mob.flags_1 |= (flags_1 & ADMIN_SPAWNED_1) - spawned_mob.mind.add_antag_datum(/datum/antagonist/clock_cultist) + spawned_mob.mind.add_antag_datum(/datum/antagonist/clock_cultist/clockmob) /obj/effect/mob_spawn/ghost_role/drone/cogscarab/allow_spawn(mob/user, silent) - if(length(GLOB.cogscarabs) > MAXIMUM_COGSCARABS) - to_chat(user, span_notice("The cult currently has its maximum amount of cogscarabs.")) + if(length(SSthe_ark.cogscarabs) > MAXIMUM_COGSCARABS) + to_chat(user, span_notice("The Ark cannot support any more cogscarabs.")) + return FALSE + + if(!SSthe_ark.marked_areas[get_area(src)] && !on_reebe(src)) + to_chat(user, span_notice("Cogscarabs can only spawn in marked areas or on reebe.")) return FALSE return TRUE diff --git a/monkestation/code/modules/antagonists/clock_cult/pickup_element.dm b/monkestation/code/modules/antagonists/clock_cult/pickup_element.dm index 66632d422e7f..8e732c1f115d 100644 --- a/monkestation/code/modules/antagonists/clock_cult/pickup_element.dm +++ b/monkestation/code/modules/antagonists/clock_cult/pickup_element.dm @@ -1,6 +1,6 @@ #define REGULAR_PICKUP_MOD 1 #define CULTIST_PICKUP_MOD 2 -#define PICKUP_SHOCK_DAMAGE 25 +#define PICKUP_SHOCK_DAMAGE 20 /datum/element/clockwork_pickup element_flags = ELEMENT_BESPOKE | ELEMENT_DETACH_ON_HOST_DESTROY @@ -9,7 +9,6 @@ /// What slots will attempt to shock the equpper var/list/equip_slots = list() - /datum/element/clockwork_pickup/Attach(datum/target, list/slots_to_count) . = ..() @@ -24,7 +23,6 @@ if(!locate(target.type) in GLOB.types_to_drop_on_clock_deonversion) GLOB.types_to_drop_on_clock_deonversion |= target.type - /datum/element/clockwork_pickup/Detach(datum/target) . = ..() UnregisterSignal(target, COMSIG_ITEM_EQUIPPED) @@ -38,22 +36,20 @@ * * equipper - The mob that picked up the item * * slot - The slot the item was equipped in, unused */ -/datum/element/clockwork_pickup/proc/attempt_shock(obj/item/source, mob/equipper, slot) +/datum/element/clockwork_pickup/proc/attempt_shock(obj/item/source, mob/living/equipper, slot) SIGNAL_HANDLER - if(IS_CLOCK(equipper) || !isliving(equipper) || (length(equip_slots) && !(slot in equip_slots))) + if(!isliving(equipper) || IS_CLOCK(equipper) || (length(equip_slots) && !(slot in equip_slots))) return - var/mob/living/equipper_living = equipper var/power_multiplier = REGULAR_PICKUP_MOD - - if(IS_CULTIST(equipper_living)) + if(IS_CULTIST(equipper)) power_multiplier = CULTIST_PICKUP_MOD - to_chat(equipper_living, span_warning("As you [slot == ITEM_SLOT_HANDS ? "touch" : "equip"] [source], you feel a jolt course through you!")) + to_chat(equipper, span_warning("As you [slot == ITEM_SLOT_HANDS ? "touch" : "equip"] [source], you feel a jolt course through you!")) - equipper_living.dropItemToGround(source, TRUE) - equipper_living.electrocute_act(PICKUP_SHOCK_DAMAGE * power_multiplier, src, 1, SHOCK_NOGLOVES|SHOCK_SUPPRESS_MESSAGE) + equipper.dropItemToGround(source, TRUE) + equipper.electrocute_act(PICKUP_SHOCK_DAMAGE * power_multiplier, src, 1, SHOCK_NOGLOVES|SHOCK_SUPPRESS_MESSAGE) #undef REGULAR_PICKUP_MOD #undef CULTIST_PICKUP_MOD diff --git a/monkestation/code/modules/antagonists/clock_cult/ratvar.dm b/monkestation/code/modules/antagonists/clock_cult/ratvar.dm index ec05bffe311f..52efd374eea0 100644 --- a/monkestation/code/modules/antagonists/clock_cult/ratvar.dm +++ b/monkestation/code/modules/antagonists/clock_cult/ratvar.dm @@ -1,7 +1,7 @@ //I would like to do what beestation does and make both this and narsie be children of /eldritch but that would make this very non-modular GLOBAL_DATUM(cult_ratvar, /obj/ratvar) -#define RATVAR_CONSUME_RANGE 12 +#define RATVAR_CONSUME_RANGE 20 #define RATVAR_GRAV_PULL 10 #define RATVAR_SINGULARITY_SIZE 11 @@ -134,9 +134,10 @@ GLOBAL_DATUM(cult_ratvar, /obj/ratvar) /proc/clockcult_ending_start() SSsecurity_level.set_level(SEC_LEVEL_LAMBDA) - priority_announce("Huge gravitational-energy spike detected emminating from a neutron star near your sector. Event has been determined to be survivable by 0% of life. \ - ESTIMATED TIME UNTIL ENERGY PULSE REACHES [GLOB.station_name]: 56 SECONDS. Godspeed crew, glory to Nanotrasen. -Admiral Telvig.", \ - "Central Command Anomolous Materials Division", 'sound/misc/airraid.ogg') + priority_announce("Huge gravitational-energy spike detected emminating from a neutron star [text2ratvar("THEY LIE")] near your sector. Event has been determined to be \ + survivable by 0% of life. ESTIMATED TIME UNTIL ENERGY PULSE REACHES [GLOB.station_name]: 56 SECONDS. Godspeed crew, glory to Nanotrasen. \ + -Admiral W[text2ratvar("orthless")].", \ + "Central Command Anomolous Materials Division", 'sound/misc/airraid.ogg') addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(clockcult_pre_ending)), 50 SECONDS) /proc/clockcult_pre_ending() @@ -150,20 +151,23 @@ GLOBAL_DATUM(cult_ratvar, /obj/ratvar) /proc/clockcult_final_ending() SSshuttle.lockdown = TRUE - for(var/mob/lit_mob in GLOB.mob_list) - if(lit_mob.client) - lit_mob.client.color = LIGHT_COLOR_CLOCKWORK - animate(lit_mob.client, color=COLOR_WHITE, time = 5) - SEND_SOUND(lit_mob, sound(null)) - SEND_SOUND(lit_mob, sound('sound/magic/fireball.ogg')) - if(!IS_CLOCK(lit_mob) && isliving(lit_mob)) - var/mob/living/very_lit_mob = lit_mob - very_lit_mob.fire_stacks = 1000 - very_lit_mob.ignite_mob() - very_lit_mob.emote("scream") + for(var/mob/player_mob in GLOB.player_list) + player_mob.client.color = LIGHT_COLOR_CLOCKWORK + animate(player_mob.client, color = COLOR_WHITE, time = 5) + SEND_SOUND(player_mob, sound(null)) + SEND_SOUND(player_mob, sound('sound/magic/fireball.ogg')) + + for(var/mob/living/lit_mob in GLOB.mob_living_list) + if(!IS_CLOCK(lit_mob)) + lit_mob.fire_stacks = 100 + lit_mob.ignite_mob() + lit_mob.emote("scream") sleep(1.5 SECONDS) SSticker.force_ending = TRUE +/datum/client_colour/ratvar_vision + colour = LIGHT_COLOR_CLOCKWORK + //ratvar_act stuff /atom/proc/ratvar_act() diff --git a/monkestation/code/modules/antagonists/clock_cult/reebe_modules.dm b/monkestation/code/modules/antagonists/clock_cult/reebe_modules.dm index c4fc2236ec0a..e85e99e4b00f 100644 --- a/monkestation/code/modules/antagonists/clock_cult/reebe_modules.dm +++ b/monkestation/code/modules/antagonists/clock_cult/reebe_modules.dm @@ -2,6 +2,9 @@ GLOBAL_LIST_EMPTY(abscond_markers) /// spawn the reebe z level and map template, lazy templates dont work because we need to give this ztraits /proc/spawn_reebe(forced = FALSE) + if(!SSthe_ark.initialized) + SSthe_ark.Initialize() + var/static/reebe_loaded if(forced) message_admins("Admin forcing reebe spawn, if it has already spawned this will break things unless you know what your doing.") @@ -32,29 +35,44 @@ GLOBAL_LIST_EMPTY(abscond_markers) if(!reebe_template.load(reservation.bottom_left_turfs[1])) reebe_loaded = FALSE CRASH("Failed to load the Reebe template.") + + for(var/area/reebe_area as anything in typesof(/area/ruin/powered/reebe)) + reebe_area = GLOB.areas_by_type[reebe_area] + if(reebe_area) + SSthe_ark.reebe_areas[reebe_area] = 1 return TRUE -///Send a pod full of helpful items to the station's bridge +///Send a pod full of helpful items to the station's bridge, you can give items number values to make that many of them be spawned /proc/send_station_support_package(list/additional_items, sent_message = "We are sending a support package to the bridge to help deal with the threats to the station.") var/turf/bridge_turf = pick(GLOB.areas_by_type[/area/station/command/bridge].get_turfs_from_all_zlevels()) if(!bridge_turf) return var/list/spawned_list = list( - /obj/item/storage/medkit/advanced, - /obj/item/storage/medkit/brute, - /obj/item/storage/medkit/fire, - /obj/item/storage/medkit/regular, - /obj/item/gun/medbeam, - /obj/item/storage/part_replacer/cargo, - /obj/item/storage/box/recharger_parts, + /obj/item/storage/medkit/advanced = 1, + /obj/item/storage/medkit/brute = 1, + /obj/item/storage/medkit/fire = 1, + /obj/item/storage/medkit/regular = 1, + /obj/item/gun/medbeam = 1, + /obj/item/storage/part_replacer/cargo = 1, + /obj/item/storage/box/recharger_parts = 1, + /obj/item/storage/toolbox/mechanical = 3, ) if(additional_items) spawned_list += additional_items + fill_with_ones(spawned_list) + for(var/spawned_object in spawned_list) + var/value = spawned_list[spawned_object] + if(value < 0) + stack_trace("a spawned_object([spawned_object]) in send_station_support_package() has a value < 0.") + while(value > 0) + value-- + spawned_list += new spawned_object() + spawned_list -= spawned_object priority_announce(sent_message, has_important_message = TRUE) - podspawn(list("target" = bridge_turf, "spawn" = spawned_list)) + podspawn(list("target" = bridge_turf, "style" = STYLE_CENTCOM, "spawn" = spawned_list, "bluespace" = FALSE, "stay_after_drop" = TRUE)) /obj/item/storage/box/recharger_parts name = "Recharger Parts" diff --git a/monkestation/code/modules/antagonists/clock_cult/scriptures/_scripture.dm b/monkestation/code/modules/antagonists/clock_cult/scriptures/_scripture.dm index 2c351d6d4837..d8256820050f 100644 --- a/monkestation/code/modules/antagonists/clock_cult/scriptures/_scripture.dm +++ b/monkestation/code/modules/antagonists/clock_cult/scriptures/_scripture.dm @@ -54,7 +54,7 @@ GLOBAL_LIST_EMPTY(clock_scriptures_by_type) /// Invoke this scripture, checking if there's valid power and vitality /datum/scripture/proc/invoke() - if(GLOB.clock_power < power_cost || GLOB.clock_vitality < vitality_cost) + if(SSthe_ark.clock_power < power_cost || GLOB.clock_vitality < vitality_cost) invoke_fail() if(invocation_chant_timer) @@ -65,30 +65,25 @@ GLOBAL_LIST_EMPTY(clock_scriptures_by_type) return - GLOB.clock_power -= power_cost + SSthe_ark.clock_power -= power_cost GLOB.clock_vitality -= vitality_cost invoke_success() - /// On success of invoking the scripture /datum/scripture/proc/invoke_success() return TRUE - /// On failure of invoking the scripture /datum/scripture/proc/invoke_fail() return TRUE - /// The overall reciting proc for saying every single line for a scripture -/datum/scripture/proc/recital() +/datum/scripture/proc/recital(input_invoke_time) if(!length(invocation_text)) return var/steps = length(invocation_text) - var/true_invocation_time = invocation_time - if(fast_invoke_mult && HAS_TRAIT(invoker, TRAIT_FASTER_SLAB_INVOKE)) - true_invocation_time = invocation_time * fast_invoke_mult + var/true_invocation_time = input_invoke_time || get_true_invocation_time() var/time_between_say = true_invocation_time / (steps + 1) if(invocation_chant_timer) @@ -97,6 +92,9 @@ GLOBAL_LIST_EMPTY(clock_scriptures_by_type) recite(1, time_between_say, steps) +/datum/scripture/proc/get_true_invocation_time() + . = invocation_time * (HAS_TRAIT(invoker, TRAIT_FASTER_SLAB_INVOKE) ? fast_invoke_mult : 1) + return . /// For reciting an individual line of a scripture /datum/scripture/proc/recite(text_point, wait_time, stop_at = 0) @@ -194,16 +192,9 @@ GLOBAL_LIST_EMPTY(clock_scriptures_by_type) end_invoke() return - recital() - - var/true_invocation_time = invocation_time - if(fast_invoke_mult && HAS_TRAIT(invoker, TRAIT_FASTER_SLAB_INVOKE)) - true_invocation_time = invocation_time * fast_invoke_mult - - if(istype(src, /datum/scripture/create_structure) && GLOB.clock_ark?.current_state >= ARK_STATE_ACTIVE) - true_invocation_time *= (iscogscarab(invoking_mob) ? 2.5 : 5) - - if(do_after(invoking_mob, true_invocation_time, target = invoking_mob, extra_checks = CALLBACK(src, PROC_REF(check_special_requirements), invoking_mob))) + var/true_invocation_time = get_true_invocation_time() + recital(true_invocation_time) + if(do_after(invoking_mob, true_invocation_time, invoking_mob, extra_checks = CALLBACK(src, PROC_REF(check_special_requirements), invoking_mob))) invoke() to_chat(invoking_mob, span_brass("You invoke [name].")) @@ -219,12 +210,10 @@ GLOBAL_LIST_EMPTY(clock_scriptures_by_type) end_invoke() - /// End the invoking, nulling things out /datum/scripture/proc/end_invoke() invoking_slab.invoking_scripture = null - // Call these on the instances in the global lists /// Set a scripture's unique_locked to FALSE and reload the UIs of slabs if set /datum/scripture/proc/unique_unlock(reload_uis = FALSE) @@ -252,8 +241,10 @@ GLOBAL_LIST_EMPTY(clock_scriptures_by_type) // Base create structure scripture /datum/scripture/create_structure - /// Typepath for the structure to create + ///Typepath for the structure to create var/summoned_structure + ///How long is our creation time multiplied by if the assault has begun + var/assault_invoke_time_mult = 2 /datum/scripture/create_structure/check_special_requirements(mob/user) @@ -269,6 +260,10 @@ GLOBAL_LIST_EMPTY(clock_scriptures_by_type) return TRUE +/datum/scripture/create_structure/get_true_invocation_time() + . = ..() + if(GLOB.clock_ark?.current_state >= ARK_STATE_ACTIVE) + . *= (iscogscarab(invoker) ? assault_invoke_time_mult : assault_invoke_time_mult * 2) /datum/scripture/create_structure/invoke_success() var/created_structure = new summoned_structure(get_turf(invoker)) @@ -277,8 +272,6 @@ GLOBAL_LIST_EMPTY(clock_scriptures_by_type) if(istype(clockwork_structure)) clockwork_structure.owner = invoker.mind - - //For scriptures that charge the slab, and the slab will affect something //(stunning etc.) /datum/scripture/slab @@ -312,15 +305,12 @@ GLOBAL_LIST_EMPTY(clock_scriptures_by_type) /datum/scripture/slab/Destroy() progress?.end_progress() - - if(!QDELETED(pointed_spell)) - QDEL_NULL(pointed_spell) + QDEL_NULL(pointed_spell) return ..() - /datum/scripture/slab/invoke() - progress = new(invoker, use_time) + progress = new(invoker, use_time, invoking_slab) uses_left = uses time_left = use_time invoking_slab.charge_overlay = slab_overlay @@ -328,11 +318,10 @@ GLOBAL_LIST_EMPTY(clock_scriptures_by_type) invoking_slab.active_scripture = src pointed_spell.set_click_ability(invoker) count_down() - GLOB.clock_power -= power_cost + SSthe_ark.clock_power -= power_cost GLOB.clock_vitality -= vitality_cost invoke_success() - /// Count down the progress bar /datum/scripture/slab/proc/count_down() if(QDELETED(src)) @@ -347,7 +336,6 @@ GLOBAL_LIST_EMPTY(clock_scriptures_by_type) else end_invocation() - /// What occurs when an atom is clicked on. /datum/scripture/slab/proc/click_on(atom/clicked_atom) SHOULD_CALL_PARENT(TRUE) @@ -367,7 +355,6 @@ GLOBAL_LIST_EMPTY(clock_scriptures_by_type) end_invocation(TRUE) - /// What occurs when the invocation ends /datum/scripture/slab/proc/end_invocation(silent = FALSE) SHOULD_CALL_PARENT(TRUE) @@ -388,13 +375,10 @@ GLOBAL_LIST_EMPTY(clock_scriptures_by_type) end_invoke() - /// Apply the effects of a scripture to an atom /datum/scripture/slab/proc/apply_effects(atom/applied_atom) return TRUE - - /datum/action/cooldown/spell/pointed/slab /// The scripture datum that this spell is referring to var/datum/scripture/slab/parent_scripture @@ -403,7 +387,6 @@ GLOBAL_LIST_EMPTY(clock_scriptures_by_type) parent_scripture = null return ..() - /datum/action/cooldown/spell/pointed/slab/InterceptClickOn(mob/living/user, params, atom/target) parent_scripture?.click_on(target) diff --git a/monkestation/code/modules/antagonists/clock_cult/scriptures/preservation/dimensional_breach.dm b/monkestation/code/modules/antagonists/clock_cult/scriptures/preservation/dimensional_breach.dm index d3a9ad10d82b..7324e9fa1d08 100644 --- a/monkestation/code/modules/antagonists/clock_cult/scriptures/preservation/dimensional_breach.dm +++ b/monkestation/code/modules/antagonists/clock_cult/scriptures/preservation/dimensional_breach.dm @@ -25,7 +25,7 @@ to_chat(invoker, span_userdanger("No ark located, contact the admins with an ahelp(f1).")) return FALSE - if(!(get_charged_anchor_crystals() >= ANCHORING_CRYSTALS_TO_SUMMON)) + if(SSthe_ark.charged_anchoring_crystals < ANCHORING_CRYSTALS_TO_SUMMON) to_chat(invoker, span_brass("Reebe is not yet anchored enough to this realm, the ark cannot open until enough anchoring crystals are summoned and protected.")) return FALSE diff --git a/monkestation/code/modules/antagonists/clock_cult/scriptures/preservation/summon_cogscarab.dm b/monkestation/code/modules/antagonists/clock_cult/scriptures/preservation/summon_cogscarab.dm index 879aae5dd667..09e1480a3247 100644 --- a/monkestation/code/modules/antagonists/clock_cult/scriptures/preservation/summon_cogscarab.dm +++ b/monkestation/code/modules/antagonists/clock_cult/scriptures/preservation/summon_cogscarab.dm @@ -13,7 +13,7 @@ fast_invoke_mult = 1 /datum/scripture/cogscarab/begin_invoke(mob/living/invoking_mob, obj/item/clockwork/clockwork_slab/slab, bypass_unlock_checks) - invocation_time = 12 SECONDS + (6 SECONDS * GLOB.cogscarabs.len) + invocation_time = 12 SECONDS + (6 SECONDS * SSthe_ark.cogscarabs.len) . = ..() /datum/scripture/cogscarab/check_special_requirements(mob/user) @@ -25,7 +25,7 @@ to_chat(invoker, span_warning("You must do this on Reebe!")) return FALSE - if(length(GLOB.cogscarabs) > MAXIMUM_COGSCARABS) + if(length(SSthe_ark.cogscarabs) > MAXIMUM_COGSCARABS) to_chat(invoker, span_warning("You can't summon anymore cogscarabs.")) return FALSE diff --git a/monkestation/code/modules/antagonists/clock_cult/scriptures/preservation/summon_marauder.dm b/monkestation/code/modules/antagonists/clock_cult/scriptures/preservation/summon_marauder.dm index 170a49d1afb3..92f5e7b609ea 100644 --- a/monkestation/code/modules/antagonists/clock_cult/scriptures/preservation/summon_marauder.dm +++ b/monkestation/code/modules/antagonists/clock_cult/scriptures/preservation/summon_marauder.dm @@ -44,15 +44,16 @@ invocation_chant_timer = null end_invoke() - return + return FALSE return ..() /datum/scripture/marauder/invoke_success() var/mob/living/basic/clockwork_marauder/new_mob = new (get_turf(invoker)) + new_mob.istate = 0 new_mob.visible_message(span_notice("[new_mob] flashes into existance!")) new_mob.key = selected.key - new_mob.mind.add_antag_datum(/datum/antagonist/clock_cultist) + new_mob.mind.add_antag_datum(/datum/antagonist/clock_cultist/clockmob) to_chat(new_mob, span_brass("You are a Clockwork Marauder! You have a [new_mob.shield_health]-hit shield that will protect you against any damage taken. \ Have a servant repair you with a welder, should you or your shield become too damaged.")) selected = null @@ -63,10 +64,9 @@ if(!.) return FALSE - if(length(GLOB.clockwork_marauders) >= MAXIMUM_MARAUDERS) + if(length(SSthe_ark.clockwork_marauders) >= MAXIMUM_MARAUDERS) to_chat(user, span_brass("Your limited power prevents you from creating more than [MAXIMUM_MARAUDERS] Clockwork Marauders.")) return FALSE - return TRUE #undef MAXIMUM_MARAUDERS diff --git a/monkestation/code/modules/antagonists/clock_cult/scriptures/preservation/vanguard.dm b/monkestation/code/modules/antagonists/clock_cult/scriptures/preservation/vanguard.dm index c049df43eede..4ed5e342d129 100644 --- a/monkestation/code/modules/antagonists/clock_cult/scriptures/preservation/vanguard.dm +++ b/monkestation/code/modules/antagonists/clock_cult/scriptures/preservation/vanguard.dm @@ -19,18 +19,20 @@ invoker.add_traits(list(TRAIT_STUNIMMUNE, TRAIT_PUSHIMMUNE, TRAIT_IGNOREDAMAGESLOWDOWN, - TRAIT_NOLIMBDISABLE), VANGUARD_TRAIT) + TRAIT_NOLIMBDISABLE, + TRAIT_NO_PAIN_EFFECTS), VANGUARD_TRAIT) to_chat(invoker, span_notice("You feel like nothing can stop you!")) /datum/scripture/slab/vanguard/count_down() . = ..() if(time_left == 5 SECONDS) - to_chat(invoker, span_warning("You start to feel tired again.")) + to_chat(invoker, span_userdanger("You start to feel tired again.")) /datum/scripture/slab/vanguard/end_invocation(silent) . = ..() invoker.remove_traits(list(TRAIT_STUNIMMUNE, TRAIT_PUSHIMMUNE, TRAIT_IGNOREDAMAGESLOWDOWN, - TRAIT_NOLIMBDISABLE), VANGUARD_TRAIT) - to_chat(invoker, span_userdanger("You feel the last of the energy from \the [invoking_slab] leave you.")) + TRAIT_NOLIMBDISABLE, + TRAIT_NO_PAIN_EFFECTS), VANGUARD_TRAIT) + to_chat(invoker, span_bolddanger("You feel the last of the energy from \the [invoking_slab] leave you.")) //smaller span here because its pretty obvious when it ends anyway diff --git a/monkestation/code/modules/antagonists/clock_cult/scriptures/servitude/abscond.dm b/monkestation/code/modules/antagonists/clock_cult/scriptures/servitude/abscond.dm index 772c8c7746c7..483b49f8e875 100644 --- a/monkestation/code/modules/antagonists/clock_cult/scriptures/servitude/abscond.dm +++ b/monkestation/code/modules/antagonists/clock_cult/scriptures/servitude/abscond.dm @@ -1,12 +1,21 @@ /datum/scripture/abscond name = "Abscond" - desc = "Recalls you and anyone you are dragging to reebe." + desc = "After a long delay recalls you and anyone you are dragging to reebe. Cannot be invoked from a non marked area." tip = "If using this with a prisoner dont forget to cuff them first." button_icon_state = "Abscond" - invocation_time = 3 SECONDS + invocation_time = 45 SECONDS invocation_text = list("Return to our home, the city of cogs.") category = SPELLTYPE_SERVITUDE power_cost = 5 +/datum/scripture/abscond/check_special_requirements(mob/user) + . = ..() + if(!.) + return + + if(!SSthe_ark.marked_areas[get_area(invoker)]) + to_chat(user, span_warning("We can only abscond from marked areas!")) + return FALSE + /datum/scripture/abscond/invoke_success() try_servant_warp(invoker, get_turf(pick(GLOB.abscond_markers))) diff --git a/monkestation/code/modules/antagonists/clock_cult/scriptures/servitude/golem_conversion.dm b/monkestation/code/modules/antagonists/clock_cult/scriptures/servitude/golem_conversion.dm index 6d3a32940776..a1e5d5148f4d 100644 --- a/monkestation/code/modules/antagonists/clock_cult/scriptures/servitude/golem_conversion.dm +++ b/monkestation/code/modules/antagonists/clock_cult/scriptures/servitude/golem_conversion.dm @@ -4,12 +4,20 @@ desc = "Ascend your form to that of a clockwork golem, giving them innate armor, environmental immunity, and faster invoking for most scriptures." tip = "Can only be used by humaniod servants." button_icon_state = "Spatial Warp" - power_cost = 300 + power_cost = 1000 invocation_time = 15 SECONDS invocation_text = list("My form is weak...", "It must ascend...", "To that of clockwork.") cogs_required = 3 category = SPELLTYPE_SERVITUDE - unique_locked = TRUE //unlocked after 3 anchoring crystals have been placed + unique_locked = TRUE //unlocked after 2 extra anchoring crystals have been placed + +/datum/scripture/transform_to_golem/New() + . = ..() + RegisterSignal(SSthe_ark, COMSIG_ANCHORING_CRYSTAL_CHARGED, PROC_REF(on_crystal_charged)) + +/datum/scripture/transform_to_golem/Destroy(force) + UnregisterSignal(SSthe_ark, COMSIG_ANCHORING_CRYSTAL_CHARGED) + return ..() /datum/scripture/transform_to_golem/check_special_requirements(mob/user) . = ..() @@ -30,3 +38,7 @@ human_servant.set_species(/datum/species/golem/clockwork) human_servant.update_body(TRUE) human_servant.update_mutations_overlay() + +/datum/scripture/transform_to_golem/proc/on_crystal_charged() + if(SSthe_ark.charged_anchoring_crystals >= ANCHORING_CRYSTALS_TO_SUMMON + 2) + unique_unlock(TRUE) diff --git a/monkestation/code/modules/antagonists/clock_cult/scriptures/servitude/hateful_manaceles.dm b/monkestation/code/modules/antagonists/clock_cult/scriptures/servitude/hateful_manaceles.dm index d8711da37891..a29c397529bb 100644 --- a/monkestation/code/modules/antagonists/clock_cult/scriptures/servitude/hateful_manaceles.dm +++ b/monkestation/code/modules/antagonists/clock_cult/scriptures/servitude/hateful_manaceles.dm @@ -25,10 +25,7 @@ target_carbon.visible_message(span_danger("[invoker] forms a well of energy around [target_carbon], brass appearing at their wrists!"),\ span_userdanger("[invoker] is trying to restrain you!")) - if(!do_after(invoker, 3 SECONDS, target = target_carbon)) - return FALSE - - if(target_carbon.handcuffed) + if(!do_after(invoker, 3 SECONDS, target = target_carbon) || target_carbon.handcuffed) return FALSE target_carbon.set_handcuffed(new /obj/item/restraints/handcuffs/clockwork(target_carbon)) diff --git a/monkestation/code/modules/antagonists/clock_cult/scriptures/servitude/kindle.dm b/monkestation/code/modules/antagonists/clock_cult/scriptures/servitude/kindle.dm index 1a06de3c9086..6bf792391e49 100644 --- a/monkestation/code/modules/antagonists/clock_cult/scriptures/servitude/kindle.dm +++ b/monkestation/code/modules/antagonists/clock_cult/scriptures/servitude/kindle.dm @@ -1,11 +1,11 @@ -#define EFFECT_TIME (6.5 SECONDS) +#define EFFECT_TIME (7 SECONDS) // Clock cult's version of the "bullshit stun hand" /datum/scripture/slab/kindle name = "Kindle" desc = "Stuns and mutes a target from a short range." - tip = "Best paired with hateful manacels for conversion, they are stunned for 6.5 seconds and muted for 13." + tip = "Best paired with hateful manacels for conversion, they are stunned for 7 seconds and muted for 14." button_icon_state = "Kindle" power_cost = 125 invocation_time = 2 SECONDS @@ -87,10 +87,10 @@ carbon_hit.adjust_timed_status_effect(26 SECONDS, /datum/status_effect/speech/slurring/cult) - carbon_hit.adjust_silence(EFFECT_TIME * 2) //enough time to cuff and remove their radio, or just go back to reebe where their comms wont work - carbon_hit.AdjustKnockdown(EFFECT_TIME * (has_mindshield ? 1 : 1.5)) + carbon_hit.adjust_silence(EFFECT_TIME * (has_mindshield ? 1 : 2)) //enough time to cuff and remove their radio, or just go back to reebe where their comms wont work + carbon_hit.AdjustKnockdown(EFFECT_TIME * (has_mindshield ? 0.5 : 1.5)) //pretty much 0 stun if your on reebe, still good for knockdown though, also only a 1 second stun on mindshielded people - carbon_hit.Stun((has_mindshield ? 1 SECONDS : EFFECT_TIME) * ((on_reebe(carbon_hit) && GLOB.clock_ark?.current_state) ? 0.1 : 1)) + carbon_hit.Stun((has_mindshield ? 0.5 SECONDS : EFFECT_TIME) * ((on_reebe(carbon_hit) && GLOB.clock_ark?.current_state) ? 0.1 : 1)) if(hit_mob.client) var/client_color = hit_mob.client.color diff --git a/monkestation/code/modules/antagonists/clock_cult/scriptures/servitude/sentinels_compromise.dm b/monkestation/code/modules/antagonists/clock_cult/scriptures/servitude/sentinels_compromise.dm index 257ad4a8e6cb..9fcdefbf2307 100644 --- a/monkestation/code/modules/antagonists/clock_cult/scriptures/servitude/sentinels_compromise.dm +++ b/monkestation/code/modules/antagonists/clock_cult/scriptures/servitude/sentinels_compromise.dm @@ -1,6 +1,8 @@ +///how much do we heal per do_after() loop +#define HEALED_PER_LOOP 10 /datum/scripture/slab/sentinels_compromise name = "Sentinel's Compromise" - desc = "Heals a large amount of non-toxin damage on a target then converts 50% of it back as toxin damage to you." + desc = "Continuously heals non-toxin damage on a target then converts 80% of it back as toxin damage to you." tip = "Works well with Properity Prisms. Cannot be used by cogscarabs." power_cost = 80 cogs_required = 1 @@ -32,26 +34,29 @@ return FALSE healed_mob.cure_husk() - if(healed_mob.stat == DEAD) //technically the husk healing is free but it should be fine return FALSE - clockwork_say(invoker, text2ratvar("Wounds will close."), TRUE) - //MMMMMM, CHUNKY - var/total_damage = (healed_mob.getBruteLoss() + healed_mob.getFireLoss() + healed_mob.getOxyLoss() + healed_mob.getCloneLoss()) * 0.6 - healed_mob.stamina.adjust(healed_mob.staminaloss * 0.6) - healed_mob.adjustBruteLoss(-healed_mob.getBruteLoss() * 0.6) - healed_mob.adjustFireLoss(-healed_mob.getFireLoss() * 0.6) - healed_mob.adjustOxyLoss(-healed_mob.getOxyLoss() * 0.6) - healed_mob.adjustCloneLoss(-healed_mob.getCloneLoss() * 0.6) healed_mob.blood_volume = BLOOD_VOLUME_NORMAL healed_mob.set_nutrition(NUTRITION_LEVEL_FULL) healed_mob.bodytemperature = BODYTEMP_NORMAL - healed_mob.reagents.remove_reagent(/datum/reagent/water/holywater, 100) //if you have over 100 units of holy water then it should take multiple to purge - healed_mob.adjustOrganLoss(ORGAN_SLOT_BRAIN, -50) + healed_mob.pain_controller?.remove_all_pain() + if(apply_heal(healed_mob)) + while(do_after(invoker, invocation_time, healed_mob)) + if(!apply_heal(healed_mob)) //im sure theres a better way to do this but im too tired + break + clockwork_say(invoker, text2ratvar("Wounds will close."), TRUE) new /obj/effect/temp_visual/heal(get_turf(healed_mob), "#1E8CE1") + return TRUE - invoker.adjustToxLoss(min(total_damage * 0.5, 80), forced = TRUE) +/datum/scripture/slab/sentinels_compromise/proc/apply_heal(mob/living/healed_mob) + var/healed_amount = -healed_mob.heal_ordered_damage(HEALED_PER_LOOP, list(BRUTE, BURN, OXY, CLONE, BRAIN)) + healed_mob.stamina.adjust(HEALED_PER_LOOP) + healed_mob.reagents.remove_reagent(/datum/reagent/water/holywater, HEALED_PER_LOOP) + if(!invoker.adjustToxLoss(healed_amount * 0.8, TRUE, TRUE) || invoker.getToxLoss() > 80 || healed_amount < HEALED_PER_LOOP) + return FALSE return TRUE + +#undef HEALED_PER_LOOP diff --git a/monkestation/code/modules/antagonists/clock_cult/scriptures/structures/anchoring_crystal.dm b/monkestation/code/modules/antagonists/clock_cult/scriptures/structures/anchoring_crystal.dm index e36effbac16f..e847bfe3f177 100644 --- a/monkestation/code/modules/antagonists/clock_cult/scriptures/structures/anchoring_crystal.dm +++ b/monkestation/code/modules/antagonists/clock_cult/scriptures/structures/anchoring_crystal.dm @@ -12,10 +12,19 @@ category = SPELLTYPE_STRUCTURES ///how long in seconds until the scripture can be invoked again, pretty much a cooldown var/static/time_until_invokable = 0 + ///the list of + var/static/list/valid_areas /datum/scripture/create_structure/anchoring_crystal/New() - tip = "With this crystal [anchoring_crystal_charge_message()]" + update_info() . = ..() + RegisterSignal(SSthe_ark, COMSIG_ANCHORING_CRYSTAL_CHARGED, PROC_REF(on_crystal_charged)) + RegisterSignal(SSthe_ark, COMSIG_ANCHORING_CRYSTAL_CREATED, PROC_REF(update_info)) + +/datum/scripture/create_structure/anchoring_crystal/Destroy(force) + UnregisterSignal(SSthe_ark, COMSIG_ANCHORING_CRYSTAL_CHARGED) + UnregisterSignal(SSthe_ark, COMSIG_ANCHORING_CRYSTAL_CREATED) + return ..() /datum/scripture/create_structure/anchoring_crystal/process(seconds_per_tick) time_until_invokable = time_until_invokable - (seconds_per_tick SECONDS) @@ -33,14 +42,10 @@ to_chat(invoker, span_warning("The ark will be stable enough to summon another crystal in [time_until_invokable] seconds.")) return FALSE - var/datum/objective/anchoring_crystals/crystals_objective = locate() in GLOB.main_clock_cult?.objectives - if(!length(crystals_objective?.valid_areas)) - return FALSE - - if(get_charged_anchor_crystals() && !(get_area(invoker) in crystals_objective.valid_areas)) + if(SSthe_ark.charged_anchoring_crystals && !SSthe_ark.valid_crystal_areas[get_area(invoker)]) var/list/area_list = list() - for(var/area/added_area in crystals_objective.valid_areas) - area_list += added_area.get_original_area_name() + for(var/area/added_area in SSthe_ark.valid_crystal_areas) + area_list += SSthe_ark.valid_crystal_areas[added_area] to_chat(invoker, span_warning("This cystal can only be summoned in [english_list(area_list)].")) return FALSE @@ -64,11 +69,22 @@ var/datum/scripture/create_structure/anchoring_crystal/scripture = GLOB.clock_scriptures_by_type[/datum/scripture/create_structure/anchoring_crystal] START_PROCESSING(SSprocessing, scripture) +/datum/scripture/create_structure/anchoring_crystal/proc/on_crystal_charged() + SIGNAL_HANDLER + if(SSthe_ark.charged_anchoring_crystals >= ANCHORING_CRYSTALS_TO_SUMMON + 2) + unique_lock() + return + /datum/scripture/create_structure/anchoring_crystal/proc/update_info() - var/datum/objective/anchoring_crystals/crystals_objective = locate() in GLOB.main_clock_cult?.objectives - if(crystals_objective && get_charged_anchor_crystals()) + SIGNAL_HANDLER + tip = "With this crystal [anchoring_crystal_charge_message()]" + if(!SSthe_ark.charged_anchoring_crystals) + return + + if(!length(SSthe_ark.valid_crystal_areas)) + desc = "We cannot summon any more anchoring crystals to the station." + else var/list/area_list = list() - for(var/area/added_area in crystals_objective.valid_areas) - area_list += added_area.get_original_area_name() + for(var/area/added_area in SSthe_ark.valid_crystal_areas) + area_list += SSthe_ark.valid_crystal_areas[added_area] desc = "Summon an anchoring crystal to the station, it can be summoned in [english_list(area_list)]." - tip = "With this crystal [anchoring_crystal_charge_message()]" diff --git a/monkestation/code/modules/antagonists/clock_cult/scriptures/structures/transmission_sigil.dm b/monkestation/code/modules/antagonists/clock_cult/scriptures/structures/transmission_sigil.dm index df8c1bf2d92b..db166d3591ba 100644 --- a/monkestation/code/modules/antagonists/clock_cult/scriptures/structures/transmission_sigil.dm +++ b/monkestation/code/modules/antagonists/clock_cult/scriptures/structures/transmission_sigil.dm @@ -8,3 +8,4 @@ invocation_text = list("Oh great holy one...", "your energy...", "the power of the holy light!") summoned_structure = /obj/structure/destructible/clockwork/sigil/transmission category = SPELLTYPE_STRUCTURES + assault_invoke_time_mult = 1 diff --git a/monkestation/code/modules/antagonists/clock_cult/structures/_powered.dm b/monkestation/code/modules/antagonists/clock_cult/structures/_powered.dm index 1d81559ff2b4..1e143c517c89 100644 --- a/monkestation/code/modules/antagonists/clock_cult/structures/_powered.dm +++ b/monkestation/code/modules/antagonists/clock_cult/structures/_powered.dm @@ -127,7 +127,7 @@ /obj/structure/destructible/clockwork/gear_base/powered/proc/update_power() if(depowered) - if((GLOB.clock_power > minimum_power && LAZYLEN(transmission_sigils)) || !minimum_power) + if((SSthe_ark.clock_power > minimum_power && LAZYLEN(transmission_sigils)) || !minimum_power) repowered() return TRUE @@ -136,7 +136,7 @@ else - if(GLOB.clock_power <= minimum_power || !LAZYLEN(transmission_sigils)) + if(SSthe_ark.clock_power <= minimum_power || !LAZYLEN(transmission_sigils)) depowered() return FALSE @@ -154,7 +154,7 @@ if(depowered) return FALSE - if(GLOB.clock_power < amount) + if(SSthe_ark.clock_power < amount) return FALSE return TRUE @@ -166,7 +166,7 @@ if(!check_power(amount)) return FALSE - GLOB.clock_power -= amount + SSthe_ark.clock_power -= amount update_power() return TRUE diff --git a/monkestation/code/modules/antagonists/clock_cult/structures/_structure.dm b/monkestation/code/modules/antagonists/clock_cult/structures/_structure.dm index dcaf1679400d..725730bef026 100644 --- a/monkestation/code/modules/antagonists/clock_cult/structures/_structure.dm +++ b/monkestation/code/modules/antagonists/clock_cult/structures/_structure.dm @@ -35,13 +35,11 @@ /obj/structure/destructible/clockwork/Destroy() owner = null - return ..() /obj/structure/destructible/clockwork/attacked_by(obj/item/I, mob/living/user) - if(immune_to_servant_attacks && (IS_CLOCK(user))) + if(immune_to_servant_attacks && user.istate != ISTATE_HARM && (IS_CLOCK(user))) return - return ..() diff --git a/monkestation/code/modules/antagonists/clock_cult/structures/anchor_crystal.dm b/monkestation/code/modules/antagonists/clock_cult/structures/anchor_crystal.dm index 914d70b456b4..a6c96b888482 100644 --- a/monkestation/code/modules/antagonists/clock_cult/structures/anchor_crystal.dm +++ b/monkestation/code/modules/antagonists/clock_cult/structures/anchor_crystal.dm @@ -1,7 +1,4 @@ -GLOBAL_LIST_EMPTY(anchoring_crystals) //list of all anchoring crystals - #define CRYSTAL_SHIELD_DELAY 50 SECONDS //how long until shields start to recharge -#define CRYSTAL_CHARGE_TIMER 360 //how long in seconds do crystals take to charge, 6 MINTUES #define CRYSTAL_CHARGING 0 //crystal is currently charging #define CRYSTAL_LOCATION_ANNOUNCED 1 //the location of the crystal has been anouced to the crew #define FULLY_CHARGED 2 //the crystal is fully charged @@ -9,7 +6,7 @@ GLOBAL_LIST_EMPTY(anchoring_crystals) //list of all anchoring crystals #define SHIELD_DEFLECT "deflect" //the shield is currently in its deflecting animation #define SHIELD_BREAK "break" //the shield is currently in its breaking animation #define SHIELD_BROKEN "broken" //the shield is currently broken -#define SERVANT_CAPACITY_TO_GIVE 2 //how many extra server slots do we give on first charged crystal +#define EXTRA_MARKED_AREAS 4 //how many extra adjacent areas do we mark /obj/structure/destructible/clockwork/anchoring_crystal name = "Anchoring Crystal" desc = "A strange crystal that you cant quite seem to focus on." @@ -22,19 +19,21 @@ GLOBAL_LIST_EMPTY(anchoring_crystals) //list of all anchoring crystals can_rotate = FALSE resistance_flags = FIRE_PROOF | ACID_PROOF | LAVA_PROOF armor_type = /datum/armor/anchoring_crystal - max_integrity = 300 //pretty hard to break + max_integrity = 250 //pretty hard to break ///how many hits this can take before taking structure damage, not using the component as its only for items/mobs var/shields = 3 ///what charge state is this crystal var/charge_state = CRYSTAL_CHARGING ///what area is this in var/area/crystal_area - ///theme for transforming the area - var/static/datum/dimension_theme/clock_theme ///timer var for charging var/charging_for = 0 ///due to the way overlays are handled we have to handle everything for them within a single SIGNAL_HANDLER proc, this var is used for keeping track of what to set our overlay state to next var/overlay_state = SHIELD_ACTIVE + ///the list of our charge effect datums + var/static/list/charge_datums + ///the charge effect datum we are currently using + var/datum/anchoring_crystal_charge_effect/charge_effect_datum ///cooldown for when we were last hit COOLDOWN_DECLARE(recently_hit_cd) @@ -50,29 +49,40 @@ GLOBAL_LIST_EMPTY(anchoring_crystals) //list of all anchoring crystals /obj/structure/destructible/clockwork/anchoring_crystal/Initialize(mapload) . = ..() - crystal_area = get_area(src) - GLOB.anchoring_crystals += src - if(!clock_theme) - clock_theme = new /datum/dimension_theme/clockwork(is_cult = TRUE) + if(!SSthe_ark.initialized) + SSthe_ark.Initialize() - start_turf_conversion() - send_clock_message(null, span_bigbrass(span_bold("An Anchoring Crystal has been created at [crystal_area], defend it!"))) + crystal_area = get_area(src) + SSthe_ark.anchoring_crystals[src] = 0 + + SEND_SIGNAL(SSthe_ark, COMSIG_ANCHORING_CRYSTAL_CREATED, src) + var/conversion_timer = SSthe_ark.convert_area_turfs(crystal_area) + var/list/adjacent_areas = get_area_edge_turfs(crystal_area, TRUE)[src.z] + var/extra_marks = 0 + while(length(adjacent_areas) && extra_marks < EXTRA_MARKED_AREAS) + var/area/marked_area = pick_n_take(adjacent_areas) + if(marked_area.outdoors || SSthe_ark.marked_areas[marked_area]) + continue - if(length(GLOB.anchoring_crystals) >= 2) - priority_announce("Reality warping object detected aboard the station.", "Higher Dimensional Affairs", ANNOUNCER_SPANOMALIES, has_important_message = TRUE) + extra_marks++ + SSthe_ark.marked_areas[marked_area] = TRUE + SSthe_ark.convert_area_turfs(marked_area, 50, conversion_timer) + priority_announce("Reality warping object aboard the station, emergency shuttle uplink connection lost.", "Higher Dimensional Affairs", ANNOUNCER_SPANOMALIES, has_important_message = TRUE) + send_clock_message(null, span_bigbrass(span_bold("An Anchoring Crystal has been created at [crystal_area], defend it!"))) START_PROCESSING(SSprocessing, src) RegisterSignal(src, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(on_update_overlays)) update_icon() + START_PROCESSING(SSmachines, src) - var/datum/objective/anchoring_crystals/crystals_objective = locate() in GLOB.main_clock_cult?.objectives - if(crystal_area in crystals_objective?.valid_areas) //if a crystal gets destroyed you cant use that area again - crystals_objective.valid_areas -= crystal_area + SSthe_ark.marked_areas[crystal_area] = TRUE + SSthe_ark.block_shuttle(src) + if(SSthe_ark.valid_crystal_areas) + SSthe_ark.valid_crystal_areas -= crystal_area - SSshuttle.registerHostileEnvironment(src) //removed on destruction or once the scripture is off cooldown - var/datum/scripture/create_structure/anchoring_crystal/crystal_scripture - addtimer(CALLBACK(src, PROC_REF(clear_hostile_environment)), ANCHORING_CRYSTAL_COOLDOWN + initial(crystal_scripture.invocation_time)) //also give them time to invoke - GLOB.clock_warp_areas |= crystal_area +/obj/structure/destructible/clockwork/anchoring_crystal/Destroy() + SSthe_ark.clear_shuttle_interference(src) + return ..() /obj/structure/destructible/clockwork/anchoring_crystal/take_damage(damage_amount, damage_type, damage_flag, sound_effect, attack_dir, armour_penetration) COOLDOWN_START(src, recently_hit_cd, CRYSTAL_SHIELD_DELAY) @@ -86,7 +96,7 @@ GLOBAL_LIST_EMPTY(anchoring_crystals) //list of all anchoring crystals do_sparks(2, TRUE, src) update_icon() damage_amount = 0 //dont take damage if we have shields - . = ..() + return ..() /obj/structure/destructible/clockwork/anchoring_crystal/process(seconds_per_tick) for(var/mob/living/affected_mob in crystal_area) @@ -97,10 +107,10 @@ GLOBAL_LIST_EMPTY(anchoring_crystals) //list of all anchoring crystals affected_mob.adjust_silence_up_to(5 SECONDS * seconds_per_tick, 2 MINUTES) if(charge_state == FULLY_CHARGED) //if fully charged then add the power and return - GLOB.clock_power = min(GLOB.clock_power + (10 * seconds_per_tick), GLOB.max_clock_power) + SSthe_ark.clock_power = min(SSthe_ark.clock_power + (10 * seconds_per_tick), SSthe_ark.max_clock_power) return - charging_for = min(charging_for + seconds_per_tick, CRYSTAL_CHARGE_TIMER) + charging_for = min(charging_for + (seconds_per_tick SECONDS), ANCHORING_CRYSTAL_CHARGE_DURATION) if(shields < initial(shields) && COOLDOWN_FINISHED(src, recently_hit_cd)) playsound(src, 'sound/magic/charge.ogg', 50, TRUE) @@ -108,84 +118,39 @@ GLOBAL_LIST_EMPTY(anchoring_crystals) //list of all anchoring crystals overlay_state = SHIELD_ACTIVE update_icon() - if(charging_for >= CRYSTAL_CHARGE_TIMER) + if(charging_for >= ANCHORING_CRYSTAL_CHARGE_DURATION) finish_charging() return - if(charge_state < CRYSTAL_LOCATION_ANNOUNCED && charging_for >= (CRYSTAL_CHARGE_TIMER * 0.4)) + if(charge_state < CRYSTAL_LOCATION_ANNOUNCED && charging_for >= 30 SECONDS) //announce after thirty seconds charge_state = CRYSTAL_LOCATION_ANNOUNCED - if(length(GLOB.anchoring_crystals) >= 2) - priority_announce("Reality warping object located in [crystal_area].", "Central Command Higher Dimensional Affairs", ANNOUNCER_SPANOMALIES, has_important_message = TRUE) + priority_announce("Reality warping object located in [crystal_area].", "Central Command Higher Dimensional Affairs", ANNOUNCER_SPANOMALIES, has_important_message = TRUE) /obj/structure/destructible/clockwork/anchoring_crystal/Destroy() send_clock_message(null, span_bigbrass(span_bold("The Anchoring Crystal at [crystal_area] has been destroyed!"))) - GLOB.anchoring_crystals -= src + SSthe_ark.anchoring_crystals -= src STOP_PROCESSING(SSprocessing, src) UnregisterSignal(src, COMSIG_ATOM_UPDATE_OVERLAYS) - SSshuttle.clearHostileEnvironment(src) return ..() /obj/structure/destructible/clockwork/anchoring_crystal/examine(mob/user) //needs to be here as it has updating information . = ..() if(IS_CLOCK(user) || isobserver(user)) - . += span_brass("[charge_state == FULLY_CHARGED ? "It is fully charged and is indestructable." : "It will be fully charged in [(CRYSTAL_CHARGE_TIMER - charging_for)] seconds."]") - -//called on init, transforms the turfs and objs in the area of the crystal to clockwork versions -/obj/structure/destructible/clockwork/anchoring_crystal/proc/start_turf_conversion() - var/timer_counter = 1 //used by the addtimer() - for(var/turf/turf_to_transform in crystal_area) - if(!clock_theme.can_convert(turf_to_transform)) - continue - addtimer(CALLBACK(src, PROC_REF(do_turf_conversion), turf_to_transform), 3 * timer_counter) - timer_counter++ - -/obj/structure/destructible/clockwork/anchoring_crystal/proc/do_turf_conversion(turf/converted_turf) - if(QDELETED(src) || !clock_theme.can_convert(converted_turf)) - return - - clock_theme.apply_theme(converted_turf) - new /obj/effect/temp_visual/ratvar/beam(converted_turf) - if(istype(converted_turf, /turf/closed/wall)) - new /obj/effect/temp_visual/ratvar/wall(converted_turf) - else if(istype(converted_turf, /turf/open/floor)) - new /obj/effect/temp_visual/ratvar/floor(converted_turf) + . += span_brass(\ + "[charge_state == FULLY_CHARGED ? "It is fully charged and is indestructable." : "It will be fully charged in [(ANCHORING_CRYSTAL_CHARGE_DURATION - charging_for)] seconds."]") //do all the stuff for finishing charging /obj/structure/destructible/clockwork/anchoring_crystal/proc/finish_charging() send_clock_message(null, span_bigbrass(span_bold("The Anchoring Crystal at [crystal_area] has fully charged! [anchoring_crystal_charge_message(TRUE)]"))) charge_state = FULLY_CHARGED - resistance_flags += INDESTRUCTIBLE + resistance_flags |= INDESTRUCTIBLE atom_integrity = INFINITY set_armor(/datum/armor/immune) - if(length(GLOB.anchoring_crystals) >= 2) - priority_announce("Reality in [crystal_area] has been destabilized, all personnel are advised to avoid the area.", \ - "Central Command Higher Dimensional Affairs", ANNOUNCER_SPANOMALIES, has_important_message = TRUE) - - GLOB.max_clock_power += 1000 - SSshuttle.clearHostileEnvironment(src) - var/datum/scripture/create_structure/anchoring_crystal/creation_scripture = /datum/scripture/create_structure/anchoring_crystal - if(locate(creation_scripture) in GLOB.clock_scriptures_by_type) - creation_scripture = GLOB.clock_scriptures_by_type[creation_scripture] - creation_scripture.update_info() - - switch(get_charged_anchor_crystals()) - if(1) //add 2 more max servants and increase replica fabricator build speed - GLOB.main_clock_cult.max_human_servants += SERVANT_CAPACITY_TO_GIVE - if(ANCHORING_CRYSTALS_TO_SUMMON + 1) //create a steam helios on reebe - if(length(GLOB.abscond_markers)) - var/turf/created_at = get_turf(pick(GLOB.abscond_markers)) - new /obj/vehicle/sealed/mecha/steam_helios(created_at) - new /obj/effect/temp_visual/steam(created_at) - else if(GLOB.clock_ark) - new /obj/vehicle/sealed/mecha/steam_helios(get_turf(GLOB.clock_ark)) - else - message_admins("No valid location for Steam Helios creation.") - if(ANCHORING_CRYSTALS_TO_SUMMON + 2) //lock the anchoring crystal scripture and unlock the golem scripture - var/datum/scripture/create_structure/anchoring_crystal/crystal_scripture = GLOB.clock_scriptures_by_type[/datum/scripture/create_structure/anchoring_crystal] - crystal_scripture.unique_lock() - - var/datum/scripture/transform_to_golem/golem_scripture = GLOB.clock_scriptures_by_type[/datum/scripture/transform_to_golem] - golem_scripture.unique_unlock(TRUE) + desc += "Reality around it shimmers, making it effectively impervious to damage." + priority_announce("Reality in [crystal_area] has been destabilized, all personnel are advised to avoid the area.", \ + "Central Command Higher Dimensional Affairs", ANNOUNCER_SPANOMALIES, has_important_message = TRUE) + SSthe_ark.max_clock_power += 1000 + SSthe_ark.on_crystal_charged(src) //set the shield overlay /obj/structure/destructible/clockwork/anchoring_crystal/proc/on_update_overlays(atom/crystal, list/overlays) @@ -203,16 +168,10 @@ GLOBAL_LIST_EMPTY(anchoring_crystals) //list of all anchoring crystals addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_icon)), 2) overlays += shield_appearance -/obj/structure/destructible/clockwork/anchoring_crystal/proc/clear_hostile_environment() - if(QDELETED(src)) - return - - SSshuttle.clearHostileEnvironment(src) - ///return a message based off of what this anchoring crystal did/will do for the cult /proc/anchoring_crystal_charge_message(completed = FALSE) var/message = "" - switch(get_charged_anchor_crystals()) + switch(SSthe_ark.charged_anchoring_crystals) if(0) message = "[completed ? "We can now" : "We will be able to"] support 2 more servants and gain faster build speed with replica fabricators on reebe." if(ANCHORING_CRYSTALS_TO_SUMMON - 1) @@ -224,16 +183,7 @@ GLOBAL_LIST_EMPTY(anchoring_crystals) //list of all anchoring crystals and faster invoking for most scriptures." return message -///returns how many charged anchor crystals there are -/proc/get_charged_anchor_crystals() - var/charged_count = 0 - for(var/obj/structure/destructible/clockwork/anchoring_crystal/checked_crystal in GLOB.anchoring_crystals) - if(checked_crystal.charge_state == FULLY_CHARGED) - charged_count++ - return charged_count - #undef CRYSTAL_SHIELD_DELAY -#undef CRYSTAL_CHARGE_TIMER #undef CRYSTAL_CHARGING #undef CRYSTAL_LOCATION_ANNOUNCED #undef FULLY_CHARGED @@ -241,4 +191,4 @@ GLOBAL_LIST_EMPTY(anchoring_crystals) //list of all anchoring crystals #undef SHIELD_DEFLECT #undef SHIELD_BREAK #undef SHIELD_BROKEN -#undef SERVANT_CAPACITY_TO_GIVE +#undef EXTRA_MARKED_AREAS diff --git a/monkestation/code/modules/antagonists/clock_cult/structures/brass_window.dm b/monkestation/code/modules/antagonists/clock_cult/structures/brass_window.dm index da3c1e68c84e..11576daca50f 100644 --- a/monkestation/code/modules/antagonists/clock_cult/structures/brass_window.dm +++ b/monkestation/code/modules/antagonists/clock_cult/structures/brass_window.dm @@ -9,6 +9,8 @@ decon_speed = 4 SECONDS glass_type = /obj/item/stack/sheet/bronze glass_amount = 1 + uses_color = FALSE + has_sill = FALSE /obj/structure/window/reinforced/clockwork/Initialize(mapload, direct) if(on_reebe(src)) diff --git a/monkestation/code/modules/antagonists/clock_cult/structures/eminence_beacon.dm b/monkestation/code/modules/antagonists/clock_cult/structures/eminence_beacon.dm index 787cb68d15d9..9b90d5f7aa42 100644 --- a/monkestation/code/modules/antagonists/clock_cult/structures/eminence_beacon.dm +++ b/monkestation/code/modules/antagonists/clock_cult/structures/eminence_beacon.dm @@ -7,6 +7,8 @@ var/vote_active = FALSE ///weakref to our vote timer var/datum/weakref/vote_timer + ///are we currently polling for an eminence + var/polling = FALSE /obj/structure/destructible/clockwork/eminence_beacon/attack_hand(mob/user) . = ..() @@ -25,6 +27,10 @@ var/option = tgui_alert(user, "Becoming the Eminence is not an easy task, be sure you will be able to lead the servants. \ If you choose to do so, your old form with be destroyed.", "Who shall control the Eminence?", list("Yourself", "A ghost", "Cancel")) + if(vote_active) + balloon_alert(user, "A vote has already been called, if you would like to object you can interact with the spire again.") + return + if(option == "Yourself") send_clock_message(null, span_bigbrass("[user] has elected themselves to become the Eminence. Interact with \the [src] to object.")) vote_timer = WEAKREF(addtimer(CALLBACK(src, PROC_REF(vote_succeed), user), 60 SECONDS, TIMER_UNIQUE | TIMER_STOPPABLE)) @@ -37,10 +43,13 @@ /obj/structure/destructible/clockwork/eminence_beacon/proc/vote_succeed(mob/living/eminence) //if we select a ghost then we dont call any living procs so this is fine vote_active = FALSE + if(polling) + return + if(GLOB.current_eminence) message_admins("[type] calling vote_succeed() with a set GLOB.current_eminence, this should not be happening.") return - + polling = TRUE if(!eminence) var/list/mob/dead/observer/candidates = SSpolling.poll_ghost_candidates( "Do you want to play as the eminence", @@ -53,6 +62,7 @@ if(length(candidates)) eminence = pick(candidates) + polling = FALSE if(!(eminence?.client)) send_clock_message(null, "The Eminence remains in slumber, for now, try waking it again soon.") return diff --git a/monkestation/code/modules/antagonists/clock_cult/structures/prosperity_prism.dm b/monkestation/code/modules/antagonists/clock_cult/structures/prosperity_prism.dm index f7f1764e1a1b..a275aff16b20 100644 --- a/monkestation/code/modules/antagonists/clock_cult/structures/prosperity_prism.dm +++ b/monkestation/code/modules/antagonists/clock_cult/structures/prosperity_prism.dm @@ -1,4 +1,5 @@ #define POWER_PER_USE 20 +#define HEAL_PER_USE 2 /obj/structure/destructible/clockwork/gear_base/powered/prosperity_prism name = "prosperity prism" @@ -19,7 +20,6 @@ if(!chems_to_purge) chems_to_purge = typecacheof(list(/datum/reagent/toxin, /datum/reagent/water/holywater)) - /obj/structure/destructible/clockwork/gear_base/powered/prosperity_prism/process(seconds_per_tick) . = ..() if(!.) @@ -32,12 +32,11 @@ if(possible_cultist.health >= possible_cultist.maxHealth) continue - possible_cultist.adjustToxLoss(-2.5 * seconds_per_tick, forced = TRUE) - possible_cultist.stamina.adjust(7.5 * seconds_per_tick, TRUE) - possible_cultist.adjustBruteLoss(-2.5 * seconds_per_tick) - possible_cultist.adjustFireLoss(-2.5 * seconds_per_tick) - possible_cultist.adjustOxyLoss(-2.5 * seconds_per_tick) - possible_cultist.adjustCloneLoss(-1 * seconds_per_tick) + var/healed_amount = HEAL_PER_USE * seconds_per_tick + possible_cultist.stamina.adjust(8 * seconds_per_tick, TRUE) + possible_cultist.adjustOxyLoss(-healed_amount) + possible_cultist.adjustCloneLoss(-(HEAL_PER_USE / 2) * seconds_per_tick) + possible_cultist.heal_overall_damage(healed_amount, healed_amount, updating_health = TRUE) new /obj/effect/temp_visual/heal(get_turf(possible_cultist), "#1E8CE1") @@ -46,3 +45,4 @@ possible_cultist.reagents?.remove_reagent(negative_chem.type, 2.5 * seconds_per_tick) #undef POWER_PER_USE +#undef HEAL_PER_USE diff --git a/monkestation/code/modules/antagonists/clock_cult/structures/sigil/_sigil.dm b/monkestation/code/modules/antagonists/clock_cult/structures/sigil/_sigil.dm index 1fb54cdee3e3..ac73ed0b74d9 100644 --- a/monkestation/code/modules/antagonists/clock_cult/structures/sigil/_sigil.dm +++ b/monkestation/code/modules/antagonists/clock_cult/structures/sigil/_sigil.dm @@ -56,7 +56,6 @@ if(dispel_check(user)) dispel() - /// For trap sigils and similar; applies effects when someone/something walks over /obj/structure/destructible/clockwork/sigil/proc/on_entered(datum/source, atom/movable/entered_movable) SIGNAL_HANDLER @@ -142,7 +141,7 @@ /// Put any addtional checks you want to do before dispelling here /obj/structure/destructible/clockwork/sigil/proc/dispel_check(mob/user) - . = TRUE + return IS_CLOCK(user) || do_after(user, 10 SECONDS, src) #undef SIGIL_INVOCATION_ALPHA #undef SIGIL_INVOKED_ALPHA diff --git a/monkestation/code/modules/antagonists/clock_cult/structures/sigil/sigil_submission.dm b/monkestation/code/modules/antagonists/clock_cult/structures/sigil/sigil_submission.dm index 242f17a126e1..e9ab4679bc9c 100644 --- a/monkestation/code/modules/antagonists/clock_cult/structures/sigil/sigil_submission.dm +++ b/monkestation/code/modules/antagonists/clock_cult/structures/sigil/sigil_submission.dm @@ -31,7 +31,7 @@ animate(converted_mob.client, color = previous_colour, time = 1 SECONDS) GLOB.main_clock_cult?.check_member_distribution() - if(isdrone(converted_mob) && (GLOB.cogscarabs.len < MAXIMUM_COGSCARABS)) + if(isdrone(converted_mob) && (length(SSthe_ark.cogscarabs) < MAXIMUM_COGSCARABS)) var/mob/living/basic/drone/cogscarab/cogger = new /mob/living/basic/drone/cogscarab(get_turf(src)) cogger.key = converted_mob.key cogger.mind?.add_antag_datum(/datum/antagonist/clock_cultist) @@ -68,6 +68,10 @@ return FALSE /obj/structure/destructible/clockwork/sigil/submission/dispel_check(mob/user) + . = ..() + if(!.) + return if(active_timer) if(IS_CLOCK(user) && tgui_alert(user, "Are you sure you want to dispel [src]? It is currently converting [currently_affecting].", "Confirm dispel", list("Yes", "No")) != "Yes") return FALSE + return TRUE diff --git a/monkestation/code/modules/antagonists/clock_cult/structures/sigil/sigil_transmission.dm b/monkestation/code/modules/antagonists/clock_cult/structures/sigil/sigil_transmission.dm index 186fad4ce7ad..5474d47c1d7c 100644 --- a/monkestation/code/modules/antagonists/clock_cult/structures/sigil/sigil_transmission.dm +++ b/monkestation/code/modules/antagonists/clock_cult/structures/sigil/sigil_transmission.dm @@ -1,4 +1,4 @@ -//these are not actually the amount given and taken but are instead the amount GLOB.clock_power is adjusted by +//these are not actually the amount given and taken but are instead the amount SSthe_ark.clock_power is adjusted by #define POWER_GIVE 5 #define POWER_SIPHON 5 @@ -66,14 +66,14 @@ return if(is_clockie) - if((power_cell.charge < power_cell.maxcharge) && GLOB.clock_power >= POWER_GIVE) + if((power_cell.charge < power_cell.maxcharge) && SSthe_ark.clock_power >= POWER_GIVE) target_mech.give_power(power_cell.chargerate) - GLOB.clock_power -= POWER_GIVE + SSthe_ark.clock_power -= POWER_GIVE else if(power_cell.charge) target_mech.use_power(power_cell.chargerate) - GLOB.clock_power += POWER_SIPHON + SSthe_ark.clock_power += POWER_SIPHON else if(iscyborg(apply_to)) var/mob/living/silicon/robot/borg = apply_to @@ -83,13 +83,13 @@ return if(IS_CLOCK(borg)) - if((power_cell.charge < power_cell.maxcharge) && GLOB.clock_power >= POWER_GIVE) + if((power_cell.charge < power_cell.maxcharge) && SSthe_ark.clock_power >= POWER_GIVE) power_cell.give(power_cell.chargerate) - GLOB.clock_power -= POWER_GIVE + SSthe_ark.clock_power -= POWER_GIVE else if(power_cell.charge > power_cell.chargerate) power_cell.give(-power_cell.chargerate) - GLOB.clock_power += POWER_SIPHON + SSthe_ark.clock_power += POWER_SIPHON else if(ishuman(apply_to)) var/mob/living/carbon/human/human = apply_to @@ -102,14 +102,14 @@ continue if(IS_CLOCK(human)) - if((power_cell.charge < power_cell.maxcharge) && GLOB.clock_power >= POWER_GIVE) + if((power_cell.charge < power_cell.maxcharge) && SSthe_ark.clock_power >= POWER_GIVE) power_cell.give(power_cell.chargerate) - GLOB.clock_power -= POWER_GIVE + SSthe_ark.clock_power -= POWER_GIVE else if(power_cell.charge > power_cell.chargerate) power_cell.give(-power_cell.chargerate) - GLOB.clock_power += POWER_SIPHON + SSthe_ark.clock_power += POWER_SIPHON #undef POWER_GIVE #undef POWER_SIPHON diff --git a/monkestation/code/modules/antagonists/clock_cult/structures/sigil/sigil_vitality.dm b/monkestation/code/modules/antagonists/clock_cult/structures/sigil/sigil_vitality.dm index 1fbeba92fd38..6751661dd5e7 100644 --- a/monkestation/code/modules/antagonists/clock_cult/structures/sigil/sigil_vitality.dm +++ b/monkestation/code/modules/antagonists/clock_cult/structures/sigil/sigil_vitality.dm @@ -24,9 +24,14 @@ return TRUE /obj/structure/destructible/clockwork/sigil/vitality/dispel_check(mob/user) + . = ..() + if(!.) + return + if(active_timer) if(IS_CLOCK(user) && tgui_alert(user, "Are you sure you want to dispel [src]? It is currently siphoning [currently_affecting].", "Confirm dispel", list("Yes", "No")) != "Yes") return FALSE + return TRUE /obj/structure/destructible/clockwork/sigil/vitality/apply_effects(mob/living/affected_mob) . = ..() @@ -86,7 +91,9 @@ check_special_role(affected_mob) GLOB.clock_vitality = min(GLOB.clock_vitality + 40, MAX_CLOCK_VITALITY) // 100 (for clients) total in the ideal situation, since it'll take 6 pulses to go from full to crit if(affected_mob.client) - new /obj/item/robot_suit/prebuilt/clockwork(get_turf(src)) + if(GLOB.clock_ark.current_state >= ARK_STATE_ACTIVE) + new /obj/item/robot_suit/prebuilt/clockwork(get_turf(src)) + var/obj/item/mmi/posibrain/soul_vessel/new_vessel = new(get_turf(src)) if(!is_banned_from(affected_mob.ckey, list(JOB_CYBORG, ROLE_CLOCK_CULTIST))) new_vessel.transfer_personality(affected_mob) diff --git a/monkestation/code/modules/antagonists/clock_cult/structures/stargazer.dm b/monkestation/code/modules/antagonists/clock_cult/structures/stargazer.dm index db898e74c02d..e4600b0c6fa9 100644 --- a/monkestation/code/modules/antagonists/clock_cult/structures/stargazer.dm +++ b/monkestation/code/modules/antagonists/clock_cult/structures/stargazer.dm @@ -62,8 +62,7 @@ if(!enchanting_checks(attacking_item, user)) return - if(istype(attacking_item, /obj/item) && !istype(attacking_item, /obj/item/clothing) && attacking_item.force) - upgrade_weapon(attacking_item, user) + if(istype(attacking_item, /obj/item) && (istype(attacking_item, /obj/item/clothing) || attacking_item.force) && upgrade_weapon(attacking_item, user)) COOLDOWN_START(src, use_cooldown, stargazer_cooldown) return to_chat(user, span_brass("You cannot upgrade \the [attacking_item].")) @@ -79,17 +78,14 @@ return TRUE /obj/structure/destructible/clockwork/gear_base/stargazer/proc/upgrade_weapon(obj/item/upgraded_item, mob/living/user) + if(!attempt_enchantment(upgraded_item, description_span = "")) + return FALSE //Prevent re-enchanting ADD_TRAIT(upgraded_item, TRAIT_STARGAZED, STARGAZER_TRAIT) //Add a glowy colour upgraded_item.add_atom_colour(rgb(243, 227, 183), ADMIN_COLOUR_PRIORITY) - //Pick a random effect - var/static/list/possible_components - if(!possible_components) - possible_components = subtypesof(/datum/component/enchantment) - upgraded_item.AddComponent(pick(possible_components)) to_chat(user, span_notice("\The [upgraded_item] glows with a brilliant light!")) - + return TRUE //The visual effect of the stargazer /obj/effect/stargazer_light diff --git a/monkestation/code/modules/antagonists/clock_cult/structures/the_ark.dm b/monkestation/code/modules/antagonists/clock_cult/structures/the_ark.dm index 73b394c524eb..e88ec87b6ed4 100644 --- a/monkestation/code/modules/antagonists/clock_cult/structures/the_ark.dm +++ b/monkestation/code/modules/antagonists/clock_cult/structures/the_ark.dm @@ -33,6 +33,9 @@ GLOBAL_VAR_INIT(ratvar_risen, FALSE) GLOB.clock_ark = src SSpoints_of_interest.make_point_of_interest(src) + if(!SSthe_ark.initialized) + SSthe_ark.Initialize() + /obj/structure/destructible/clockwork/the_ark/examine(mob/user) . = ..() if(IS_CLOCK(user) || isobserver(user)) @@ -43,6 +46,8 @@ GLOBAL_VAR_INIT(ratvar_risen, FALSE) . += span_brass("The ark is opening, [charging_for ? "defend it until ratvar arrives in [ARK_ASSAULT_PERIOD - charging_for] seconds." : "prepare to defend it!"]") if(ARK_STATE_SUMMONING) . += span_brass("Ratvar has nearly arrived, it will only be [ARK_ASSAULT_PERIOD - charging_for] more seconds!") + if(user.client?.holder) + . += span_warning("ADMIN ONLY WARNING: DELETING THIS WILL END THE ROUND.") /obj/structure/destructible/clockwork/the_ark/Destroy() if(GLOB.clock_ark == src) @@ -132,7 +137,7 @@ GLOBAL_VAR_INIT(ratvar_risen, FALSE) icon_state = "clockwork_gateway_charging" send_clock_message(null, span_bigbrass("The Ark's many cogs suddenly whir to life, steam gushing out of its many crevices; it will open in 5 minutes!"), \ sent_sound = 'sound/magic/clockwork/scripture_tier_up.ogg') - addtimer(CALLBACK(src, PROC_REF(open_gateway)), ARK_READY_PERIOD) + addtimer(CALLBACK(src, PROC_REF(open_gateway)), ARK_READY_PERIOD) //MOVE THIS TO A LOOP ON THE ARK SS /obj/structure/destructible/clockwork/the_ark/proc/open_gateway() if(current_state >= ARK_STATE_GRACE) diff --git a/monkestation/code/modules/antagonists/clock_cult/structures/tinkerers_cache.dm b/monkestation/code/modules/antagonists/clock_cult/structures/tinkerers_cache.dm index e26694e97a8c..0d45a6ff6dbd 100644 --- a/monkestation/code/modules/antagonists/clock_cult/structures/tinkerers_cache.dm +++ b/monkestation/code/modules/antagonists/clock_cult/structures/tinkerers_cache.dm @@ -41,12 +41,12 @@ to_chat(user, span_brass("[src] is still warming up, it will be ready in [DisplayTimeText(COOLDOWN_TIMELEFT(src, use_cooldown))].")) return - var/datum/tinker_cache_item/chosen_item = tgui_input_list(user, "Select an item to create at the forge.", "Forging", \ - (on_reebe(src) ? reebe_craftable : reebe_craftable + station_craftable)) + var/list/valid_list = (on_reebe(src) ? reebe_craftable : reebe_craftable + station_craftable) + var/datum/tinker_cache_item/chosen_item = tgui_input_list(user, "Select an item to create at the forge.", "Forging", valid_list) if(!chosen_item) return - chosen_item = station_craftable[chosen_item] + chosen_item = valid_list[chosen_item] if(!can_interact(user) || !anchored || depowered || !chosen_item || !COOLDOWN_FINISHED(src, use_cooldown)) return @@ -118,6 +118,12 @@ power_use = 400 allowed_on_reebe = FALSE +/datum/tinker_cache_item/borg_shell + name = "Clockwork Cyborg Shell" + item_path = /obj/item/robot_suit/prebuilt/clockwork + power_use = 3000 + allowed_on_reebe = FALSE + /datum/tinker_cache_item/replica_fabricator name = "Replica Fabricator" item_path = /obj/item/clockwork/replica_fabricator diff --git a/monkestation/code/modules/antagonists/clock_cult/turf.dm b/monkestation/code/modules/antagonists/clock_cult/turf.dm index 41c3e5cf1c7a..cac3218ed17e 100644 --- a/monkestation/code/modules/antagonists/clock_cult/turf.dm +++ b/monkestation/code/modules/antagonists/clock_cult/turf.dm @@ -80,6 +80,11 @@ /turf/open/indestructible/reebe_flooring/filled icon_state = "clockwork_floor_filled" +/turf/open/floor/engine/clockwork + name = "clockwork floor" + desc = "You feel a faint warmth from below it." + icon_state = "clockwork_floor" + /turf/closed/wall/clockwork //version created by clock cultists name = "clockwork wall" desc = "A forboding clump of gears that turn on their own. A faint glow emanates from within." @@ -138,7 +143,7 @@ if(COVER_COG_REMOVED) if(item_tool.tool_behaviour == TOOL_SCREWDRIVER) to_chat(user, span_notice("You start to unscrew the transmission cogs.")) - if(next_decon_state(item_tool, user, d_state, TRANSMISSION_COGS_REMOVED, "You unscrew the transmission cogs.", 3 SECONDS)) + if(next_decon_state(item_tool, user, d_state, TRANSMISSION_COGS_REMOVED, "You unscrew the transmission cogs.")) return TRUE else if(item_tool.tool_behaviour == TOOL_WIRECUTTER) item_tool.play_tool_sound(src, 100) @@ -161,7 +166,7 @@ if(!item_tool.tool_start_check(user, amount=0)) return to_chat(user, span_notice("You start to weld the support beam loose.")) - if(next_decon_state(item_tool, user, d_state, INNER_PANEL_REMOVED, "You weld the support beam loose.", 6 SECONDS)) + if(next_decon_state(item_tool, user, d_state, INNER_PANEL_REMOVED, "You weld the support beam loose.", 3 SECONDS)) return TRUE if(item_tool.tool_behaviour == TOOL_WRENCH) to_chat(user, span_notice("You start to re-attach the main gears.")) @@ -171,20 +176,20 @@ if(INNER_PANEL_REMOVED) if(item_tool.tool_behaviour == TOOL_CROWBAR) to_chat(user, span_notice("You start to pry apart the [src].")) - if(next_decon_state(item_tool, user, d_state, sent_message = "You pry apart the [src].", use_time = 5 SECONDS)) + if(next_decon_state(item_tool, user, d_state, sent_message = "You pry apart the [src].")) dismantle_wall() return TRUE if(item_tool.tool_behaviour == TOOL_WELDER) if(!item_tool.tool_start_check(user, amount=0)) return to_chat(user, span_notice("You start to weld the support beam back into place.")) - if(next_decon_state(item_tool, user, d_state, GEARS_UNBOLTED, "You weld the support beam back into place.", 6 SECONDS)) + if(next_decon_state(item_tool, user, d_state, GEARS_UNBOLTED, "You weld the support beam back into place.", 3 SECONDS)) return TRUE if(GEARS_UNWOUND) if(item_tool.tool_behaviour == TOOL_CROWBAR) to_chat(user, span_notice("You tart to pry apart the [src].")) - if(next_decon_state(item_tool, user, d_state, sent_message = "You pry apart the [src].", use_time = 5 SECONDS)) + if(next_decon_state(item_tool, user, d_state, sent_message = "You pry apart the [src].")) dismantle_wall() return TRUE if(item_tool.tool_behaviour == TOOL_WRENCH) @@ -194,7 +199,7 @@ return FALSE //do the deconstruction stuff, this really should be a proc on Rwalls as well -/turf/closed/wall/clockwork/proc/next_decon_state(obj/item/used_tool, mob/user, current_state, set_state, sent_message, use_time = 4 SECONDS) +/turf/closed/wall/clockwork/proc/next_decon_state(obj/item/used_tool, mob/user, current_state, set_state, sent_message, use_time = 2 SECONDS) if(on_reebe(src)) use_time = round(use_time * 0.2, 0.1) //it takes much less time to deconstruct walls on reebe diff --git a/monkestation/code/modules/antagonists/wizard/wizard.dm b/monkestation/code/modules/antagonists/wizard/wizard.dm index 5d9f44d09f33..02d9aa3f3e80 100644 --- a/monkestation/code/modules/antagonists/wizard/wizard.dm +++ b/monkestation/code/modules/antagonists/wizard/wizard.dm @@ -48,3 +48,15 @@ ))) if(newname) ascended_traitor.fully_replace_character_name(ascended_traitor.real_name, newname) + +/proc/make_everyone_wizards() + for(var/mob/living/player_mob in GLOB.alive_player_list) + if(!player_mob.mind) + continue + + if(!ishuman(player_mob)) + var/mob/living/carbon/human/new_mob = new + player_mob.mind.transfer_to(new_mob, TRUE) + qdel(player_mob) + player_mob = new_mob + player_mob.mind.make_wizard() diff --git a/monkestation/code/modules/can_spessmen_feel_pain/pain/_base.dm b/monkestation/code/modules/can_spessmen_feel_pain/pain/_base.dm index 360fcda4f8ba..926021576acd 100644 --- a/monkestation/code/modules/can_spessmen_feel_pain/pain/_base.dm +++ b/monkestation/code/modules/can_spessmen_feel_pain/pain/_base.dm @@ -210,6 +210,19 @@ LAZYREMOVE(pain_mods, key) return update_pain_modifier() +///Clear all pain attributes and bodypart pain +/datum/pain/proc/remove_all_pain() + for(var/zone in body_zones) + var/obj/item/bodypart/healed_bodypart = body_zones[zone] + adjust_bodypart_min_pain(zone, -INFINITY) + adjust_bodypart_pain(zone, -INFINITY) + // Shouldn't be necessary but you never know! + REMOVE_TRAIT(healed_bodypart, TRAIT_PARALYSIS, PAIN_LIMB_PARALYSIS) + + clear_pain_attributes() + shock_buildup = 0 + natural_pain_decay = base_pain_decay + /** * Update our overall pain modifier. * The pain modifier is multiplicative based on all the pain modifiers we have. @@ -919,25 +932,6 @@ if(heal_flags & (HEAL_ADMIN|HEAL_WOUNDS|HEAL_STATUS)) remove_all_pain() -/** - * Remove all pain, pain paralysis, side effects, etc. from our mob after we're fully healed by something (like an adminheal) - */ -/datum/pain/proc/remove_all_pain() - SIGNAL_HANDLER - - for(var/zone in body_zones) - var/obj/item/bodypart/healed_bodypart = body_zones[zone] - if(QDELETED(healed_bodypart)) - continue - adjust_bodypart_min_pain(zone, -INFINITY) - adjust_bodypart_pain(zone, -INFINITY) - // Shouldn't be necessary but you never know! - REMOVE_TRAIT(healed_bodypart, TRAIT_PARALYSIS, PAIN_LIMB_PARALYSIS) - - clear_pain_attributes() - shock_buildup = 0 - natural_pain_decay = base_pain_decay - /** * Determines if we should be processing or not. */ diff --git a/monkestation/code/modules/hallucination/clock_cult_hallucinations.dm b/monkestation/code/modules/hallucination/clock_cult_hallucinations.dm new file mode 100644 index 000000000000..b82403b9e54b --- /dev/null +++ b/monkestation/code/modules/hallucination/clock_cult_hallucinations.dm @@ -0,0 +1,55 @@ +/datum/hallucination/fake_item/clockwork_slab + random_hallucination_weight = 0 + template_item_type = /obj/item/clockwork/clockwork_slab + valid_slots = ITEM_SLOT_HANDS + +/datum/hallucination/nearby_fake_item/clockwork_slab + left_hand_file = 'monkestation/icons/mob/clock_cult/clockwork_lefthand.dmi' + right_hand_file = 'monkestation/icons/mob/clock_cult/clockwork_righthand.dmi' + image_icon_state = "clockwork_slab" + +/datum/hallucination/hazard/clockwork_skewer + random_hallucination_weight = 0 + hazard_type = /obj/effect/client_image_holder/hallucination/danger/clockwork_skewer + +/obj/effect/client_image_holder/hallucination/danger/clockwork_skewer + name = "brass skewer" + image_icon = 'monkestation/icons/obj/clock_cult/clockwork_objects.dmi' + image_state = "brass_skewer" + +/obj/effect/client_image_holder/hallucination/danger/clockwork_skewer/on_hallucinator_entered(mob/living/afflicted) + to_chat(afflicted, span_userdanger("You are impaled by [src]!")) + afflicted.visible_message(span_warning("[afflicted] falls to the ground suddenly!"), ignored_mobs = afflicted) + afflicted.Paralyze(4 SECONDS) + afflicted.emote("scream") + afflicted.stamina.adjust(-80) + image_state = "brass_skewer_pokeybit" + image_layer = ABOVE_MOB_LAYER + update_appearance() + addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), afflicted, span_notice("...You feel the pain of being stabbed fading strangely quickly.")), 1.5 SECONDS) + QDEL_IN(src, 3 SECONDS) + +/datum/hallucination/delusion/preset/clock_cultists + dynamic_delusion = TRUE + random_hallucination_weight = 0 + delusion_name = "Servant of Rat'var" + affects_others = TRUE + skip_nearby = TRUE + +/datum/hallucination/delusion/preset/clock_cultists/make_delusion_image(mob/over_who) + var/static/mutable_appearance/servant_appearance + if(isnull(servant_appearance)) + servant_appearance = get_dynamic_human_appearance(/datum/outfit/clock/preview, r_hand = NO_REPLACE) + delusion_appearance = servant_appearance + return ..() + +/datum/hallucination/fake_sound/weird/clockcult_kindle + sound_type = 'sound/magic/staff_animation.ogg' + +/datum/hallucination/fake_sound/weird/clockcult_kindle/play_fake_sound(turf/source, sound_to_play) + . = ..() + if(prob(50)) + queue_fake_sound(source, 'sound/weapons/handcuffs.ogg', delay = 4 SECONDS) + +/datum/hallucination/fake_sound/weird/clockcult_warp + sound_type = 'sound/magic/magic_missile.ogg' diff --git a/monkestation/code/modules/spells/spell_types/pointed/smite.dm b/monkestation/code/modules/spells/spell_types/pointed/smite.dm index fd91f28e19ec..6f881a063b81 100644 --- a/monkestation/code/modules/spells/spell_types/pointed/smite.dm +++ b/monkestation/code/modules/spells/spell_types/pointed/smite.dm @@ -29,6 +29,8 @@ /datum/smite/knot_shoes, /datum/smite/ocky_icky, /datum/smite/scarify) /datum/action/cooldown/spell/pointed/smite/is_valid_target(atom/cast_on) + if(cast_on == owner) + return FALSE if(!iscarbon(cast_on)) //im just gonna make this only work on carbon mobs cast_on.balloon_alert(owner, "Can only be cast on advanced life forms!") return FALSE diff --git a/monkestation/code/modules/storytellers/converted_events/_base_event.dm b/monkestation/code/modules/storytellers/converted_events/_base_event.dm index 03c7c4095660..8d8c970bc522 100644 --- a/monkestation/code/modules/storytellers/converted_events/_base_event.dm +++ b/monkestation/code/modules/storytellers/converted_events/_base_event.dm @@ -235,7 +235,7 @@ var/list/possible_candidates = cast_control.get_candidates() var/list/candidates = list() if(cast_control == SSgamemode.current_roundstart_event && length(SSgamemode.roundstart_antag_minds)) - log_storyteller("Running roundstart antagonist assignment, event: [src], roundstart_antag_minds: [english_list(SSgamemode.roundstart_antag_minds)]") + log_storyteller("Running roundstart antagonist assignment, event type: [src.type], roundstart_antag_minds: [english_list(SSgamemode.roundstart_antag_minds)]") for(var/datum/mind/antag_mind in SSgamemode.roundstart_antag_minds) if(!antag_mind.current) log_storyteller("Roundstart antagonist setup error: antag_mind([antag_mind]) in roundstart_antag_minds without a set mob") diff --git a/monkestation/code/modules/storytellers/converted_events/solo/clockwork_cult.dm b/monkestation/code/modules/storytellers/converted_events/solo/clockwork_cult.dm index 98f2a7adbbf8..edca30a6e252 100644 --- a/monkestation/code/modules/storytellers/converted_events/solo/clockwork_cult.dm +++ b/monkestation/code/modules/storytellers/converted_events/solo/clockwork_cult.dm @@ -36,7 +36,7 @@ min_players = 45 roundstart = TRUE earliest_start = 0 SECONDS - weight = 0 + weight = 4 max_occurrences = 1 event_icon_state = "clockcult" preferred_events = list(/datum/round_event_control/antagonist/solo/bloodcult = 1) diff --git a/tgstation.dme b/tgstation.dme index fdb97d3a7c8e..ccc14801f9dd 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -609,6 +609,7 @@ #include "code\__HELPERS\~monkestation-helpers\mobs.dm" #include "code\__HELPERS\~monkestation-helpers\records.dm" #include "code\__HELPERS\~monkestation-helpers\roundend.dm" +#include "code\__HELPERS\~monkestation-helpers\spatial_info.dm" #include "code\__HELPERS\~monkestation-helpers\time.dm" #include "code\__HELPERS\~monkestation-helpers\uwuify.dm" #include "code\__HELPERS\~monkestation-helpers\virology.dm" @@ -5935,6 +5936,7 @@ #include "monkestation\code\controllers\subsystem\plexora.dm" #include "monkestation\code\controllers\subsystem\priority_effects.dm" #include "monkestation\code\controllers\subsystem\profiler.dm" +#include "monkestation\code\controllers\subsystem\shuttle.dm" #include "monkestation\code\controllers\subsystem\stamina.dm" #include "monkestation\code\datums\action.dm" #include "monkestation\code\datums\dna.dm" @@ -5969,6 +5971,7 @@ #include "monkestation\code\datums\components\gps.dm" #include "monkestation\code\datums\components\irradiated.dm" #include "monkestation\code\datums\components\lock_on_cursor.dm" +#include "monkestation\code\datums\components\multi_area_bound.dm" #include "monkestation\code\datums\components\multi_hit.dm" #include "monkestation\code\datums\components\pixel_shift.dm" #include "monkestation\code\datums\components\throw_bounce.dm" @@ -5977,6 +5980,19 @@ #include "monkestation\code\datums\components\uplink.dm" #include "monkestation\code\datums\components\wound_converter.dm" #include "monkestation\code\datums\components\crafting\robot.dm" +#include "monkestation\code\datums\components\enchantments\_enchanted.dm" +#include "monkestation\code\datums\components\enchantments\_helpers.dm" +#include "monkestation\code\datums\components\enchantments\antimagic.dm" +#include "monkestation\code\datums\components\enchantments\blinding.dm" +#include "monkestation\code\datums\components\enchantments\blocking.dm" +#include "monkestation\code\datums\components\enchantments\burn.dm" +#include "monkestation\code\datums\components\enchantments\electricution.dm" +#include "monkestation\code\datums\components\enchantments\hardened.dm" +#include "monkestation\code\datums\components\enchantments\haste.dm" +#include "monkestation\code\datums\components\enchantments\penetration.dm" +#include "monkestation\code\datums\components\enchantments\sharpness.dm" +#include "monkestation\code\datums\components\enchantments\soul_tap.dm" +#include "monkestation\code\datums\components\enchantments\tiny.dm" #include "monkestation\code\datums\components\riding\riding_mob.dm" #include "monkestation\code\datums\components\riding\riding_vehicle.dm" #include "monkestation\code\datums\diseases\advance\symptoms\clockwork.dm" @@ -6036,6 +6052,7 @@ #include "monkestation\code\datums\status_effects\changeling.dm" #include "monkestation\code\datums\status_effects\disorient.dm" #include "monkestation\code\datums\status_effects\food_buffs.dm" +#include "monkestation\code\datums\status_effects\debuffs\clock_warp_sickness.dm" #include "monkestation\code\datums\status_effects\debuffs\drunk.dm" #include "monkestation\code\datums\storage\storage.dm" #include "monkestation\code\datums\votes\_vote_datum.dm" @@ -6346,6 +6363,7 @@ #include "monkestation\code\modules\antagonists\clock_cult\turf.dm" #include "monkestation\code\modules\antagonists\clock_cult\actions\_action.dm" #include "monkestation\code\modules\antagonists\clock_cult\actions\add_warp_area.dm" +#include "monkestation\code\modules\antagonists\clock_cult\actions\clockmob_warp.dm" #include "monkestation\code\modules\antagonists\clock_cult\actions\purge_reagents.dm" #include "monkestation\code\modules\antagonists\clock_cult\actions\recall_slab.dm" #include "monkestation\code\modules\antagonists\clock_cult\actions\space_fold.dm" @@ -6355,17 +6373,10 @@ #include "monkestation\code\modules\antagonists\clock_cult\actions\emience_teleports\teleport_to_servant.dm" #include "monkestation\code\modules\antagonists\clock_cult\antag_datums\clock_cult_team.dm" #include "monkestation\code\modules\antagonists\clock_cult\antag_datums\clock_cultist.dm" -#include "monkestation\code\modules\antagonists\clock_cult\enchantments\_enchantment.dm" -#include "monkestation\code\modules\antagonists\clock_cult\enchantments\antimagic.dm" -#include "monkestation\code\modules\antagonists\clock_cult\enchantments\blinding.dm" -#include "monkestation\code\modules\antagonists\clock_cult\enchantments\blocking.dm" -#include "monkestation\code\modules\antagonists\clock_cult\enchantments\burn.dm" -#include "monkestation\code\modules\antagonists\clock_cult\enchantments\electricution.dm" -#include "monkestation\code\modules\antagonists\clock_cult\enchantments\haste.dm" -#include "monkestation\code\modules\antagonists\clock_cult\enchantments\penetration.dm" -#include "monkestation\code\modules\antagonists\clock_cult\enchantments\sharpness.dm" -#include "monkestation\code\modules\antagonists\clock_cult\enchantments\soul_tap.dm" -#include "monkestation\code\modules\antagonists\clock_cult\enchantments\tiny.dm" +#include "monkestation\code\modules\antagonists\clock_cult\antag_datums\clockmob_antag_datum.dm" +#include "monkestation\code\modules\antagonists\clock_cult\antag_datums\eminence_antag_datum.dm" +#include "monkestation\code\modules\antagonists\clock_cult\ark_subsystem\_ark_subsystem.dm" +#include "monkestation\code\modules\antagonists\clock_cult\ark_subsystem\warp_effects.dm" #include "monkestation\code\modules\antagonists\clock_cult\items\clock_stock_parts.dm" #include "monkestation\code\modules\antagonists\clock_cult\items\clockwork_slab.dm" #include "monkestation\code\modules\antagonists\clock_cult\items\clothing.dm" @@ -6374,6 +6385,7 @@ #include "monkestation\code\modules\antagonists\clock_cult\items\soul_vessel.dm" #include "monkestation\code\modules\antagonists\clock_cult\items\tools.dm" #include "monkestation\code\modules\antagonists\clock_cult\items\weaponry.dm" +#include "monkestation\code\modules\antagonists\clock_cult\machines\airlock.dm" #include "monkestation\code\modules\antagonists\clock_cult\machines\clock_sleeper.dm" #include "monkestation\code\modules\antagonists\clock_cult\machines\clockwork_operating_computer.dm" #include "monkestation\code\modules\antagonists\clock_cult\machines\comms_relay.dm" @@ -6411,7 +6423,6 @@ #include "monkestation\code\modules\antagonists\clock_cult\scriptures\structures\transmission_sigil.dm" #include "monkestation\code\modules\antagonists\clock_cult\structures\_powered.dm" #include "monkestation\code\modules\antagonists\clock_cult\structures\_structure.dm" -#include "monkestation\code\modules\antagonists\clock_cult\structures\airlock.dm" #include "monkestation\code\modules\antagonists\clock_cult\structures\anchor_crystal.dm" #include "monkestation\code\modules\antagonists\clock_cult\structures\brass_window.dm" #include "monkestation\code\modules\antagonists\clock_cult\structures\eminence_beacon.dm" @@ -7388,6 +7399,7 @@ #include "monkestation\code\modules\ghost_players\job_helpers\injured_spawner.dm" #include "monkestation\code\modules\ghost_players\job_helpers\organ_printer.dm" #include "monkestation\code\modules\goonimizations\goon_keybinds.dm" +#include "monkestation\code\modules\hallucination\clock_cult_hallucinations.dm" #include "monkestation\code\modules\holomaps\areas.dm" #include "monkestation\code\modules\holomaps\base_datum.dm" #include "monkestation\code\modules\holomaps\huds.dm" diff --git a/tgui/packages/tgui/interfaces/AntagInfoClock.tsx b/tgui/packages/tgui/interfaces/AntagInfoClock.tsx index b03f898c4c66..70e9d59a1d02 100644 --- a/tgui/packages/tgui/interfaces/AntagInfoClock.tsx +++ b/tgui/packages/tgui/interfaces/AntagInfoClock.tsx @@ -11,11 +11,12 @@ type Objective = { type Info = { antag_name: string; objectives: Objective[]; + marked_areas: string[]; }; export const AntagInfoClock = (props) => { const { data } = useBackend(); - const { antag_name } = data; + const { antag_name, marked_areas } = data; return ( @@ -29,6 +30,7 @@ export const AntagInfoClock = (props) => { + {'Our marked areas are: ' + marked_areas} diff --git a/tgui/packages/tgui/interfaces/ClockworkSlab.jsx b/tgui/packages/tgui/interfaces/ClockworkSlab.jsx index c7e06b08d190..e839be34c7be 100644 --- a/tgui/packages/tgui/interfaces/ClockworkSlab.jsx +++ b/tgui/packages/tgui/interfaces/ClockworkSlab.jsx @@ -93,8 +93,8 @@ const ClockworkHelp = (props) => { to unlock more scriptures and siphon power!

- Hover over the button for a scripture to get additonal information for - it. + Hover over the button to invoke a scripture to get additonal + information for it.