diff --git a/code/_globalvars/game_modes.dm b/code/_globalvars/game_modes.dm index 7747a6fb93..12fb1bae48 100644 --- a/code/_globalvars/game_modes.dm +++ b/code/_globalvars/game_modes.dm @@ -7,6 +7,7 @@ GLOBAL_DATUM(start_state, /datum/station_state) // Used in round-end report // Cult, needs to be global so admin cultists are functional GLOBAL_VAR_INIT(blood_target, null) // Cult Master's target or Construct's Master GLOBAL_DATUM(blood_target_image, /image) +GLOBAL_VAR_INIT(blood_target_reset_timer, null) GLOBAL_DATUM(sac_mind, /datum/mind) GLOBAL_VAR_INIT(sac_image, null) GLOBAL_VAR_INIT(cult_vote_called, FALSE) diff --git a/code/game/gamemodes/clock_cult/clock_structures/ratvar_the_clockwork_justicar.dm b/code/game/gamemodes/clock_cult/clock_structures/ratvar_the_clockwork_justicar.dm index a8dfb2dd4a..b82e9a9c85 100644 --- a/code/game/gamemodes/clock_cult/clock_structures/ratvar_the_clockwork_justicar.dm +++ b/code/game/gamemodes/clock_cult/clock_structures/ratvar_the_clockwork_justicar.dm @@ -117,12 +117,10 @@ if(!isnewplayer(M)) flash_color(M, flash_color="#966400", flash_time=1) shake_camera(M, 4, 3) - var/ratvar_chance = min(SSticker.mode.servants_of_ratvar.len, 50) - var/narsie_chance = SSticker.mode.cult.len - for(var/mob/living/simple_animal/hostile/construct/harvester/C in GLOB.player_list) - narsie_chance++ + var/ratvar_chance = min(LAZYLEN(SSticker.mode.servants_of_ratvar), 50) + var/narsie_chance = min(LAZYLEN(SSticker.mode.cult), 50) ratvar_chance = rand(base_victory_chance, ratvar_chance) - narsie_chance = rand(base_victory_chance, min(narsie_chance, 50)) + narsie_chance = rand(base_victory_chance, narsie_chance) if(ratvar_chance > narsie_chance) winner = "Ratvar" break diff --git a/code/game/gamemodes/cult/cult.dm b/code/game/gamemodes/cult/cult.dm index 28c22d695a..32b88724bf 100644 --- a/code/game/gamemodes/cult/cult.dm +++ b/code/game/gamemodes/cult/cult.dm @@ -279,12 +279,13 @@ var/explanation switch(cult_objectives[obj_count]) if("sacrifice") - if(GLOB.sac_complete) - explanation = "Sacrifice [GLOB.sac_mind], the [GLOB.sac_mind.assigned_role]. Success!" - SSblackbox.add_details("cult_objective","cult_sacrifice|SUCCESS") - else - explanation = "Sacrifice [GLOB.sac_mind], the [GLOB.sac_mind.assigned_role]. Fail." - SSblackbox.add_details("cult_objective","cult_sacrifice|FAIL") + if(GLOB.sac_mind) + if(GLOB.sac_complete) + explanation = "Sacrifice [GLOB.sac_mind], the [GLOB.sac_mind.assigned_role]. Success!" + SSblackbox.add_details("cult_objective","cult_sacrifice|SUCCESS") + else + explanation = "Sacrifice [GLOB.sac_mind], the [GLOB.sac_mind.assigned_role]. Fail." + SSblackbox.add_details("cult_objective","cult_sacrifice|FAIL") if("eldergod") if(!eldergod) explanation = "Summon Nar-Sie. Success!" diff --git a/code/game/gamemodes/cult/cult_comms.dm b/code/game/gamemodes/cult/cult_comms.dm index 781714c716..6258ea284d 100644 --- a/code/game/gamemodes/cult/cult_comms.dm +++ b/code/game/gamemodes/cult/cult_comms.dm @@ -141,7 +141,7 @@ to_chat(B.current, "[Nominee] could not win the cult's support and shall continue to serve as an acolyte.") return FALSE GLOB.cult_mastered = TRUE - SSticker.mode.remove_cultist(Nominee.mind, FALSE) + SSticker.mode.remove_cultist(Nominee.mind, TRUE) Nominee.mind.add_antag_datum(ANTAG_DATUM_CULT_MASTER) for(var/datum/mind/B in SSticker.mode.cult) if(B.current) @@ -288,7 +288,7 @@ B.current.client.images += GLOB.blood_target_image attached_action.owner.update_action_buttons_icon() remove_ranged_ability("The marking rite is complete! It will last for 90 seconds.") - addtimer(CALLBACK(GLOBAL_PROC, .proc/reset_blood_target), 900, TIMER_OVERRIDE) + GLOB.blood_target_reset_timer = addtimer(CALLBACK(GLOBAL_PROC, .proc/reset_blood_target), 900, TIMER_STOPPABLE) return TRUE return FALSE diff --git a/code/game/gamemodes/cult/runes.dm b/code/game/gamemodes/cult/runes.dm index 8c01d361c0..40cad5c0dd 100644 --- a/code/game/gamemodes/cult/runes.dm +++ b/code/game/gamemodes/cult/runes.dm @@ -481,7 +481,12 @@ structure_check() searches for nearby cultist structures required for the invoca if(src) color = "#FF0000" SSticker.mode.eldergod = FALSE - new /obj/singularity/narsie/large(T) //Causes Nar-Sie to spawn even if the rune has been removed + deltimer(GLOB.blood_target_reset_timer) + GLOB.blood_target = new /obj/singularity/narsie/large(T) //Causes Nar-Sie to spawn even if the rune has been removed + for(var/datum/mind/cult_mind in SSticker.mode.cult) + if(isliving(cult_mind.current)) + var/mob/living/L = cult_mind.current + L.narsie_act() /obj/effect/rune/narsie/attackby(obj/I, mob/user, params) //Since the narsie rune takes a long time to make, add logging to removal. if((istype(I, /obj/item/weapon/tome) && iscultist(user))) diff --git a/code/game/gamemodes/wizard/soulstone.dm b/code/game/gamemodes/wizard/soulstone.dm index d3aeef178c..503fc0f396 100644 --- a/code/game/gamemodes/wizard/soulstone.dm +++ b/code/game/gamemodes/wizard/soulstone.dm @@ -216,9 +216,8 @@ to_chat(newstruct, "You are still bound to serve the cult[stoner ? " and [stoner]":""], follow their orders and help them complete their goals at all costs.") else if(stoner) to_chat(newstruct, "You are still bound to serve your creator, [stoner], follow their orders and help them complete their goals at all costs.") - newstruct.throw_alert("bloodsense", /obj/screen/alert/bloodsense) - var/obj/screen/alert/bloodsense/BS = newstruct.alerts["bloodsense"] - BS.Cviewer = newstruct + var/obj/screen/alert/bloodsense/BS = newstruct.throw_alert("bloodsense", /obj/screen/alert/bloodsense) + BS.Cviewer = newstruct newstruct.cancel_camera() @@ -271,4 +270,4 @@ T.dropItemToGround(W) init_shade(T, U) qdel(T) - return 1 + return 1 \ No newline at end of file diff --git a/code/game/machinery/computer/computer.dm b/code/game/machinery/computer/computer.dm index 74fcf77ce5..9819d4374a 100644 --- a/code/game/machinery/computer/computer.dm +++ b/code/game/machinery/computer/computer.dm @@ -52,7 +52,7 @@ update_icon() /obj/machinery/computer/narsie_act() - if(clockwork && clockwork != initial(clockwork) && prob(20)) //if it's clockwork but isn't normally clockwork + if(clockwork && clockwork != initial(clockwork)) //if it's clockwork but isn't normally clockwork clockwork = FALSE icon_screen = initial(icon_screen) icon_keyboard = initial(icon_keyboard) diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 7ff38f53c9..1750aa7aa8 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -179,18 +179,17 @@ /obj/machinery/door/airlock/narsie_act() var/turf/T = get_turf(src) var/runed = prob(20) - if(prob(20)) - if(glass) - if(runed) - new/obj/machinery/door/airlock/cult/glass(T) - else - new/obj/machinery/door/airlock/cult/unruned/glass(T) + if(glass) + if(runed) + new/obj/machinery/door/airlock/cult/glass(T) else - if(runed) - new/obj/machinery/door/airlock/cult(T) - else - new/obj/machinery/door/airlock/cult/unruned(T) - qdel(src) + new/obj/machinery/door/airlock/cult/unruned/glass(T) + else + if(runed) + new/obj/machinery/door/airlock/cult(T) + else + new/obj/machinery/door/airlock/cult/unruned(T) + qdel(src) /obj/machinery/door/airlock/ratvar_act() //Airlocks become pinion airlocks that only allow servants if(glass) diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index 9657c7d888..2336aa71ed 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -71,9 +71,8 @@ GLOBAL_LIST_INIT(metal_recipes, list ( \ qdel(src) /obj/item/stack/sheet/metal/narsie_act() - if(prob(20)) - new /obj/item/stack/sheet/runed_metal(loc, amount) - qdel(src) + new /obj/item/stack/sheet/runed_metal(loc, amount) + qdel(src) /obj/item/stack/sheet/metal/fifty amount = 50 @@ -325,9 +324,8 @@ GLOBAL_LIST_INIT(brass_recipes, list ( \ turf_type = /turf/open/floor/clockwork /obj/item/stack/tile/brass/narsie_act() - if(prob(20)) - new /obj/item/stack/sheet/runed_metal(loc, amount) - qdel(src) + new /obj/item/stack/sheet/runed_metal(loc, amount) + qdel(src) /obj/item/stack/tile/brass/Initialize(mapload, new_amount, merge = TRUE) recipes = GLOB.brass_recipes diff --git a/code/game/objects/structures/beds_chairs/chair.dm b/code/game/objects/structures/beds_chairs/chair.dm index 87560f426f..7202aeae1c 100644 --- a/code/game/objects/structures/beds_chairs/chair.dm +++ b/code/game/objects/structures/beds_chairs/chair.dm @@ -37,10 +37,9 @@ return attack_hand(user) /obj/structure/chair/narsie_act() - if(prob(20)) - var/obj/structure/chair/wood/W = new/obj/structure/chair/wood(get_turf(src)) - W.setDir(dir) - qdel(src) + var/obj/structure/chair/wood/W = new/obj/structure/chair/wood(get_turf(src)) + W.setDir(dir) + qdel(src) /obj/structure/chair/attackby(obj/item/weapon/W, mob/user, params) if(istype(W, /obj/item/weapon/wrench) && !(flags&NODECONSTRUCT)) @@ -239,10 +238,9 @@ var/obj/structure/chair/origin_type = /obj/structure/chair /obj/item/chair/narsie_act() - if(prob(20)) - var/obj/item/chair/wood/W = new/obj/item/chair/wood(get_turf(src)) - W.setDir(dir) - qdel(src) + var/obj/item/chair/wood/W = new/obj/item/chair/wood(get_turf(src)) + W.setDir(dir) + qdel(src) /obj/item/chair/attack_self(mob/user) plant(user) diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm index 9f37710d78..bdf2a5eb40 100644 --- a/code/game/objects/structures/girders.dm +++ b/code/game/objects/structures/girders.dm @@ -297,9 +297,8 @@ qdel(src) /obj/structure/girder/narsie_act() - if(prob(25)) - new /obj/structure/girder/cult(loc) - qdel(src) + new /obj/structure/girder/cult(loc) + qdel(src) /obj/structure/girder/displaced name = "displaced girder" diff --git a/code/game/objects/structures/table_frames.dm b/code/game/objects/structures/table_frames.dm index b6837015f1..50aa23434e 100644 --- a/code/game/objects/structures/table_frames.dm +++ b/code/game/objects/structures/table_frames.dm @@ -84,9 +84,8 @@ qdel(src) /obj/structure/table_frame/narsie_act() - if(prob(20)) - new /obj/structure/table_frame/wood(src.loc) - qdel(src) + new /obj/structure/table_frame/wood(src.loc) + qdel(src) /obj/structure/table_frame/ratvar_act() new /obj/structure/table_frame/brass(src.loc) diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index c42b61a622..cbb0fcc5f7 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -47,8 +47,7 @@ queue_smooth_neighbors(src) /obj/structure/table/narsie_act() - if(prob(20)) - new /obj/structure/table/wood(src.loc) + new /obj/structure/table/wood(src.loc) /obj/structure/table/ratvar_act() new /obj/structure/table/reinforced/brass(src.loc) diff --git a/code/game/turfs/simulated/floor.dm b/code/game/turfs/simulated/floor.dm index 5f581fba63..c1993677f3 100644 --- a/code/game/turfs/simulated/floor.dm +++ b/code/game/turfs/simulated/floor.dm @@ -188,8 +188,9 @@ else if(prob(50)) ReplaceWithLattice() -/turf/open/floor/narsie_act() - if(prob(20)) +/turf/open/floor/narsie_act(force, ignore_mobs, probability = 20) + . = ..() + if(.) ChangeTurf(/turf/open/floor/engine/cult) /turf/open/floor/ratvar_act(force, ignore_mobs) diff --git a/code/game/turfs/simulated/floor/fancy_floor.dm b/code/game/turfs/simulated/floor/fancy_floor.dm index cce7756892..4f6da47bde 100644 --- a/code/game/turfs/simulated/floor/fancy_floor.dm +++ b/code/game/turfs/simulated/floor/fancy_floor.dm @@ -158,8 +158,14 @@ if(smooth) queue_smooth_neighbors(src) -/turf/open/floor/carpet/narsie_act() - return +/turf/open/floor/carpet/narsie_act(force, ignore_mobs, probability = 20) + . = (prob(probability) || force) + for(var/I in src) + var/atom/A = I + if(ignore_mobs && ismob(A)) + continue + if(ismob(A) || .) + A.narsie_act() /turf/open/floor/carpet/break_tile() broken = 1 diff --git a/code/game/turfs/simulated/floor/misc_floor.dm b/code/game/turfs/simulated/floor/misc_floor.dm index 79ad84e752..9144cbc871 100644 --- a/code/game/turfs/simulated/floor/misc_floor.dm +++ b/code/game/turfs/simulated/floor/misc_floor.dm @@ -250,9 +250,10 @@ if(severity < 3 || target == src) ChangeTurf(src.baseturf) -/turf/open/floor/vines/narsie_act() - if(prob(20)) - ChangeTurf(src.baseturf) //nar sie eats this shit +/turf/open/floor/vines/narsie_act(force, ignore_mobs, probability = 20) + if(prob(probability) || force) + ChangeTurf(baseturf) //nar sie eats this shit + narsie_act(force, ignore_mobs, probability) /turf/open/floor/vines/singularity_pull(S, current_size) if(current_size >= STAGE_FIVE) diff --git a/code/game/turfs/simulated/floor/reinf_floor.dm b/code/game/turfs/simulated/floor/reinf_floor.dm index bbc61d54d3..9c40b8276f 100644 --- a/code/game/turfs/simulated/floor/reinf_floor.dm +++ b/code/game/turfs/simulated/floor/reinf_floor.dm @@ -125,9 +125,6 @@ qdel(realappearence) realappearence = null -/turf/open/floor/engine/cult/narsie_act() - return - /turf/open/floor/engine/cult/ratvar_act() . = ..() if(istype(src, /turf/open/floor/engine/cult)) //if we haven't changed type diff --git a/code/game/turfs/simulated/wall/misc_walls.dm b/code/game/turfs/simulated/wall/misc_walls.dm index a0ed982144..9fa69fc6a7 100644 --- a/code/game/turfs/simulated/wall/misc_walls.dm +++ b/code/game/turfs/simulated/wall/misc_walls.dm @@ -4,19 +4,27 @@ icon = 'icons/turf/walls/cult_wall.dmi' icon_state = "cult" canSmoothWith = null + smooth = SMOOTH_MORE sheet_type = /obj/item/stack/sheet/runed_metal sheet_amount = 1 girder_type = /obj/structure/girder/cult /turf/closed/wall/mineral/cult/Initialize() new /obj/effect/overlay/temp/cult/turf(src) - ..() + . = ..() /turf/closed/wall/mineral/cult/devastate_wall() new sheet_type(get_turf(src), sheet_amount) -/turf/closed/wall/mineral/cult/narsie_act() - return +/turf/closed/wall/mineral/cult/Exited(atom/movable/AM, atom/newloc) + . = ..() + if(istype(AM, /mob/living/simple_animal/hostile/construct/harvester)) //harvesters can go through cult walls, dragging something with + var/mob/living/simple_animal/hostile/construct/harvester/H = AM + var/atom/movable/stored_pulling = H.pulling + if(stored_pulling) + stored_pulling.setDir(get_dir(stored_pulling.loc, newloc)) + stored_pulling.forceMove(src) + H.start_pulling(stored_pulling, TRUE) /turf/closed/wall/mineral/cult/ratvar_act() . = ..() diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm index 1aea3d7dbc..820a54da42 100644 --- a/code/game/turfs/simulated/walls.dm +++ b/code/game/turfs/simulated/walls.dm @@ -238,8 +238,9 @@ if(prob(30)) dismantle_wall() -/turf/closed/wall/narsie_act() - if(prob(20)) +/turf/closed/wall/narsie_act(force, ignore_mobs, probability = 20) + . = ..() + if(.) ChangeTurf(/turf/closed/wall/mineral/cult) /turf/closed/wall/ratvar_act(force, ignore_mobs) diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 618894f207..96e3b9c590 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -375,6 +375,15 @@ A.ex_act(severity, target) CHECK_TICK +/turf/narsie_act(force, ignore_mobs, probability = 20) + . = (prob(probability) || force) + for(var/I in src) + var/atom/A = I + if(ignore_mobs && ismob(A)) + continue + if(ismob(A) || .) + A.narsie_act() + /turf/ratvar_act(force, ignore_mobs, probability = 40) . = (prob(probability) || force) for(var/I in src) diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 316a7a3b83..0599aaaa8a 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -127,22 +127,21 @@ GLOBAL_VAR_INIT(observer_default_invisibility, INVISIBILITY_OBSERVER) /mob/dead/observer/narsie_act() var/old_color = color color = "#960000" - animate(src, color = old_color, time = 10) + animate(src, color = old_color, time = 10, flags = ANIMATION_PARALLEL) addtimer(CALLBACK(src, /atom/proc/update_atom_colour), 10) /mob/dead/observer/ratvar_act() var/old_color = color color = "#FAE48C" - animate(src, color = old_color, time = 10) + animate(src, color = old_color, time = 10, flags = ANIMATION_PARALLEL) addtimer(CALLBACK(src, /atom/proc/update_atom_colour), 10) +/mob/dead/observer/Destroy() GLOB.ghost_images_default -= ghostimage_default - qdel(ghostimage_default) - ghostimage_default = null + QDEL_NULL(ghostimage_default) GLOB.ghost_images_simple -= ghostimage_simple - qdel(ghostimage_simple) - ghostimage_simple = null + QDEL_NULL(ghostimage_simple) updateallghostimages() return ..() diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index e4129e642d..d15d71c23c 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -306,17 +306,15 @@ reagents.add_reagent("heparin", 5) return FALSE if(client) - makeNewConstruct(/mob/living/simple_animal/hostile/construct/harvester, src, null, 0) + makeNewConstruct(/mob/living/simple_animal/hostile/construct/harvester, src, cultoverride = TRUE) else - switch(rand(1, 10)) + switch(rand(1, 6)) if(1) new /mob/living/simple_animal/hostile/construct/armored/hostile(get_turf(src)) if(2) new /mob/living/simple_animal/hostile/construct/wraith/hostile(get_turf(src)) if(3 to 6) new /mob/living/simple_animal/hostile/construct/builder/hostile(get_turf(src)) - if(6 to 10) - new /mob/living/simple_animal/hostile/construct/harvester/hostile(get_turf(src)) spawn_dust() gib() return TRUE diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm index 304eb31e11..c0f88e3641 100644 --- a/code/modules/mob/living/simple_animal/constructs.dm +++ b/code/modules/mob/living/simple_animal/constructs.dm @@ -27,25 +27,22 @@ unique_name = 1 AIStatus = AI_OFF //normal constructs don't have AI loot = list(/obj/item/weapon/ectoplasm) - del_on_death = TRUE - initial_language_holder = /datum/language_holder/construct + del_on_death = TRUE + initial_language_holder = /datum/language_holder/construct deathmessage = "collapses in a shattered heap." var/list/construct_spells = list() var/playstyle_string = "You are a generic construct! Your job is to not exist, and you should probably adminhelp this." var/master = null var/seeking = FALSE + var/can_repair_constructs = FALSE + var/can_repair_self = FALSE /mob/living/simple_animal/hostile/construct/Initialize() . = ..() + update_health_hud() for(var/spell in construct_spells) AddSpell(new spell(null)) -/mob/living/simple_animal/hostile/construct/Destroy() - for(var/X in actions) - var/datum/action/A = X - qdel(A) - ..() - /mob/living/simple_animal/hostile/construct/Login() ..() to_chat(src, playstyle_string) @@ -67,7 +64,10 @@ to_chat(user, msg) /mob/living/simple_animal/hostile/construct/attack_animal(mob/living/simple_animal/M) - if(istype(M, /mob/living/simple_animal/hostile/construct/builder)) + if(isconstruct(M)) //is it a construct? + var/mob/living/simple_animal/hostile/construct/C = M + if(!C.can_repair_constructs || (C == src && !C.can_repair_self)) + return if(health < maxHealth) adjustHealth(-5) if(src != M) @@ -128,38 +128,6 @@ AIStatus = AI_ON environment_smash = 1 //only token destruction, don't smash the cult wall NO STOP - -///////////////////////Master-Tracker/////////////////////// - -/datum/action/innate/seek_master - name = "Seek your Master" - desc = "You and your master share a soul-link that informs you of their location" - background_icon_state = "bg_demon" - buttontooltipstyle = "cult" - button_icon_state = "cult_mark" - var/tracking = FALSE - var/mob/living/simple_animal/hostile/construct/the_construct - -/datum/action/innate/seek_master/Grant(var/mob/living/C) - the_construct = C - ..() - -/datum/action/innate/seek_master/Activate() - if(!the_construct.master) - to_chat(the_construct, "You have no master to seek!") - the_construct.seeking = FALSE - return - if(tracking) - tracking = FALSE - the_construct.seeking = FALSE - to_chat(the_construct, "You are no longer tracking your master.") - return - else - tracking = TRUE - the_construct.seeking = TRUE - to_chat(the_construct, "You are now tracking your master.") - - /mob/living/simple_animal/hostile/construct/armored/bullet_act(obj/item/projectile/P) if(istype(P, /obj/item/projectile/energy) || istype(P, /obj/item/projectile/beam)) var/reflectchance = 80 - round(P.damage/3) @@ -203,30 +171,7 @@ attacktext = "slashes" attack_sound = 'sound/weapons/bladeslice.ogg' construct_spells = list(/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift) - playstyle_string = "You are a Wraith. Though relatively fragile, you are fast, deadly, can phase through walls, and your attacks will lower the cooldown on phasing." - var/attack_refund = 10 //1 second per attack - var/crit_refund = 50 //5 seconds when putting a target into critical - var/kill_refund = 250 //full refund on kills - -/mob/living/simple_animal/hostile/construct/wraith/AttackingTarget() //refund jaunt cooldown when attacking living targets - var/prev_stat - if(isliving(target) && !iscultist(target)) - var/mob/living/L = target - prev_stat = L.stat - - . = ..() - - if(. && isnum(prev_stat)) - var/mob/living/L = target - var/refund = 0 - if(QDELETED(L) || (L.stat == DEAD && prev_stat != DEAD)) //they're dead, you killed them - refund += kill_refund - else if(L.InCritical() && prev_stat == CONSCIOUS) //you knocked them into critical - refund += crit_refund - if(L.stat != DEAD && prev_stat != DEAD) - refund += attack_refund - for(var/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift/S in mob_spell_list) - S.charge_counter = min(S.charge_counter + refund, S.charge_max) + playstyle_string = "You are a Wraith. Though relatively fragile, you are fast, deadly, and even able to phase through walls." /mob/living/simple_animal/hostile/construct/wraith/hostile //actually hostile, will move around, hit things AIStatus = AI_ON @@ -261,6 +206,8 @@ use magic missile, repair allied constructs, shades, and yourself (by clicking on them), \ and, most important of all, create new constructs by producing soulstones to capture souls, \ and shells to place those soulstones into." + can_repair_constructs = TRUE + can_repair_self = TRUE /mob/living/simple_animal/hostile/construct/builder/Found(atom/A) //what have we found here? if(isconstruct(A)) //is it a construct? @@ -322,22 +269,81 @@ icon_living = "harvester" maxHealth = 60 health = 60 - melee_damage_lower = 1 - melee_damage_upper = 5 - retreat_distance = 2 //AI harvesters will move in and out of combat, like wraiths, but shittier - attacktext = "prods" - environment_smash = 3 - attack_sound = 'sound/weapons/tap.ogg' - construct_spells = list(/obj/effect/proc_holder/spell/aoe_turf/conjure/wall, - /obj/effect/proc_holder/spell/aoe_turf/conjure/floor, - /obj/effect/proc_holder/spell/targeted/smoke/disable) - playstyle_string = "You are a Harvester. You are not strong, but your powers of domination will assist you in your role: \ + sight = SEE_MOBS + melee_damage_lower = 15 + melee_damage_upper = 20 + attacktext = "butchers" + attack_sound = 'sound/weapons/bladeslice.ogg' + construct_spells = list(/obj/effect/proc_holder/spell/aoe_turf/area_conversion, + /obj/effect/proc_holder/spell/aoe_turf/conjure/lesserforcewall) + playstyle_string = "You are a Harvester. You are incapable of directly killing humans, but your attacks will remove their limbs: \ Bring those who still cling to this world of illusion back to the Geometer so they may know Truth." + can_repair_constructs = TRUE -/mob/living/simple_animal/hostile/construct/harvester/hostile //actually hostile, will move around, hit things - AIStatus = AI_ON - environment_smash = 1 //only token destruction, don't smash the cult wall NO STOP +/mob/living/simple_animal/hostile/construct/harvester/Bump(atom/AM) + . = ..() + if(istype(AM, /turf/closed/wall/mineral/cult) && AM != loc) //we can go through cult walls + var/atom/movable/stored_pulling = pulling + if(stored_pulling) + stored_pulling.setDir(get_dir(stored_pulling.loc, loc)) + stored_pulling.forceMove(loc) + forceMove(AM) + if(stored_pulling) + start_pulling(stored_pulling, TRUE) //drag anything we're pulling through the wall with us by magic +/mob/living/simple_animal/hostile/construct/harvester/AttackingTarget() + if(iscarbon(target)) + var/mob/living/carbon/C = target + var/list/parts = list() + var/undismembermerable_limbs = 0 + for(var/X in C.bodyparts) + var/obj/item/bodypart/BP = X + if(BP.body_part != HEAD && BP.body_part != CHEST) + if(BP.dismemberable) + parts += BP + else + undismembermerable_limbs++ + if(!LAZYLEN(parts)) + if(undismembermerable_limbs) //they have limbs we can't remove, and no parts we can, attack! + return ..() + to_chat(src, "\"Bring [C.p_them()] to me.\"") + return FALSE + do_attack_animation(C) + var/obj/item/bodypart/BP = pick(parts) + BP.dismember() + return FALSE + . = ..() + + +///////////////////////Master-Tracker/////////////////////// + +/datum/action/innate/seek_master + name = "Seek your Master" + desc = "You and your master share a soul-link that informs you of their location" + background_icon_state = "bg_demon" + buttontooltipstyle = "cult" + button_icon_state = "cult_mark" + var/tracking = FALSE + var/mob/living/simple_animal/hostile/construct/the_construct + +/datum/action/innate/seek_master/Grant(var/mob/living/C) + the_construct = C + ..() + +/datum/action/innate/seek_master/Activate() + if(!the_construct.master) + to_chat(the_construct, "You have no master to seek!") + the_construct.seeking = FALSE + return + if(tracking) + tracking = FALSE + the_construct.seeking = FALSE + to_chat(the_construct, "You are no longer tracking your master.") + return + else + tracking = TRUE + the_construct.seeking = TRUE + to_chat(the_construct, "You are now tracking your master.") /////////////////////////////ui stuff///////////////////////////// @@ -355,4 +361,4 @@ else if(health > maxHealth*0.2) hud_used.healths.icon_state = "[icon_state]_health5" else - hud_used.healths.icon_state = "[icon_state]_health6" \ No newline at end of file + hud_used.healths.icon_state = "[icon_state]_health6" diff --git a/code/modules/mob/living/simple_animal/shade.dm b/code/modules/mob/living/simple_animal/shade.dm index 6ebac2394c..7dfb76f579 100644 --- a/code/modules/mob/living/simple_animal/shade.dm +++ b/code/modules/mob/living/simple_animal/shade.dm @@ -44,7 +44,10 @@ return TRUE //this doesn't make much sense; you'd thing TRUE would mean it'd process spacemove but it means it doesn't /mob/living/simple_animal/shade/attack_animal(mob/living/simple_animal/M) - if(istype(M, /mob/living/simple_animal/hostile/construct/builder)) + if(isconstruct(M)) + var/mob/living/simple_animal/hostile/construct/C = M + if(!C.can_repair_constructs) + return if(health < maxHealth) adjustHealth(-25) Beam(M,icon_state="sendbeam",time=4) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index a5fdc3ed1c..d4333872e1 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -331,12 +331,14 @@ changeNext_move(CLICK_CD_GRABBING) if(AM.pulledby) - visible_message("[src] has pulled [AM] from [AM.pulledby]'s grip.") + if(!supress_message) + visible_message("[src] has pulled [AM] from [AM.pulledby]'s grip.") AM.pulledby.stop_pulling() //an object can't be pulled by two mobs at once. pulling = AM AM.pulledby = src - playsound(src.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + if(!supress_message) + playsound(src.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) update_pull_hud_icon() if(ismob(AM)) diff --git a/code/modules/power/singularity/narsie.dm b/code/modules/power/singularity/narsie.dm index fb2df4deeb..1997b6bcbd 100644 --- a/code/modules/power/singularity/narsie.dm +++ b/code/modules/power/singularity/narsie.dm @@ -39,13 +39,12 @@ narsie_spawn_animation() - sleep(70) - SSshuttle.emergency.request(null, set_coefficient = 0.1) // Cannot recall + sleep(19) + SSshuttle.emergency.request(null, set_coefficient = 0) //instantly arrives /obj/singularity/narsie/large/attack_ghost(mob/dead/observer/user as mob) - makeNewConstruct(/mob/living/simple_animal/hostile/construct/harvester, user, null, 0, loc_override = src.loc) - new /obj/effect/particle_effect/smoke/sleeping(src.loc) + makeNewConstruct(/mob/living/simple_animal/hostile/construct/harvester, user, cultoverride = TRUE, loc_override = src.loc) /obj/singularity/narsie/process() @@ -82,7 +81,8 @@ /obj/singularity/narsie/consume(atom/A) - A.narsie_act() + if(isturf(A)) + A.narsie_act() /obj/singularity/narsie/ex_act() //No throwing bombs at her either. diff --git a/code/modules/spells/spell_types/construct_spells.dm b/code/modules/spells/spell_types/construct_spells.dm index c59af27ddd..b6898afdef 100644 --- a/code/modules/spells/spell_types/construct_spells.dm +++ b/code/modules/spells/spell_types/construct_spells.dm @@ -9,6 +9,26 @@ cult_req = 1 charge_max = 2500 + +/obj/effect/proc_holder/spell/aoe_turf/area_conversion + name = "Area Conversion" + desc = "This spell instantly converts a small area around you." + + school = "transmutation" + charge_max = 50 + clothes_req = 0 + invocation = "none" + invocation_type = "none" + range = 2 + action_icon_state = "areaconvert" + action_background_icon_state = "bg_cult" + +/obj/effect/proc_holder/spell/aoe_turf/area_conversion/cast(list/targets, mob/user = usr) + playsound(get_turf(user), 'sound/items/welder.ogg', 75, 1) + for(var/turf/T in targets) + T.narsie_act(FALSE, TRUE, 100 - (get_dist(user, T) * 25)) + + /obj/effect/proc_holder/spell/aoe_turf/conjure/floor name = "Summon Cult Floor" desc = "This spell constructs a cult floor"