[MIRROR] Harvesters are more fun to play (#894)

* Harvesters are more fun to play

* resolve .rej
This commit is contained in:
CitadelStationBot
2017-05-18 07:12:29 -05:00
committed by Poojawa
parent 593a784583
commit 6617f68604
27 changed files with 211 additions and 164 deletions

View File

@@ -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)

View File

@@ -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

View File

@@ -279,6 +279,7 @@
var/explanation
switch(cult_objectives[obj_count])
if("sacrifice")
if(GLOB.sac_mind)
if(GLOB.sac_complete)
explanation = "Sacrifice [GLOB.sac_mind], the [GLOB.sac_mind.assigned_role]. <span class='greenannounce'>Success!</span>"
SSblackbox.add_details("cult_objective","cult_sacrifice|SUCCESS")

View File

@@ -141,7 +141,7 @@
to_chat(B.current, "<span class='cultlarge'>[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("<span class='cult'>The marking rite is complete! It will last for 90 seconds.</span>")
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

View File

@@ -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)))

View File

@@ -216,8 +216,7 @@
to_chat(newstruct, "<b>You are still bound to serve the cult[stoner ? " and [stoner]":""], follow their orders and help them complete their goals at all costs.</b>")
else if(stoner)
to_chat(newstruct, "<b>You are still bound to serve your creator, [stoner], follow their orders and help them complete their goals at all costs.</b>")
newstruct.throw_alert("bloodsense", /obj/screen/alert/bloodsense)
var/obj/screen/alert/bloodsense/BS = newstruct.alerts["bloodsense"]
var/obj/screen/alert/bloodsense/BS = newstruct.throw_alert("bloodsense", /obj/screen/alert/bloodsense)
BS.Cviewer = newstruct
newstruct.cancel_camera()

View File

@@ -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)

View File

@@ -179,7 +179,6 @@
/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)

View File

@@ -71,7 +71,6 @@ 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)
@@ -325,7 +324,6 @@ 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)

View File

@@ -37,7 +37,6 @@
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)
@@ -239,7 +238,6 @@
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)

View File

@@ -297,7 +297,6 @@
qdel(src)
/obj/structure/girder/narsie_act()
if(prob(25))
new /obj/structure/girder/cult(loc)
qdel(src)

View File

@@ -84,7 +84,6 @@
qdel(src)
/obj/structure/table_frame/narsie_act()
if(prob(20))
new /obj/structure/table_frame/wood(src.loc)
qdel(src)

View File

@@ -47,7 +47,6 @@
queue_smooth_neighbors(src)
/obj/structure/table/narsie_act()
if(prob(20))
new /obj/structure/table/wood(src.loc)
/obj/structure/table/ratvar_act()

View File

@@ -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)

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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()
. = ..()

View File

@@ -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)

View File

@@ -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)

View File

@@ -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 ..()

View File

@@ -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

View File

@@ -34,18 +34,15 @@
var/playstyle_string = "<b>You are a generic construct! Your job is to not exist, and you should probably adminhelp this.</b>"
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, "<span class='cultitalic'>You have no master to seek!</span>")
the_construct.seeking = FALSE
return
if(tracking)
tracking = FALSE
the_construct.seeking = FALSE
to_chat(the_construct, "<span class='cultitalic'>You are no longer tracking your master.</span>")
return
else
tracking = TRUE
the_construct.seeking = TRUE
to_chat(the_construct, "<span class='cultitalic'>You are now tracking your master.</span>")
/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 = "<b>You are a Wraith. Though relatively fragile, you are fast, deadly, can phase through walls, and your attacks will lower the cooldown on phasing.</b>"
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 = "<b>You are a Wraith. Though relatively fragile, you are fast, deadly, and even able to phase through walls.</b>"
/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), \
<i>and, most important of all,</i> create new constructs by producing soulstones to capture souls, \
and shells to place those soulstones into.</b>"
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 = "<B>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 = "<B>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.</B>"
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, "<span class='cultlarge'>\"Bring [C.p_them()] to me.\"</span>")
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, "<span class='cultitalic'>You have no master to seek!</span>")
the_construct.seeking = FALSE
return
if(tracking)
tracking = FALSE
the_construct.seeking = FALSE
to_chat(the_construct, "<span class='cultitalic'>You are no longer tracking your master.</span>")
return
else
tracking = TRUE
the_construct.seeking = TRUE
to_chat(the_construct, "<span class='cultitalic'>You are now tracking your master.</span>")
/////////////////////////////ui stuff/////////////////////////////

View File

@@ -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)

View File

@@ -331,11 +331,13 @@
changeNext_move(CLICK_CD_GRABBING)
if(AM.pulledby)
if(!supress_message)
visible_message("<span class='danger'>[src] has pulled [AM] from [AM.pulledby]'s grip.</span>")
AM.pulledby.stop_pulling() //an object can't be pulled by two mobs at once.
pulling = AM
AM.pulledby = src
if(!supress_message)
playsound(src.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
update_pull_hud_icon()

View File

@@ -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,6 +81,7 @@
/obj/singularity/narsie/consume(atom/A)
if(isturf(A))
A.narsie_act()

View File

@@ -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"