mirror of
https://github.com/CHOMPstation/CHOMPstation.git
synced 2026-08-24 12:36:22 +01:00
Secret
This commit is contained in:
@@ -0,0 +1,276 @@
|
||||
//sculpture
|
||||
//SCP-173, nothing more need be said
|
||||
/mob/living/simple_animal/sculpture
|
||||
name = "\improper sculpture"
|
||||
desc = "It's some kind of hastily-painted human-size stone sculpture. Just looking at it makes you feel nervous."
|
||||
icon_state = "sculpture"
|
||||
icon_living = "sculpture"
|
||||
icon_dead = "sculpture"
|
||||
emote_hear = list("makes a faint scraping sound")
|
||||
emote_see = list("twitches slightly", "shivers")
|
||||
response_help = "touches the"
|
||||
response_disarm = "pushes the"
|
||||
response_harm = "hits the"
|
||||
see_in_dark = 8 //Needs to see in darkness to snap in darkness
|
||||
pass_flags = PASSTABLE
|
||||
var/response_snap = "snapped the neck of" //Past tense because it "happened before you could see it"
|
||||
var/response_snap_target = "In the blink of an eye, something grabs you and snaps your neck!"
|
||||
var/snap_sound = list('sound/scp/firstpersonsnap.ogg','sound/scp/firstpersonsnap2.ogg','sound/scp/firstpersonsnap3.ogg')
|
||||
var/scare_sound = list('sound/scp/scare1.ogg','sound/scp/scare2.ogg','sound/scp/scare3.ogg','sound/scp/scare4.ogg') //Boo
|
||||
var/hibernate = 0 //Disables SCP until toggled back to 0
|
||||
var/scare_played = 0 //Did we rape everyone's ears yet ?
|
||||
var/obj/machinery/atmospherics/unary/vent_pump/entry_vent //Graciously stolen from spider code
|
||||
|
||||
/mob/living/simple_animal/sculpture/Life()
|
||||
|
||||
//If we are hibernating, just don't do anything
|
||||
if(hibernate)
|
||||
return
|
||||
|
||||
if(!check_los())
|
||||
return
|
||||
|
||||
//See if we're able to strangle anyone
|
||||
for(var/mob/living/carbon/M in get_turf(src))
|
||||
if(M.stat == CONSCIOUS && check_los())
|
||||
snap_neck(M)
|
||||
break
|
||||
|
||||
//Find out what mobs we can see for targetting purposes
|
||||
var/list/conscious = list()
|
||||
for(var/mob/living/carbon/H in view(7, src))
|
||||
if(H.stat == CONSCIOUS) //He's up and running
|
||||
conscious.Add(H)
|
||||
|
||||
//Pick the nearest valid conscious target
|
||||
var/mob/living/carbon/target
|
||||
for(var/mob/living/carbon/H in conscious)
|
||||
if(!target || get_dist(src, H) < get_dist(src, target))
|
||||
target = H
|
||||
|
||||
if(target)
|
||||
handle_target(target)
|
||||
else
|
||||
handle_idle()
|
||||
|
||||
|
||||
//Check if any mob can see SPC-173
|
||||
/mob/living/simple_animal/sculpture/proc/check_los()
|
||||
|
||||
var/observed = 0
|
||||
|
||||
//Humans can observe SCP-173. If a single human observes him, he's observed for everyone
|
||||
//Note that humans have a 180 degrees field of vision for the purposes of this proc
|
||||
for(var/mob/living/carbon/H in viewers(src, null))
|
||||
if(H.stat)
|
||||
continue
|
||||
var/x_diff = H.x - src.x
|
||||
var/y_diff = H.y - src.y
|
||||
if(y_diff != 0) //If we are not on the same vertical plane (up/down), mob is either above or below src
|
||||
if(y_diff < 0 && H.dir == NORTH) //Mob is below src and looking up
|
||||
observed = 1
|
||||
break
|
||||
else if(y_diff > 0 && H.dir == SOUTH) //Mob is above src and looking down
|
||||
observed = 1
|
||||
break
|
||||
if(x_diff != 0) //If we are not on the same horizontal plane (left/right), mob is either left or right of src
|
||||
if(x_diff < 0 && H.dir == EAST) //Mob is left of src and looking right
|
||||
observed = 1
|
||||
break
|
||||
else if(x_diff > 0 && H.dir == WEST) //Mob is right of src and looking left
|
||||
observed = 1
|
||||
break
|
||||
|
||||
if(observed) //Is someone looking at us, given that they can see us ?
|
||||
return 0 //Try again when we get a chance
|
||||
return 1 //Success, let's move
|
||||
|
||||
/mob/living/simple_animal/sculpture/proc/handle_target(var/mob/living/carbon/target)
|
||||
|
||||
if(!target) //Sanity
|
||||
return
|
||||
|
||||
if(!check_los())
|
||||
return
|
||||
|
||||
var/turf/target_turf
|
||||
|
||||
//Send the warning that SPC is homing in
|
||||
target_turf = get_turf(target)
|
||||
if(!scare_played) //Let's minimize the spam
|
||||
playsound(get_turf(src), pick(scare_sound), 50, 1)
|
||||
scare_played = 1
|
||||
spawn(50)
|
||||
scare_played = 0
|
||||
|
||||
//Rampage along a path to get to them, in the blink of an eye
|
||||
var/turf/next_turf = get_step_towards(src, target)
|
||||
var/num_turfs = get_dist(src,target)
|
||||
spawn()
|
||||
while(get_turf(src) != target_turf && num_turfs > 0)
|
||||
if(!check_los()) //Something is looking at us now
|
||||
break
|
||||
if(!next_turf.CanPass(src, next_turf)) //We can't pass through our planned path
|
||||
break
|
||||
for(var/obj/structure/table/O in next_turf)
|
||||
O.ex_act(1)
|
||||
sleep(5)
|
||||
for(var/obj/structure/closet/C in next_turf)
|
||||
C.ex_act(1)
|
||||
sleep(5)
|
||||
for(var/obj/structure/grille/G in next_turf)
|
||||
G.ex_act(1)
|
||||
sleep(5)
|
||||
for(var/obj/machinery/door/airlock/A in next_turf)
|
||||
if(A.welded || A.locked) //Snowflakey code to take in account bolts and welding
|
||||
break
|
||||
A.open()
|
||||
sleep(5)
|
||||
for(var/obj/machinery/door/D in next_turf)
|
||||
D.open()
|
||||
sleep(5)
|
||||
if(!next_turf.CanPass(src, next_turf)) //Once we cleared everything we could, check one last time if we can pass
|
||||
break
|
||||
forceMove(next_turf)
|
||||
dir = get_dir(src, target)
|
||||
next_turf = get_step(src, get_dir(next_turf,target))
|
||||
num_turfs--
|
||||
|
||||
/mob/living/simple_animal/sculpture/proc/handle_idle()
|
||||
|
||||
if(!check_los())
|
||||
return
|
||||
|
||||
//If we're not strangling anyone, take a stroll
|
||||
if(prob(25)) //1 in 4 chance of checking out something new
|
||||
var/list/turfs = new/list()
|
||||
for(var/turf/T in view(7, src))
|
||||
if(!istype(T, /turf/simulated/floor))
|
||||
continue
|
||||
turfs += T
|
||||
var/turf/target_turf = safepick(turfs)
|
||||
if(!target_turf)
|
||||
return
|
||||
//Move to our new resting point with celerity
|
||||
var/turf/next_turf = get_step_towards(src, target_turf)
|
||||
var/num_turfs = get_dist(src, target_turf)
|
||||
spawn()
|
||||
while(get_turf(src) != target_turf && num_turfs > 0)
|
||||
if(!check_los()) //Something is looking at us now
|
||||
break
|
||||
if(!next_turf.CanPass(src, next_turf)) //We can't pass through our planned path
|
||||
break
|
||||
for(var/obj/structure/table/O in next_turf)
|
||||
O.ex_act(1)
|
||||
sleep(5)
|
||||
for(var/obj/structure/closet/C in next_turf)
|
||||
C.ex_act(1)
|
||||
sleep(5)
|
||||
for(var/obj/structure/grille/G in next_turf)
|
||||
G.ex_act(1)
|
||||
sleep(5)
|
||||
for(var/obj/machinery/door/airlock/A in next_turf)
|
||||
if(A.welded || A.locked) //Snowflakey code to take in account bolts and welding
|
||||
break
|
||||
A.open()
|
||||
sleep(5)
|
||||
for(var/obj/machinery/door/D in next_turf)
|
||||
D.open()
|
||||
sleep(5)
|
||||
if(!next_turf.CanPass(src, next_turf)) //Once we cleared everything we could, check one last time if we can pass
|
||||
break
|
||||
forceMove(next_turf)
|
||||
dir = get_dir(src, target_turf)
|
||||
next_turf = get_step(src, get_dir(next_turf,target_turf))
|
||||
num_turfs--
|
||||
//Coding note : This is known to allow SCP to end up on tiles that contain obstructing structures (doors, machinery, etc)
|
||||
//Although he CAN'T pass through them during normal movement. Will look into a fix soon
|
||||
|
||||
//Do we have a vent ? Good, let's take a look
|
||||
for(entry_vent in view(1, src))
|
||||
if(prob(90)) //10 % chance to consider a vent, to try and avoid constant vent switching
|
||||
return
|
||||
visible_message("<span class='danger'>\The [src] starts trying to slide itself into the vent!</span>")
|
||||
sleep(50) //Let's stop SCP-173 for five seconds to do his parking job
|
||||
..()
|
||||
if(entry_vent.network && entry_vent.network.normal_members.len)
|
||||
var/list/vents = list()
|
||||
for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in entry_vent.network.normal_members)
|
||||
vents.Add(temp_vent)
|
||||
if(!vents.len)
|
||||
entry_vent = null
|
||||
return
|
||||
if(!check_los()) //Someone started looking at us
|
||||
return
|
||||
var/obj/machinery/atmospherics/unary/vent_pump/exit_vent = pick(vents)
|
||||
spawn()
|
||||
visible_message("<span class='danger'>\The [src] suddenly disappears into the vent!</span>")
|
||||
loc = exit_vent
|
||||
var/travel_time = round(get_dist(loc, exit_vent.loc)/2)
|
||||
spawn(travel_time)
|
||||
if(!exit_vent || exit_vent.welded)
|
||||
forceMove(get_turf(entry_vent))
|
||||
entry_vent = null
|
||||
visible_message("<span class='danger'>\The [src] suddenly appears from the vent!</span>")
|
||||
return
|
||||
|
||||
forceMove(get_turf(exit_vent))
|
||||
entry_vent = null
|
||||
visible_message("<span class='danger'>\The [src] suddenly appears from the vent!</span>")
|
||||
else
|
||||
entry_vent = null
|
||||
|
||||
//This performs an immediate neck snap check, meant to avoid people cheesing SCP-173 by just running faster than Life() refresh
|
||||
/mob/living/simple_animal/sculpture/proc/check_snap_neck()
|
||||
|
||||
//See if we're able to strangle anyone
|
||||
for(var/mob/living/carbon/M in get_turf(src))
|
||||
if(M.stat == CONSCIOUS && check_los())
|
||||
snap_neck(M)
|
||||
break
|
||||
|
||||
/mob/living/simple_animal/sculpture/forceMove(atom/destination, var/no_tp = 0)
|
||||
|
||||
..()
|
||||
check_snap_neck()
|
||||
|
||||
/mob/living/simple_animal/sculpture/proc/snap_neck(var/mob/living/target)
|
||||
|
||||
if(!check_los())
|
||||
return
|
||||
|
||||
if(target)
|
||||
//To prevent movement cheese, SCP snaps necks the second it ends up on the same turf as someone
|
||||
//Or in other terms, if SCP decides it had a clean shot for a neck snap at the moment this proc fired, you're good as dead
|
||||
target.apply_damage(rand(120, 150), BRUTE, "head")
|
||||
target.apply_damage(100, OXY)
|
||||
playsound(target.loc, pick(snap_sound), 50, 1)
|
||||
|
||||
//Warn everyone
|
||||
visible_message("<span class='danger'>[src] [response_snap] [target]!</span>")
|
||||
target << "<span class='alert'><b>[response_snap_target]</b> Your vision fades away...</span>"
|
||||
|
||||
target.death() //Immediately trigger death to avoid doublesnap during lag
|
||||
|
||||
//Logging stuff
|
||||
target.attack_log += text("\[[time_stamp()]\] <font color='red'>Has had his neck snapped by [src]!</font>")
|
||||
log_admin("[target] ([target.ckey]) has had his neck snapped by an active [src].")
|
||||
message_admins("ALERT: <A HREF='?_src_=holder;adminplayerobservecoodjump=1;X=[target.x];Y=[target.y];Z=[target.z]'>[target.real_name]</a> has had his neck snapped by an active [src].")
|
||||
|
||||
/mob/living/simple_animal/sculpture/attackby(var/obj/item/O as obj, var/mob/user as mob)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/sculpture/Topic(href, href_list)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/sculpture/Bump(atom/movable/AM as mob)
|
||||
if(!check_los())
|
||||
snap_neck(AM)
|
||||
..()
|
||||
|
||||
/mob/living/simple_animal/sculpture/Bumped(atom/movable/AM as mob, yes)
|
||||
if(!check_los())
|
||||
snap_neck(AM)
|
||||
|
||||
//You cannot destroy SCP-173, fool!
|
||||
/mob/living/simple_animal/sculpture/ex_act(var/severity)
|
||||
Reference in New Issue
Block a user