mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-24 05:23:22 +01:00
Return of the facehuggers (#3883)
This commit is contained in:
@@ -1,11 +1,18 @@
|
||||
#define BURST 0
|
||||
#define BURSTING 1
|
||||
#define GROWING 2
|
||||
#define GROWN 3
|
||||
|
||||
#define MAX_PROGRESS 100
|
||||
|
||||
|
||||
/obj/structure/alien/egg
|
||||
desc = "It looks like a weird egg."
|
||||
name = "egg"
|
||||
icon_state = "egg_growing"
|
||||
density = 0
|
||||
anchored = 1
|
||||
var/status = GROWING //can be GROWING, GROWN or BURST; all mutually exclusive
|
||||
var/progress = 0
|
||||
|
||||
/obj/structure/alien/egg/Initialize()
|
||||
@@ -16,82 +23,74 @@
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
return ..()
|
||||
|
||||
/obj/structure/alien/egg/CanUseTopic(var/mob/user)
|
||||
return isobserver(user) ? STATUS_INTERACTIVE : STATUS_CLOSE
|
||||
|
||||
/obj/structure/alien/egg/Topic(href, href_list)
|
||||
if(..())
|
||||
return 1
|
||||
|
||||
if(href_list["spawn"])
|
||||
attack_ghost(usr)
|
||||
|
||||
/obj/structure/alien/egg/process()
|
||||
progress++
|
||||
if(progress >= MAX_PROGRESS)
|
||||
for(var/mob/M in dead_mob_list)
|
||||
if(istype(M,/mob/dead) && M.client && M.client.prefs && (MODE_XENOMORPH in M.client.prefs.be_special_role))
|
||||
M << "[ghost_follow_link(src, M)] <span class='notice'>An alien is ready to hatch! (<a href='byond://?src=\ref[src];spawn=1'>spawn</a>)</span>"
|
||||
Grow()
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
update_icon()
|
||||
|
||||
/obj/structure/alien/egg/update_icon()
|
||||
if(progress == -1)
|
||||
/obj/structure/alien/egg/attack_hand(user as mob)
|
||||
var/mob/living/carbon/M = user
|
||||
if(!istype(M) || !(locate(/obj/item/organ/xenos/hivenode) in M.internal_organs))
|
||||
return
|
||||
|
||||
switch(status)
|
||||
if(BURST)
|
||||
user << "<span class='warning'>You clear the hatched egg.</span>"
|
||||
qdel(src)
|
||||
return
|
||||
if(GROWING)
|
||||
user << "<span class='warning'>The child is not developed yet.</span>"
|
||||
return
|
||||
if(GROWN)
|
||||
user << "<span class='warning'>You retrieve the child.</span>"
|
||||
Burst(0)
|
||||
return
|
||||
|
||||
/obj/structure/alien/egg/proc/GetFacehugger()
|
||||
return locate(/obj/item/clothing/mask/facehugger) in contents
|
||||
|
||||
/obj/structure/alien/egg/proc/Grow()
|
||||
icon_state = "egg"
|
||||
status = GROWN
|
||||
new /obj/item/clothing/mask/facehugger(src)
|
||||
return
|
||||
|
||||
/obj/structure/alien/egg/proc/Burst(var/kill = 1) //drops and kills the hugger if any is remaining
|
||||
if(status == GROWN || status == GROWING)
|
||||
icon_state = "egg_hatched"
|
||||
else if(progress < MAX_PROGRESS)
|
||||
icon_state = "egg_growing"
|
||||
flick("egg_opening", src)
|
||||
status = BURSTING
|
||||
addtimer(CALLBACK(src, .proc/givefacehugger, kill), 15)
|
||||
|
||||
/obj/structure/alien/egg/proc/givefacehugger(var/kill = 1)
|
||||
var/obj/item/clothing/mask/facehugger/child = GetFacehugger()
|
||||
status = BURST
|
||||
child.loc = get_turf(src)
|
||||
|
||||
if(kill && istype(child))
|
||||
child.Die()
|
||||
else
|
||||
icon_state = "egg"
|
||||
for(var/mob/M in range(1,src))
|
||||
if(CanHug(M))
|
||||
child.Attach(M)
|
||||
break
|
||||
|
||||
/obj/structure/alien/egg/attack_ghost(var/mob/dead/observer/user)
|
||||
if(progress == -1) //Egg has been hatched.
|
||||
return
|
||||
/obj/structure/alien/egg/HasProximity(atom/movable/AM as mob|obj)
|
||||
if(status == GROWN)
|
||||
if(!CanHug(AM))
|
||||
return
|
||||
|
||||
if(progress < MAX_PROGRESS)
|
||||
user << "\The [src] has not yet matured."
|
||||
return
|
||||
var/mob/living/carbon/C = AM
|
||||
if(C.stat == CONSCIOUS && C.status_flags & XENO_HOST)
|
||||
return
|
||||
|
||||
if(!user.MayRespawn(1))
|
||||
return
|
||||
Burst(0)
|
||||
|
||||
// Check for bans properly.
|
||||
if(jobban_isbanned(user, "Xenomorph"))
|
||||
user << "<span class='danger'>You are banned from playing a Xenomorph.</span>"
|
||||
return
|
||||
|
||||
var/confirm = alert(user, "Are you sure you want to join as a Xenomorph larva?", "Become Larva", "No", "Yes")
|
||||
|
||||
if(!src || confirm != "Yes")
|
||||
return
|
||||
|
||||
if(!user || !user.ckey)
|
||||
return
|
||||
|
||||
if(progress == -1) //Egg has been hatched.
|
||||
user << "Too slow..."
|
||||
return
|
||||
|
||||
flick("egg_opening",src)
|
||||
progress = -1 // No harvesting pls.
|
||||
sleep(5)
|
||||
|
||||
if(!src || !user)
|
||||
visible_message("<span class='alium'>\The [src] writhes with internal motion, but nothing comes out.</span>")
|
||||
progress = MAX_PROGRESS // Someone else can have a go.
|
||||
return // What a pain.
|
||||
|
||||
// Create the mob, transfer over key.
|
||||
var/mob/living/carbon/alien/larva/larva = new(get_turf(src))
|
||||
larva.ckey = user.ckey
|
||||
xenomorphs.add_antagonist(larva.mind, 1)
|
||||
spawn(-1)
|
||||
if(user) qdel(user) // Remove the keyless ghost if it exists.
|
||||
|
||||
visible_message("<span class='alium'>\The [src] splits open with a wet slithering noise, and \the [larva] writhes free!</span>")
|
||||
|
||||
// Turn us into a hatched egg.
|
||||
name = "hatched alien egg"
|
||||
desc += " This one has hatched."
|
||||
update_icon()
|
||||
#undef BURST
|
||||
#undef BURSTING
|
||||
#undef GROWING
|
||||
#undef GROWN
|
||||
|
||||
#undef MAX_PROGRESS
|
||||
|
||||
@@ -63,7 +63,8 @@
|
||||
if (src.destroyed)
|
||||
return
|
||||
else
|
||||
usr << "<span class='warning'>You kick the lab cage.</span>"
|
||||
user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN)
|
||||
user << "<span class='warning'>You kick the lab cage.</span>"
|
||||
for(var/mob/O in oviewers())
|
||||
if ((O.client && !( O.blinded )))
|
||||
O << "<span class='warning'>[user] kicks the lab cage.</span>"
|
||||
@@ -74,187 +75,9 @@
|
||||
|
||||
/obj/structure/lamarr/proc/Break()
|
||||
if(occupied)
|
||||
new /obj/item/clothing/mask/lamarr(src.loc)
|
||||
new /obj/item/clothing/mask/facehugger/lamarr(src.loc)
|
||||
occupied = 0
|
||||
update_icon()
|
||||
return
|
||||
|
||||
var/const/MIN_ACTIVE_TIME = 200 //time between being dropped and going idle
|
||||
var/const/MAX_ACTIVE_TIME = 400
|
||||
|
||||
/obj/item/clothing/mask/lamarr
|
||||
name = "Lamarr"
|
||||
desc = "The worst she might do is attempt to... couple with your head."//hope we don't get sued over a harmless reference, rite?
|
||||
gender = FEMALE
|
||||
icon = 'icons/mob/alien.dmi'
|
||||
icon_state = "facehugger"
|
||||
item_state = "facehugger"
|
||||
w_class = 3 //note: can be picked up by aliens unlike most other items of w_class below 4
|
||||
flags = PROXMOVE
|
||||
body_parts_covered = FACE|EYES
|
||||
throw_range = 5
|
||||
|
||||
var/stat = CONSCIOUS //UNCONSCIOUS is the idle state in this case
|
||||
var/strength = 5
|
||||
var/attached = 0
|
||||
var/sterile = 1
|
||||
|
||||
/obj/item/clothing/mask/lamarr/attack_hand(user as mob)
|
||||
|
||||
if((stat == CONSCIOUS))
|
||||
if(Attach(user))
|
||||
return
|
||||
|
||||
..()
|
||||
|
||||
/obj/item/clothing/mask/lamarr/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone)
|
||||
. = ..()
|
||||
user.drop_from_inventory(src)
|
||||
if(hit_zone == "head")
|
||||
Attach(target)
|
||||
|
||||
|
||||
/obj/item/clothing/mask/lamarr/examine(mob/user)
|
||||
..(user)
|
||||
switch(stat)
|
||||
if(DEAD,UNCONSCIOUS)
|
||||
user << "<span class='warning'>[src] is not moving.</span>"
|
||||
if(CONSCIOUS)
|
||||
user << "<span class='warning'>[src] seems to be active.</span>"
|
||||
if (sterile)
|
||||
user << "<span class='warning'>It looks like the proboscis has been removed.</span>"
|
||||
return
|
||||
|
||||
/obj/item/clothing/mask/lamarr/attackby(obj/item/I, mob/user)
|
||||
if(I.force)
|
||||
user.do_attack_animation(src)
|
||||
Die()
|
||||
return
|
||||
|
||||
/obj/item/clothing/mask/lamarr/bullet_act()
|
||||
Die()
|
||||
return
|
||||
|
||||
/obj/item/clothing/mask/lamarr/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume)
|
||||
if(exposed_temperature > T0C+80)
|
||||
Die()
|
||||
return
|
||||
|
||||
/obj/item/clothing/mask/lamarr/equipped(mob/M)
|
||||
..()
|
||||
Attach(M)
|
||||
|
||||
/obj/item/clothing/mask/lamarr/Crossed(atom/target)
|
||||
HasProximity(target)
|
||||
return
|
||||
|
||||
/obj/item/clothing/mask/lamarr/on_found(mob/finder as mob)
|
||||
if(stat == CONSCIOUS)
|
||||
HasProximity(finder)
|
||||
return 1
|
||||
return
|
||||
|
||||
/obj/item/clothing/mask/lamarr/HasProximity(atom/movable/AM as mob|obj)
|
||||
if(CanHug(AM))
|
||||
Attach(AM)
|
||||
|
||||
/obj/item/clothing/mask/lamarr/throw_at(atom/target, range, speed)
|
||||
..()
|
||||
if(stat == CONSCIOUS)
|
||||
icon_state = "[initial(icon_state)]_thrown"
|
||||
spawn(15)
|
||||
if(icon_state == "[initial(icon_state)]_thrown")
|
||||
icon_state = "[initial(icon_state)]"
|
||||
|
||||
/obj/item/clothing/mask/lamarr/proc/Attach(M as mob)
|
||||
|
||||
if((!iscarbon(M)))
|
||||
return
|
||||
|
||||
if(attached)
|
||||
return
|
||||
|
||||
var/mob/living/L = M //just so I don't need to use :
|
||||
|
||||
if(loc == L) return
|
||||
if(stat != CONSCIOUS) return
|
||||
if(!sterile) L.take_organ_damage(strength,0) //done here so that even borgs and humans in helmets take damage
|
||||
|
||||
L.visible_message("<span class='danger'>[src] leaps at [L]'s face!</span>")
|
||||
|
||||
|
||||
if(ishuman(L))
|
||||
var/mob/living/carbon/human/H = L
|
||||
if(H.head && H.head.flags & AIRTIGHT)
|
||||
H.visible_message("<span class='danger'>\The [src] smashes against [H]'s [H.head]!</span>")
|
||||
Die()
|
||||
return
|
||||
|
||||
|
||||
if(iscarbon(M))
|
||||
var/mob/living/carbon/target = L
|
||||
|
||||
if(target.wear_mask)
|
||||
if(prob(20)) return
|
||||
var/obj/item/clothing/W = target.wear_mask
|
||||
if(!W.canremove) return
|
||||
target.drop_from_inventory(W)
|
||||
|
||||
target.visible_message("<span class='danger'>\The [src] tears [W] off of [target]'s face!</span>")
|
||||
|
||||
target.equip_to_slot(src, slot_wear_mask)
|
||||
target.contents += src // Monkey sanity check - Snapshot
|
||||
|
||||
GoIdle() //so it doesn't jump the people that tear it off
|
||||
|
||||
return
|
||||
|
||||
/obj/item/clothing/mask/lamarr/proc/GoActive()
|
||||
if(stat == DEAD || stat == CONSCIOUS)
|
||||
return
|
||||
|
||||
stat = CONSCIOUS
|
||||
icon_state = "[initial(icon_state)]"
|
||||
|
||||
return
|
||||
|
||||
/obj/item/clothing/mask/lamarr/proc/GoIdle(var/min_time=MIN_ACTIVE_TIME, var/max_time=MAX_ACTIVE_TIME)
|
||||
if(stat == DEAD || stat == UNCONSCIOUS)
|
||||
return
|
||||
|
||||
/* RemoveActiveIndicators() */
|
||||
|
||||
stat = UNCONSCIOUS
|
||||
icon_state = "[initial(icon_state)]_inactive"
|
||||
|
||||
spawn(rand(min_time,max_time))
|
||||
GoActive()
|
||||
return
|
||||
|
||||
/obj/item/clothing/mask/lamarr/proc/Die()
|
||||
if(stat == DEAD)
|
||||
return
|
||||
|
||||
/* RemoveActiveIndicators() */
|
||||
|
||||
icon_state = "[initial(icon_state)]_dead"
|
||||
stat = DEAD
|
||||
|
||||
src.visible_message("<span class='danger'>\The [src] curls up into a ball!</span>")
|
||||
|
||||
return
|
||||
|
||||
/proc/CanHug(var/mob/M)
|
||||
|
||||
if(!iscarbon(M))
|
||||
return 0
|
||||
|
||||
var/mob/living/carbon/C = M
|
||||
if(istype(C) && locate(/obj/item/organ/xenos/hivenode) in C.internal_organs)
|
||||
return 0
|
||||
|
||||
if(ishuman(C))
|
||||
var/mob/living/carbon/human/H = C
|
||||
if(H.head && (H.head.body_parts_covered & FACE) && !(H.head.item_flags & FLEXIBLEMATERIAL))
|
||||
return 0
|
||||
return 1
|
||||
|
||||
Reference in New Issue
Block a user