Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reorgs xeno_structures.dm, tunnels now use minimap to choose exit. #35

Merged
merged 3 commits into from
Jul 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions code/__HELPERS/ai.dm
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,22 @@
continue
nearest_target = nearby_vehicle
return nearest_target

/**
* This proc attempts to get an instance of an atom type within distance, with center as the center.
* Arguments
* * center - The center of the search
* * type - The type of atom we're looking for
* * distance - The distance we should search
* * list_to_search - The list to look through for the type
*/
/proc/cheap_get_atom(atom/center, type, distance, list/list_to_search)
var/turf/turf_center = get_turf(center)
if(!turf_center)
return
for(var/atom/near AS in list_to_search)
if(!istype(near, type))
continue
if(get_dist(turf_center, near) > distance)
continue
return near
59 changes: 59 additions & 0 deletions code/modules/xenomorph/_xeno_structure.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/obj/structure/xeno
hit_sound = "alien_resin_break"
layer = RESIN_STRUCTURE_LAYER
resistance_flags = UNACIDABLE
///Bitflags specific to xeno structures
var/xeno_structure_flags
///Which hive(number) do we belong to?
var/hivenumber = XENO_HIVE_NORMAL

/obj/structure/xeno/Initialize(mapload, _hivenumber)
. = ..()
if(!(xeno_structure_flags & IGNORE_WEED_REMOVAL))
RegisterSignal(loc, COMSIG_TURF_WEED_REMOVED, PROC_REF(weed_removed))
if(_hivenumber) ///because admins can spawn them
hivenumber = _hivenumber
LAZYADDASSOC(GLOB.xeno_structures_by_hive, hivenumber, src)
if(xeno_structure_flags & CRITICAL_STRUCTURE)
LAZYADDASSOC(GLOB.xeno_critical_structures_by_hive, hivenumber, src)

/obj/structure/xeno/Destroy()
if(!locate(src) in GLOB.xeno_structures_by_hive[hivenumber]+GLOB.xeno_critical_structures_by_hive[hivenumber]) //The rest of the proc is pointless to look through if its not in the lists
stack_trace("[src] not found in the list of (potentially critical) xeno structures!") //We dont want to CRASH because that'd block deletion completely. Just trace it and continue.
return ..()
GLOB.xeno_structures_by_hive[hivenumber] -= src
if(xeno_structure_flags & CRITICAL_STRUCTURE)
GLOB.xeno_critical_structures_by_hive[hivenumber] -= src
return ..()

/obj/structure/xeno/ex_act(severity)
take_damage(severity * 0.8, BRUTE, BOMB)

/obj/structure/xeno/attack_hand(mob/living/user)
balloon_alert(user, "You only scrape at it")
return TRUE

/obj/structure/xeno/flamer_fire_act(burnlevel)
take_damage(burnlevel / 3, BURN, FIRE)

/obj/structure/xeno/fire_act()
take_damage(10, BURN, FIRE)

/// Destroy the xeno structure when the weed it was on is destroyed
/obj/structure/xeno/proc/weed_removed()
SIGNAL_HANDLER
var/obj/alien/weeds/found_weed = locate(/obj/alien/weeds) in loc
if(found_weed.obj_integrity <= 0)
obj_destruction(damage_flag = MELEE)
else
obj_destruction()

/obj/structure/xeno/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount, damage_type, damage_flag, effects, armor_penetration, isrightclick)
if(!(HAS_TRAIT(xeno_attacker, TRAIT_VALHALLA_XENO) && xeno_attacker.a_intent == INTENT_HARM && (tgui_alert(xeno_attacker, "Are you sure you want to tear down [src]?", "Tear down [src]?", list("Yes","No"))) == "Yes"))
return ..()
if(!do_after(xeno_attacker, 3 SECONDS, NONE, src))
return
xeno_attacker.do_attack_animation(src, ATTACK_EFFECT_CLAW)
balloon_alert_to_viewers("\The [xeno_attacker] tears down \the [src]!", "We tear down \the [src].")
playsound(src, "alien_resin_break", 25)
take_damage(max_integrity) // Ensure its destroyed
192 changes: 192 additions & 0 deletions code/modules/xenomorph/acidwell.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
/obj/structure/xeno/acidwell
name = "acid well"
desc = "An acid well. It stores acid to put out fires."
icon = 'icons/Xeno/acid_pool.dmi'
plane = FLOOR_PLANE
icon_state = "well"
density = FALSE
opacity = FALSE
anchored = TRUE
max_integrity = 5

hit_sound = "alien_resin_move"
destroy_sound = "alien_resin_move"
///How many charges of acid this well contains
var/charges = 1
///If a xeno is charging this well
var/charging = FALSE
///What xeno created this well
var/mob/living/carbon/xenomorph/creator = null

/obj/structure/xeno/acidwell/Initialize(mapload, _creator)
. = ..()
creator = _creator
RegisterSignal(creator, COMSIG_QDELETING, PROC_REF(clear_creator))
update_icon()
var/static/list/connections = list(
COMSIG_ATOM_ENTERED = PROC_REF(on_cross),
)
AddElement(/datum/element/connect_loc, connections)

/obj/structure/xeno/acidwell/Destroy()
creator = null
return ..()

///Signal handler for creator destruction to clear reference
/obj/structure/xeno/acidwell/proc/clear_creator()
SIGNAL_HANDLER
creator = null

/obj/structure/xeno/acidwell/obj_destruction(damage_amount, damage_type, damage_flag)
if(!QDELETED(creator) && creator.stat == CONSCIOUS && creator.z == z)
var/area/A = get_area(src)
if(A)
to_chat(creator, span_xenoannounce("You sense your acid well at [A.name] has been destroyed!") )

if(damage_amount || damage_flag) //Spawn the gas only if we actually get destroyed by damage
var/datum/effect_system/smoke_spread/xeno/acid/A = new(get_turf(src))
A.set_up(clamp(CEILING(charges*0.5, 1),0,3),src) //smoke scales with charges
A.start()
return ..()

/obj/structure/xeno/acidwell/examine(mob/user)
. = ..()
if(!isxeno(user) && !isobserver(user))
return
. += span_xenonotice("An acid well made by [creator]. It currently has <b>[charges]/[XENO_ACID_WELL_MAX_CHARGES] charges</b>.")

/obj/structure/xeno/acidwell/deconstruct(disassembled = TRUE)
visible_message(span_danger("[src] suddenly collapses!") )
return ..()

/obj/structure/xeno/acidwell/update_icon()
. = ..()
set_light(charges , charges / 2, LIGHT_COLOR_GREEN)

/obj/structure/xeno/acidwell/update_overlays()
. = ..()
if(!charges)
return
. += mutable_appearance(icon, "[charges]", alpha = src.alpha)
. += emissive_appearance(icon, "[charges]", alpha = src.alpha)

/obj/structure/xeno/acidwell/flamer_fire_act(burnlevel) //Removes a charge of acid, but fire is extinguished
acid_well_fire_interaction()

/obj/structure/xeno/acidwell/fire_act() //Removes a charge of acid, but fire is extinguished
acid_well_fire_interaction()

///Handles fire based interactions with the acid well. Depletes 1 charge if there are any to extinguish all fires in the turf while producing acid smoke.
/obj/structure/xeno/acidwell/proc/acid_well_fire_interaction()
if(!charges)
take_damage(50, BURN, FIRE)
return

charges--
update_icon()
var/turf/T = get_turf(src)
var/datum/effect_system/smoke_spread/xeno/acid/extuingishing/acid_smoke = new(T) //spawn acid smoke when charges are actually used
acid_smoke.set_up(0, src) //acid smoke in the immediate vicinity
acid_smoke.start()

for(var/obj/flamer_fire/F in T) //Extinguish all flames in turf
qdel(F)

/obj/structure/xeno/acidwell/attackby(obj/item/I, mob/user, params)
if(!isxeno(user))
return ..()
attack_alien(user)

/obj/structure/xeno/acidwell/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = MELEE, effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
if(xeno_attacker.a_intent == INTENT_HARM && (CHECK_BITFIELD(xeno_attacker.xeno_caste.caste_flags, CASTE_IS_BUILDER) || xeno_attacker == creator) ) //If we're a builder caste or the creator and we're on harm intent, deconstruct it.
balloon_alert(xeno_attacker, "Removing...")
if(!do_after(xeno_attacker, XENO_ACID_WELL_FILL_TIME, IGNORE_HELD_ITEM, src, BUSY_ICON_HOSTILE))
balloon_alert(xeno_attacker, "Stopped removing")
return
playsound(src, "alien_resin_break", 25)
deconstruct(TRUE, xeno_attacker)
return

if(charges >= 5)
balloon_alert(xeno_attacker, "Already full")
return
if(charging)
balloon_alert(xeno_attacker, "Already being filled")
return

if(xeno_attacker.plasma_stored < XENO_ACID_WELL_FILL_COST) //You need to have enough plasma to attempt to fill the well
balloon_alert(xeno_attacker, "Need [XENO_ACID_WELL_FILL_COST - xeno_attacker.plasma_stored] more plasma")
return

charging = TRUE

balloon_alert(xeno_attacker, "Refilling...")
if(!do_after(xeno_attacker, XENO_ACID_WELL_FILL_TIME, IGNORE_HELD_ITEM, src, BUSY_ICON_BUILD))
charging = FALSE
balloon_alert(xeno_attacker, "Aborted refilling")
return

if(xeno_attacker.plasma_stored < XENO_ACID_WELL_FILL_COST)
charging = FALSE
balloon_alert(xeno_attacker, "Need [XENO_ACID_WELL_FILL_COST - xeno_attacker.plasma_stored] more plasma")
return

xeno_attacker.plasma_stored -= XENO_ACID_WELL_FILL_COST
charges++
charging = FALSE
update_icon()
balloon_alert(xeno_attacker, "Now has [charges] / [XENO_ACID_WELL_MAX_CHARGES] charges")
to_chat(xeno_attacker,span_xenonotice("We add acid to [src]. It is currently has <b>[charges] / [XENO_ACID_WELL_MAX_CHARGES] charges</b>.") )

/obj/structure/xeno/acidwell/proc/on_cross(datum/source, atom/movable/A, oldloc, oldlocs)
SIGNAL_HANDLER
if(CHECK_MULTIPLE_BITFIELDS(A.allow_pass_flags, HOVERING))
return
if(iscarbon(A))
HasProximity(A)

/obj/structure/xeno/acidwell/HasProximity(atom/movable/AM)
if(!charges)
return
if(!isliving(AM))
return
var/mob/living/stepper = AM
if(stepper.stat == DEAD)
return

var/charges_used = 0

for(var/obj/item/explosive/grenade/sticky/sticky_bomb in stepper.contents)
if(charges_used >= charges)
break
if(sticky_bomb.stuck_to == stepper)
sticky_bomb.clean_refs()
sticky_bomb.forceMove(loc) // i'm not sure if this is even needed, but just to prevent possible bugs
visible_message(span_danger("[src] sizzles as [sticky_bomb] melts down in the acid."))
qdel(sticky_bomb)
charges_used ++

if(stepper.on_fire && (charges_used < charges))
stepper.ExtinguishMob()
charges_used ++

if(!isxeno(stepper))
stepper.next_move_slowdown += charges * 2 //Acid spray has slow down so this should too; scales with charges, Min 2 slowdown, Max 10
stepper.apply_damage(charges * 10, BURN, BODY_ZONE_PRECISE_L_FOOT, ACID, penetration = 33)
stepper.apply_damage(charges * 10, BURN, BODY_ZONE_PRECISE_R_FOOT, ACID, penetration = 33)
stepper.visible_message(span_danger("[stepper] is immersed in [src]'s acid!") , \
span_danger("We are immersed in [src]'s acid!") , null, 5)
playsound(stepper, "sound/bullets/acid_impact1.ogg", 10 * charges)
new /obj/effect/temp_visual/acid_bath(get_turf(stepper))
charges_used = charges //humans stepping on it empties it out

if(!charges_used)
return

var/datum/effect_system/smoke_spread/xeno/acid/extuingishing/acid_smoke
acid_smoke = new(get_turf(stepper)) //spawn acid smoke when charges are actually used
acid_smoke.set_up(0, src) //acid smoke in the immediate vicinity
acid_smoke.start()

charges -= charges_used
update_icon()
67 changes: 67 additions & 0 deletions code/modules/xenomorph/jellypod.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/obj/structure/xeno/resin_jelly_pod
name = "Resin jelly pod"
desc = "A large resin pod. Inside is a thick, viscous fluid that looks like it doesnt burn easily."
icon = 'icons/Xeno/resinpod.dmi'
icon_state = "resinpod"
density = FALSE
opacity = FALSE
anchored = TRUE
max_integrity = 250
layer = RESIN_STRUCTURE_LAYER
pixel_x = -16
pixel_y = -16
xeno_structure_flags = IGNORE_WEED_REMOVAL

hit_sound = "alien_resin_move"
destroy_sound = "alien_resin_move"
///How many actual jellies the pod has stored
var/chargesleft = 0
///Max amount of jellies the pod can hold
var/maxcharges = 10
///Every 5 times this number seconds we will create a jelly
var/recharge_rate = 10
///Countdown to the next time we generate a jelly
var/nextjelly = 0

/obj/structure/xeno/resin_jelly_pod/Initialize(mapload, _hivenumber)
. = ..()
add_overlay(image(icon, "resinpod_inside", layer + 0.01, dir))
START_PROCESSING(SSslowprocess, src)

/obj/structure/xeno/resin_jelly_pod/Destroy()
STOP_PROCESSING(SSslowprocess, src)
return ..()

/obj/structure/xeno/resin_jelly_pod/examine(mob/user, distance, infix, suffix)
. = ..()
if(isxeno(user))
. += "It has [chargesleft] jelly globules remaining[datum_flags & DF_ISPROCESSING ? ", and will create a new jelly in [(recharge_rate-nextjelly)*5] seconds": " and seems latent"]."

/obj/structure/xeno/resin_jelly_pod/process()
if(nextjelly <= recharge_rate)
nextjelly++
return
nextjelly = 0
chargesleft++
if(chargesleft >= maxcharges)
return PROCESS_KILL

/obj/structure/xeno/resin_jelly_pod/attack_alien(mob/living/carbon/xenomorph/xeno_attacker, damage_amount = xeno_attacker.xeno_caste.melee_damage, damage_type = BRUTE, damage_flag = MELEE, effects = TRUE, armor_penetration = 0, isrightclick = FALSE)
if(xeno_attacker.status_flags & INCORPOREAL)
return FALSE

if((xeno_attacker.a_intent == INTENT_HARM && isxenohivelord(xeno_attacker)) || xeno_attacker.hivenumber != hivenumber)
balloon_alert(xeno_attacker, "Destroying...")
if(do_after(xeno_attacker, HIVELORD_TUNNEL_DISMANTLE_TIME, IGNORE_HELD_ITEM, src, BUSY_ICON_BUILD))
deconstruct(FALSE)
return

if(!chargesleft)
balloon_alert(xeno_attacker, "No jelly remaining")
to_chat(xeno_attacker, span_xenonotice("We reach into \the [src], but only find dregs of resin. We should wait some more.") )
return
balloon_alert(xeno_attacker, "Retrieved jelly")
new /obj/item/resin_jelly(loc)
chargesleft--
if(!(datum_flags & DF_ISPROCESSING) && (chargesleft < maxcharges))
START_PROCESSING(SSslowprocess, src)
Loading
Loading