diff --git a/code/__defines/gamemode.dm b/code/__defines/gamemode.dm index 0be497843b..896553e809 100644 --- a/code/__defines/gamemode.dm +++ b/code/__defines/gamemode.dm @@ -63,6 +63,7 @@ var/list/be_special_flags = list( // Mode/antag template macros. #define MODE_BORER "borer" +#define MODE_XENOMORPH "xeno" #define MODE_LOYALIST "loyalist" #define MODE_MUTINEER "mutineer" #define MODE_COMMANDO "commando" diff --git a/code/game/antagonist/alien/xenomorph.dm b/code/game/antagonist/alien/xenomorph.dm new file mode 100644 index 0000000000..e69db8aee7 --- /dev/null +++ b/code/game/antagonist/alien/xenomorph.dm @@ -0,0 +1,47 @@ +var/datum/antagonist/xenos/xenomorphs + +/datum/antagonist/xenos + id = MODE_XENOMORPH + role_type = BE_ALIEN + role_text = "Xenomorph" + role_text_plural = "Xenomorphs" + mob_path = /mob/living/carbon/alien/larva + bantype = "Xenomorph" + flags = ANTAG_OVERRIDE_MOB | ANTAG_RANDSPAWN | ANTAG_OVERRIDE_JOB | ANTAG_VOTABLE + welcome_text = "Hiss! You are a larval alien. Hide and bide your time until you are ready to evolve." + antaghud_indicator = "hudalien" + + hard_cap = 5 + hard_cap_round = 8 + initial_spawn_req = 4 + initial_spawn_target = 6 + + spawn_announcement = "Unidentified lifesigns detected coming aboard the station. Secure any exterior access, including ducting and ventilation." + spawn_announcement_title = "Lifesign Alert" + spawn_announcement_sound = 'sound/AI/aliens.ogg' + spawn_announcement_delay = 5000 + +/datum/antagonist/xenos/New(var/no_reference) + ..() + if(!no_reference) + xenomorphs = src + +/datum/antagonist/xenos/attempt_random_spawn() + if(config.aliens_allowed) ..() + +/datum/antagonist/xenos/proc/get_vents() + var/list/vents = list() + for(var/obj/machinery/atmospherics/unary/vent_pump/temp_vent in machines) + if(!temp_vent.welded && temp_vent.network && temp_vent.loc.z in using_map.station_levels) + if(temp_vent.network.normal_members.len > 50) + vents += temp_vent + return vents + +/datum/antagonist/xenos/create_objectives(var/datum/mind/player) + if(!..()) + return + player.objectives += new /datum/objective/survive() + player.objectives += new /datum/objective/escape() + +/datum/antagonist/xenos/place_mob(var/mob/living/player) + player.forceMove(get_turf(pick(get_vents()))) diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm index 096bd090c1..8eba407e72 100644 --- a/code/game/machinery/portable_turret.dm +++ b/code/game/machinery/portable_turret.dm @@ -525,7 +525,7 @@ var/list/turret_icons if(isanimal(L) || issmall(L)) // Animals are not so dangerous return check_anomalies ? TURRET_SECONDARY_TARGET : TURRET_NOT_TARGET - if(isalien(L)) // Xenos are dangerous + if(isxenomorph(L) || isalien(L)) // Xenos are dangerous return check_anomalies ? TURRET_PRIORITY_TARGET : TURRET_NOT_TARGET if(ishuman(L)) //if the target is a human, analyze threat level diff --git a/code/game/objects/effects/alien/aliens.dm b/code/game/objects/effects/alien/aliens.dm new file mode 100644 index 0000000000..13cae4777e --- /dev/null +++ b/code/game/objects/effects/alien/aliens.dm @@ -0,0 +1,443 @@ +/* Alien Effects! + * Contains: + * effect/alien + * Resin + * Weeds + * Acid + * Egg + */ + +/* + * effect/alien + */ +/obj/effect/alien + name = "alien thing" + desc = "theres something alien about this" + icon = 'icons/mob/alien.dmi' + +/* + * Resin + */ +/obj/effect/alien/resin + name = "resin" + desc = "Looks like some kind of slimy growth." + icon_state = "resin" + + density = 1 + opacity = 1 + anchored = 1 + var/health = 200 + //var/mob/living/affecting = null + +/obj/effect/alien/resin/wall + name = "resin wall" + desc = "Purple slime solidified into a wall." + icon_state = "resinwall" //same as resin, but consistency ho! + +/obj/effect/alien/resin/membrane + name = "resin membrane" + desc = "Purple slime just thin enough to let light pass through." + icon_state = "resinmembrane" + opacity = 0 + health = 120 + +/obj/effect/alien/resin/New() + ..() + var/turf/T = get_turf(src) + T.thermal_conductivity = WALL_HEAT_TRANSFER_COEFFICIENT + +/obj/effect/alien/resin/Destroy() + var/turf/T = get_turf(src) + T.thermal_conductivity = initial(T.thermal_conductivity) + ..() + +/obj/effect/alien/resin/proc/healthcheck() + if(health <=0) + density = 0 + qdel(src) + return + +/obj/effect/alien/resin/bullet_act(var/obj/item/projectile/Proj) + health -= Proj.damage + ..() + healthcheck() + return + +/obj/effect/alien/resin/ex_act(severity) + switch(severity) + if(1.0) + health-=50 + if(2.0) + health-=50 + if(3.0) + if (prob(50)) + health-=50 + else + health-=25 + healthcheck() + return + +/obj/effect/alien/resin/hitby(AM as mob|obj) + ..() + for(var/mob/O in viewers(src, null)) + O.show_message("[src] was hit by [AM].", 1) + var/tforce = 0 + if(ismob(AM)) + tforce = 10 + else + tforce = AM:throwforce + playsound(loc, 'sound/effects/attackblob.ogg', 100, 1) + health = max(0, health - tforce) + healthcheck() + ..() + return + +/obj/effect/alien/resin/attack_hand() + usr.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + if (HULK in usr.mutations) + usr << "You easily destroy the [name]." + for(var/mob/O in oviewers(src)) + O.show_message("[usr] destroys the [name]!", 1) + health = 0 + else + + // Aliens can get straight through these. + if(istype(usr,/mob/living/carbon)) + var/mob/living/carbon/M = usr + if(locate(/obj/item/organ/internal/xenos/hivenode) in M.internal_organs) + for(var/mob/O in oviewers(src)) + O.show_message("[usr] strokes the [name] and it melts away!", 1) + health = 0 + healthcheck() + return + + usr << "You claw at the [name]." + for(var/mob/O in oviewers(src)) + O.show_message("[usr] claws at the [name]!", 1) + health -= rand(5,10) + healthcheck() + return + +/obj/effect/alien/resin/attackby(obj/item/weapon/W as obj, mob/user as mob) + + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + var/aforce = W.force + health = max(0, health - aforce) + playsound(loc, 'sound/effects/attackblob.ogg', 100, 1) + healthcheck() + ..() + return + +/obj/effect/alien/resin/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if(air_group) return 0 + if(istype(mover) && mover.checkpass(PASSGLASS)) + return !opacity + return !density + + +/* + * Weeds + */ +#define NODERANGE 3 + +/obj/effect/alien/weeds + name = "weeds" + desc = "Weird purple weeds." + icon_state = "weeds" + + anchored = 1 + density = 0 + layer = 2 + var/health = 15 + var/obj/effect/alien/weeds/node/linked_node = null + +/obj/effect/alien/weeds/node + icon_state = "weednode" + name = "purple sac" + desc = "Weird purple octopus-like thing." + layer = 3 + light_range = NODERANGE + var/node_range = NODERANGE + +/obj/effect/alien/weeds/node/New() + ..(src.loc, src) + + +/obj/effect/alien/weeds/New(pos, node) + ..() + if(istype(loc, /turf/space)) + qdel(src) + return + linked_node = node + if(icon_state == "weeds")icon_state = pick("weeds", "weeds1", "weeds2") + spawn(rand(150, 200)) + if(src) + Life() + return + +/obj/effect/alien/weeds/proc/Life() + set background = 1 + var/turf/U = get_turf(src) +/* + if (locate(/obj/movable, U)) + U = locate(/obj/movable, U) + if(U.density == 1) + qdel(src) + return +Alien plants should do something if theres a lot of poison + if(U.poison> 200000) + health -= round(U.poison/200000) + update() + return +*/ + if (istype(U, /turf/space)) + qdel(src) + return + + if(!linked_node || (get_dist(linked_node, src) > linked_node.node_range) ) + return + + direction_loop: + for(var/dirn in cardinal) + var/turf/T = get_step(src, dirn) + + if (!istype(T) || T.density || locate(/obj/effect/alien/weeds) in T || istype(T.loc, /area/arrival) || istype(T, /turf/space)) + continue + + // if (locate(/obj/movable, T)) // don't propogate into movables + // continue + + for(var/obj/O in T) + if(O.density) + continue direction_loop + + new /obj/effect/alien/weeds(T, linked_node) + + +/obj/effect/alien/weeds/ex_act(severity) + switch(severity) + if(1.0) + qdel(src) + if(2.0) + if (prob(50)) + qdel(src) + if(3.0) + if (prob(5)) + qdel(src) + return + +/obj/effect/alien/weeds/attackby(var/obj/item/weapon/W, var/mob/user) + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + if(W.attack_verb.len) + visible_message("\The [src] have been [pick(W.attack_verb)] with \the [W][(user ? " by [user]." : ".")]") + else + visible_message("\The [src] have been attacked with \the [W][(user ? " by [user]." : ".")]") + + var/damage = W.force / 4.0 + + if(istype(W, /obj/item/weapon/weldingtool)) + var/obj/item/weapon/weldingtool/WT = W + + if(WT.remove_fuel(0, user)) + damage = 15 + playsound(loc, 'sound/items/Welder.ogg', 100, 1) + + health -= damage + healthcheck() + +/obj/effect/alien/weeds/proc/healthcheck() + if(health <= 0) + qdel(src) + + +/obj/effect/alien/weeds/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + if(exposed_temperature > 300 + T0C) + health -= 5 + healthcheck() + +#undef NODERANGE + + +/* + * Acid + */ +/obj/effect/alien/acid + name = "acid" + desc = "Burbling corrossive stuff. I wouldn't want to touch it." + icon_state = "acid" + + density = 0 + opacity = 0 + anchored = 1 + + var/atom/target + var/ticks = 0 + var/target_strength = 0 + +/obj/effect/alien/acid/New(loc, target) + ..(loc) + src.target = target + + if(isturf(target)) // Turf take twice as long to take down. + target_strength = 8 + else + target_strength = 4 + tick() + +/obj/effect/alien/acid/proc/tick() + if(!target) + qdel(src) + + ticks += 1 + + if(ticks >= target_strength) + + for(var/mob/O in hearers(src, null)) + O.show_message("[src.target] collapses under its own weight into a puddle of goop and undigested debris!", 1) + + if(istype(target, /turf/simulated/wall)) // I hate turf code. + var/turf/simulated/wall/W = target + W.dismantle_wall(1) + else + qdel(target) + qdel(src) + return + + switch(target_strength - ticks) + if(6) + visible_message("[src.target] is holding up against the acid!") + if(4) + visible_message("[src.target]\s structure is being melted by the acid!") + if(2) + visible_message("[src.target] is struggling to withstand the acid!") + if(0 to 1) + visible_message("[src.target] begins to crumble under the acid!") + spawn(rand(150, 200)) tick() + +/* + * Egg + */ +/var/const //for the status var + BURST = 0 + BURSTING = 1 + GROWING = 2 + GROWN = 3 + + MIN_GROWTH_TIME = 1800 //time it takes to grow a hugger + MAX_GROWTH_TIME = 3000 + +/obj/effect/alien/egg + desc = "It looks like a weird egg" + name = "egg" +// icon_state = "egg_growing" // So the egg looks 'grown', even though it's not. + icon_state = "egg" + density = 0 + anchored = 1 + + var/health = 100 + var/status = BURST //can be GROWING, GROWN or BURST; all mutually exclusive + flags = PROXMOVE + +/obj/effect/alien/egg/New() +/* + if(config.aliens_allowed) + ..() + spawn(rand(MIN_GROWTH_TIME,MAX_GROWTH_TIME)) + Grow() + else + qdel(src) +*/ +/obj/effect/alien/egg/attack_hand(user as mob) + + var/mob/living/carbon/M = user + if(!istype(M) || !(locate(/obj/item/organ/internal/xenos/hivenode) in M.internal_organs)) + return attack_hand(user) + + switch(status) + if(BURST) + user << "You clear the hatched egg." + qdel(src) + return +/* if(GROWING) + user << "The child is not developed yet." + return + if(GROWN) + user << "You retrieve the child." + Burst(0) + return + + /obj/effect/alien/egg/proc/GetFacehugger() // Commented out for future edit. + return locate(/obj/item/clothing/mask/facehugger) in contents + +/obj/effect/alien/egg/proc/Grow() + icon_state = "egg" +// status = GROWN + status = BURST +// new /obj/item/clothing/mask/facehugger(src) + return +*/ +/obj/effect/alien/egg/proc/Burst(var/kill = 1) //drops and kills the hugger if any is remaining + if(status == GROWN || status == GROWING) +// var/obj/item/clothing/mask/facehugger/child = GetFacehugger() + icon_state = "egg_hatched" +/* flick("egg_opening", src) + status = BURSTING + spawn(15) + status = BURST + child.loc = get_turf(src) + + if(kill && istype(child)) + child.Die() + else + for(var/mob/M in range(1,src)) + if(CanHug(M)) + child.Attach(M) + break +*/ +/obj/effect/alien/egg/bullet_act(var/obj/item/projectile/Proj) + health -= Proj.damage + ..() + healthcheck() + return + + +/obj/effect/alien/egg/attackby(var/obj/item/weapon/W, var/mob/user) + if(health <= 0) + return + if(W.attack_verb.len) + src.visible_message("\The [src] has been [pick(W.attack_verb)] with \the [W][(user ? " by [user]." : ".")]") + else + src.visible_message("\The [src] has been attacked with \the [W][(user ? " by [user]." : ".")]") + var/damage = W.force / 4.0 + + if(istype(W, /obj/item/weapon/weldingtool)) + var/obj/item/weapon/weldingtool/WT = W + + if(WT.remove_fuel(0, user)) + damage = 15 + playsound(src.loc, 'sound/items/Welder.ogg', 100, 1) + + src.health -= damage + src.healthcheck() + + +/obj/effect/alien/egg/proc/healthcheck() + if(health <= 0) + Burst() + +/obj/effect/alien/egg/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + if(exposed_temperature > 500 + T0C) + health -= 5 + healthcheck() +/* +/obj/effect/alien/egg/HasProximity(atom/movable/AM as mob|obj) + if(status == GROWN) + if(!CanHug(AM)) + return + + var/mob/living/carbon/C = AM + if(C.stat == CONSCIOUS && C.status_flags & XENO_HOST) + return + + Burst(0) +*/ \ No newline at end of file diff --git a/code/game/objects/structures/stool_bed_chair_nest/alien_nests.dm b/code/game/objects/structures/stool_bed_chair_nest/alien_nests.dm new file mode 100644 index 0000000000..9d79ad45a1 --- /dev/null +++ b/code/game/objects/structures/stool_bed_chair_nest/alien_nests.dm @@ -0,0 +1,85 @@ +#define NEST_RESIST_TIME 1200 + +/obj/structure/bed/nest + name = "alien nest" + desc = "It's a gruesome pile of thick, sticky resin shaped like a nest." + icon = 'icons/mob/alien.dmi' + icon_state = "nest" + var/health = 100 + +/obj/structure/bed/nest/update_icon() + return + +/obj/structure/bed/nest/user_unbuckle_mob(mob/user as mob) + if(buckled_mob) + if(buckled_mob.buckled == src) + if(buckled_mob != user) + buckled_mob.visible_message(\ + "[user.name] pulls [buckled_mob.name] free from the sticky nest!",\ + "[user.name] pulls you free from the gelatinous resin.",\ + "You hear squelching...") + buckled_mob.pixel_y = 0 + buckled_mob.old_y = 0 + unbuckle_mob() + else + if(world.time <= buckled_mob.last_special+NEST_RESIST_TIME) + return + buckled_mob.last_special = world.time + buckled_mob.visible_message(\ + "[buckled_mob.name] struggles to break free of the gelatinous resin...",\ + "You struggle to break free from the gelatinous resin...",\ + "You hear squelching...") + spawn(NEST_RESIST_TIME) + if(user && buckled_mob && user.buckled == src) + buckled_mob.last_special = world.time + buckled_mob.pixel_y = 0 + buckled_mob.old_y = 0 + unbuckle_mob() + src.add_fingerprint(user) + return + +/obj/structure/bed/nest/user_buckle_mob(mob/M as mob, mob/user as mob) + if ( !ismob(M) || (get_dist(src, user) > 1) || (M.loc != src.loc) || user.restrained() || usr.stat || M.buckled || istype(user, /mob/living/silicon/pai) ) + return + + unbuckle_mob() + + var/mob/living/carbon/xenos = user + var/mob/living/carbon/victim = M + + if(istype(victim) && locate(/obj/item/organ/internal/xenos/hivenode) in victim.internal_organs) + return + + if(istype(xenos) && !(locate(/obj/item/organ/internal/xenos/hivenode) in xenos.internal_organs)) + return + + if(M == usr) + return + else + M.visible_message(\ + "[user.name] secretes a thick vile goo, securing [M.name] into [src]!",\ + "[user.name] drenches you in a foul-smelling resin, trapping you in the [src]!",\ + "You hear squelching...") + M.buckled = src + M.loc = src.loc + M.set_dir(src.dir) + M.update_canmove() + M.pixel_y = 6 + M.old_y = 6 + src.buckled_mob = M + src.add_fingerprint(user) + return + +/obj/structure/bed/nest/attackby(obj/item/weapon/W as obj, mob/user as mob) + var/aforce = W.force + health = max(0, health - aforce) + playsound(loc, 'sound/effects/attackblob.ogg', 100, 1) + for(var/mob/M in viewers(src, 7)) + M.show_message("[user] hits [src] with [W]!", 1) + healthcheck() + +/obj/structure/bed/nest/proc/healthcheck() + if(health <=0) + density = 0 + qdel(src) + return diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 6b3560a824..2d5fcc3ee1 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -146,6 +146,11 @@ proc/admin_notice(var/message, var/rights) body += {"

Rudimentary transformation:
These transformations only create a new mob type and copy stuff over. They do not take into account MMIs and similar mob-specific things. The buttons in 'Transformations' are preferred, when possible.

Observer | + \[ Xenos: Larva + Drone + Hunter + Sentinel + Queen \] | \[ Crew: Human Unathi Tajaran diff --git a/code/modules/admin/secrets/random_events/trigger_xenomorph_infestation.dm b/code/modules/admin/secrets/random_events/trigger_xenomorph_infestation.dm new file mode 100644 index 0000000000..a8af34137a --- /dev/null +++ b/code/modules/admin/secrets/random_events/trigger_xenomorph_infestation.dm @@ -0,0 +1,7 @@ +/datum/admin_secret_item/random_event/trigger_xenomorph_infestation + name = "Trigger a Xenomorph Infestation" + +/datum/admin_secret_item/random_event/trigger_xenomorph_infestation/execute(var/mob/user) + . = ..() + if(.) + return xenomorphs.attempt_random_spawn() diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index fde36a734c..d832d4c7d3 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1146,6 +1146,16 @@ log_admin("[key_name(usr)] AIized [key_name(H)]") H.AIize() + else if(href_list["makealien"]) + if(!check_rights(R_SPAWN)) return + + var/mob/living/carbon/human/H = locate(href_list["makealien"]) + if(!istype(H)) + usr << "This can only be used on instances of type /mob/living/carbon/human" + return + + usr.client.cmd_admin_alienize(H) + else if(href_list["makeslime"]) if(!check_rights(R_SPAWN)) return diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index 80ed64458e..bf04d11dfe 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -100,6 +100,24 @@ paiController.pai_candidates.Remove(candidate) feedback_add_details("admin_verb","MPAI") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! +/client/proc/cmd_admin_alienize(var/mob/M in mob_list) + set category = "Fun" + set name = "Make Alien" + + if(!ticker) + alert("Wait until the game starts") + return + if(ishuman(M)) + log_admin("[key_name(src)] has alienized [M.key].") + spawn(10) + M:Alienize() + feedback_add_details("admin_verb","MKAL") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + log_admin("[key_name(usr)] made [key_name(M)] into an alien.") + message_admins("\blue [key_name_admin(usr)] made [key_name(M)] into an alien.", 1) + else + alert("Invalid mob") + + /client/proc/cmd_admin_slimeize(var/mob/M in mob_list) set category = "Fun" set name = "Make slime" diff --git a/code/modules/admin/view_variables/helpers.dm b/code/modules/admin/view_variables/helpers.dm index 95945f82e0..a0f8dad9b6 100644 --- a/code/modules/admin/view_variables/helpers.dm +++ b/code/modules/admin/view_variables/helpers.dm @@ -68,6 +68,7 @@ + "} diff --git a/code/modules/hydroponics/seed_datums.dm b/code/modules/hydroponics/seed_datums.dm index e4a1237f2b..7ee8a7bcb4 100644 --- a/code/modules/hydroponics/seed_datums.dm +++ b/code/modules/hydroponics/seed_datums.dm @@ -1170,3 +1170,23 @@ set_trait(TRAIT_PRODUCTION,7) set_trait(TRAIT_YIELD,3) set_trait(TRAIT_POTENCY,3) + +// Alien weeds. +/datum/seed/xenomorph + name = "xenomorph" + seed_name = "alien weed" + display_name = "alien weeds" + force_layer = 3 + chems = list("phoron" = list(1,3)) + +/datum/seed/xenomorph/New() + ..() + set_trait(TRAIT_PLANT_ICON,"vine2") + set_trait(TRAIT_IMMUTABLE,1) + set_trait(TRAIT_PRODUCT_COLOUR,"#3D1934") + set_trait(TRAIT_FLESH_COLOUR,"#3D1934") + set_trait(TRAIT_PLANT_COLOUR,"#3D1934") + set_trait(TRAIT_PRODUCTION,1) + set_trait(TRAIT_YIELD,-1) + set_trait(TRAIT_SPREAD,2) + set_trait(TRAIT_POTENCY,50) diff --git a/code/modules/materials/materials.dm b/code/modules/materials/materials.dm index 12d78b366b..1de0db081e 100644 --- a/code/modules/materials/materials.dm +++ b/code/modules/materials/materials.dm @@ -642,6 +642,22 @@ var/list/name_to_material display_name = "elevator panelling" icon_colour = "#666666" +/material/resin + name = "resin" + icon_colour = "#E85DD8" + dooropen_noise = 'sound/effects/attackblob.ogg' + door_icon_base = "resin" + melting_point = T0C+300 + sheet_singular_name = "blob" + sheet_plural_name = "blobs" + +/material/resin/can_open_material_door(var/mob/living/user) + var/mob/living/carbon/M = user + if(istype(M) && locate(/obj/item/organ/internal/xenos/hivenode) in M.internal_organs) + return 1 + return 0 + + /material/wood name = "wood" stack_type = /obj/item/stack/material/wood diff --git a/code/modules/mob/language/outsider.dm b/code/modules/mob/language/outsider.dm index 3e85f4efec..0a721e6f56 100644 --- a/code/modules/mob/language/outsider.dm +++ b/code/modules/mob/language/outsider.dm @@ -84,3 +84,34 @@ key = "y" machine_understands = 0 flags = RESTRICTED | HIVEMIND + +/datum/language/xenocommon + name = "Xenomorph" + colour = "alien" + desc = "The common tongue of the xenomorphs." + speech_verb = "hisses" + ask_verb = "hisses" + exclaim_verb = "hisses" + key = "4" + flags = RESTRICTED + syllables = list("sss","sSs","SSS") + +/datum/language/xenos + name = "Hivemind" + desc = "Xenomorphs have the strange ability to commune over a psychic hivemind." + speech_verb = "hisses" + ask_verb = "hisses" + exclaim_verb = "hisses" + colour = "alien" + key = "a" + flags = RESTRICTED | HIVEMIND + +/datum/language/xenos/check_special_condition(var/mob/other) + + var/mob/living/carbon/M = other + if(!istype(M)) + return 1 + if(locate(/obj/item/organ/internal/xenos/hivenode) in M.internal_organs) + return 1 + + return 0 diff --git a/code/modules/mob/living/carbon/alien/larva/larva.dm b/code/modules/mob/living/carbon/alien/larva/larva.dm new file mode 100644 index 0000000000..9b72fb658f --- /dev/null +++ b/code/modules/mob/living/carbon/alien/larva/larva.dm @@ -0,0 +1,14 @@ +/mob/living/carbon/alien/larva + name = "alien larva" + real_name = "alien larva" + adult_form = /mob/living/carbon/human + speak_emote = list("hisses") + icon_state = "larva" + language = "Hivemind" + maxHealth = 25 + health = 25 + +/mob/living/carbon/alien/larva/New() + ..() + add_language("Xenomorph") //Bonus language. + internal_organs |= new /obj/item/organ/internal/xenos/hivenode(src) diff --git a/code/modules/mob/living/carbon/alien/larva/life.dm b/code/modules/mob/living/carbon/alien/larva/life.dm new file mode 100644 index 0000000000..641e572586 --- /dev/null +++ b/code/modules/mob/living/carbon/alien/larva/life.dm @@ -0,0 +1,13 @@ + +//Larvae regenerate health and nutrition from plasma and alien weeds. +/mob/living/carbon/alien/larva/handle_environment(var/datum/gas_mixture/environment) + + if(!environment) return + + var/turf/T = get_turf(src) + if(environment.gas["phoron"] > 0 || (T && locate(/obj/effect/alien/weeds) in T.contents)) + update_progression() + adjustBruteLoss(-1) + adjustFireLoss(-1) + adjustToxLoss(-1) + adjustOxyLoss(-1) diff --git a/code/modules/mob/living/carbon/alien/larva/progression.dm b/code/modules/mob/living/carbon/alien/larva/progression.dm new file mode 100644 index 0000000000..c41c94a36c --- /dev/null +++ b/code/modules/mob/living/carbon/alien/larva/progression.dm @@ -0,0 +1,12 @@ +/mob/living/carbon/alien/larva/confirm_evolution() + + src << "\blue You are growing into a beautiful alien! It is time to choose a caste." + src << "\blue There are three to choose from:" + src << "Hunters \blue are strong and agile, able to hunt away from the hive and rapidly move through ventilation shafts. Hunters generate plasma slowly and have low reserves." + src << "Sentinels \blue are tasked with protecting the hive and are deadly up close and at a range. They are not as physically imposing nor fast as the hunters." + src << "Drones \blue are the working class, offering the largest plasma storage and generation. They are the only caste which may evolve again, turning into the dreaded alien queen." + var/alien_caste = alert(src, "Please choose which alien caste you shall belong to.",,"Hunter","Sentinel","Drone") + return alien_caste ? "Xenomorph [alien_caste]" : null + +/mob/living/carbon/alien/larva/show_evolution_blurb() + return diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 6a42fc6b41..f586ecd56c 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -78,6 +78,11 @@ stat("Tank Pressure", internal.air_contents.return_pressure()) stat("Distribution Pressure", internal.distribute_pressure) + var/obj/item/organ/internal/xenos/plasmavessel/P = internal_organs_by_name[O_PLASMA] //Xenomorphs. Mech. + if(P) + stat(null, "Phoron Stored: [P.stored_plasma]/[P.max_plasma]") + + if(back && istype(back,/obj/item/weapon/rig)) var/obj/item/weapon/rig/suit = back var/cell_status = "ERROR" diff --git a/code/modules/mob/living/carbon/human/species/xenomorphs/alien_embryo.dm b/code/modules/mob/living/carbon/human/species/xenomorphs/alien_embryo.dm new file mode 100644 index 0000000000..9114e58352 --- /dev/null +++ b/code/modules/mob/living/carbon/human/species/xenomorphs/alien_embryo.dm @@ -0,0 +1,161 @@ +// This is to replace the previous datum/disease/alien_embryo for slightly improved handling and maintainability +// It functions almost identically (see code/datums/diseases/alien_embryo.dm) + +/* +/obj/item/alien_embryo //Commented out as reference for future reproduction methods, or addition later. + name = "alien embryo" + desc = "All slimy and yuck." + icon = 'icons/mob/alien.dmi' + icon_state = "larva0_dead" + var/mob/living/affected_mob + var/stage = 0 + +/obj/item/alien_embryo/New() + if(istype(loc, /mob/living)) + affected_mob = loc + processing_objects.Add(src) + spawn(0) + AddInfectionImages(affected_mob) + else + qdel(src) + +/obj/item/alien_embryo/Destroy() + if(affected_mob) + affected_mob.status_flags &= ~(XENO_HOST) + spawn(0) + RemoveInfectionImages(affected_mob) + ..() + +/obj/item/alien_embryo/process() + if(!affected_mob) return + if(loc != affected_mob) + affected_mob.status_flags &= ~(XENO_HOST) + processing_objects.Remove(src) + spawn(0) + RemoveInfectionImages(affected_mob) + affected_mob = null + return + + if(stage < 5 && prob(3)) + stage++ + spawn(0) + RefreshInfectionImage(affected_mob) + + switch(stage) + if(2, 3) + if(prob(1)) + affected_mob.emote("sneeze") + if(prob(1)) + affected_mob.emote("cough") + if(prob(1)) + affected_mob << "\red Your throat feels sore." + if(prob(1)) + affected_mob << "\red Mucous runs down the back of your throat." + if(4) + if(prob(1)) + affected_mob.emote("sneeze") + if(prob(1)) + affected_mob.emote("cough") + if(prob(2)) + affected_mob << "\red Your muscles ache." + if(prob(20)) + affected_mob.take_organ_damage(1) + if(prob(2)) + affected_mob << "\red Your stomach hurts." + if(prob(20)) + affected_mob.adjustToxLoss(1) + affected_mob.updatehealth() + if(5) + affected_mob << "\red You feel something tearing its way out of your stomach..." + affected_mob.adjustToxLoss(10) + affected_mob.updatehealth() + if(prob(50)) + AttemptGrow() + +/obj/item/alien_embryo/proc/AttemptGrow(var/gib_on_success = 1) + var/list/candidates = get_alien_candidates() + var/picked = null + + // To stop clientless larva, we will check that our host has a client + // if we find no ghosts to become the alien. If the host has a client + // he will become the alien but if he doesn't then we will set the stage + // to 2, so we don't do a process heavy check everytime. + + if(candidates.len) + picked = pick(candidates) + else if(affected_mob.client) + picked = affected_mob.key + else + stage = 4 // Let's try again later. + return + + if(affected_mob.lying) + affected_mob.overlays += image('icons/mob/alien.dmi', loc = affected_mob, icon_state = "burst_lie") + else + affected_mob.overlays += image('icons/mob/alien.dmi', loc = affected_mob, icon_state = "burst_stand") + spawn(6) + var/mob/living/carbon/alien/larva/new_xeno = new(affected_mob.loc) + new_xeno.key = picked + new_xeno << sound('sound/voice/hiss5.ogg',0,0,0,100) //To get the player's attention + if(gib_on_success) + affected_mob.gib() + qdel(src) + +/*---------------------------------------- +Proc: RefreshInfectionImage() +Des: Removes all infection images from aliens and places an infection image on all infected mobs for aliens. +----------------------------------------*/ +/obj/item/alien_embryo/proc/RefreshInfectionImage() + + for(var/mob/living/carbon/alien in player_list) + + if(!locate(/obj/item/organ/internal/xenos/hivenode) in alien.internal_organs) + continue + + if(alien.client) + for(var/image/I in alien.client.images) + if(dd_hasprefix_case(I.icon_state, "infected")) + qdel(I) + for(var/mob/living/L in mob_list) + if(iscorgi(L) || iscarbon(L)) + if(L.status_flags & XENO_HOST) + var/I = image('icons/mob/alien.dmi', loc = L, icon_state = "infected[stage]") + alien.client.images += I + +/*---------------------------------------- +Proc: AddInfectionImages(C) +Des: Checks if the passed mob (C) is infected with the alien egg, then gives each alien client an infected image at C. +----------------------------------------*/ +/obj/item/alien_embryo/proc/AddInfectionImages(var/mob/living/C) + if(C) + + for(var/mob/living/carbon/alien in player_list) + + if(!locate(/obj/item/organ/internal/xenos/hivenode) in alien.internal_organs) + continue + + if(alien.client) + if(C.status_flags & XENO_HOST) + var/I = image('icons/mob/alien.dmi', loc = C, icon_state = "infected[stage]") + alien.client.images += I + +/*---------------------------------------- +Proc: RemoveInfectionImage(C) +Des: Removes the alien infection image from all aliens in the world located in passed mob (C). +----------------------------------------*/ + +/obj/item/alien_embryo/proc/RemoveInfectionImages(var/mob/living/C) + + if(C) + + for(var/mob/living/carbon/alien in player_list) + + if(!locate(/obj/item/organ/internal/xenos/hivenode) in alien.internal_organs) + continue + + if(alien.client) + for(var/image/I in alien.client.images) + if(I.loc == C) + if(dd_hasprefix_case(I.icon_state, "infected")) + qdel(I) +*/ diff --git a/code/modules/mob/living/carbon/human/species/xenomorphs/alien_facehugger.dm b/code/modules/mob/living/carbon/human/species/xenomorphs/alien_facehugger.dm new file mode 100644 index 0000000000..817133a251 --- /dev/null +++ b/code/modules/mob/living/carbon/human/species/xenomorphs/alien_facehugger.dm @@ -0,0 +1,222 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32 + +//TODO: Make these simple_animals +/* //Commented out as reference for future reproduction methods, or addition later if needed. - Mech +var/const/MIN_IMPREGNATION_TIME = 100 //time it takes to impregnate someone +var/const/MAX_IMPREGNATION_TIME = 150 + +var/const/MIN_ACTIVE_TIME = 200 //time between being dropped and going idle +var/const/MAX_ACTIVE_TIME = 400 + +/obj/item/clothing/mask/facehugger + name = "alien" + desc = "It has some sort of a tube at the end of its tail." + 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/sterile = 0 + var/strength = 5 + var/attached = 0 + +/obj/item/clothing/mask/facehugger/attack_hand(user as mob) + + if((stat == CONSCIOUS && !sterile)) + if(Attach(user)) + return + + ..() + +/obj/item/clothing/mask/facehugger/attack(mob/living/M as mob, mob/user as mob) + ..() + user.drop_from_inventory(src) + Attach(M) + +/obj/item/clothing/mask/facehugger/New() + if(config.aliens_allowed) + ..() + else + qdel(src) + +/obj/item/clothing/mask/facehugger/examine(mob/user) + ..(user) + switch(stat) + if(DEAD,UNCONSCIOUS) + user << "\red \b [src] is not moving." + if(CONSCIOUS) + user << "\red \b [src] seems to be active." + if (sterile) + user << "\red \b It looks like the proboscis has been removed." + return + +/obj/item/clothing/mask/facehugger/attackby(obj/item/I, mob/user) + if(I.force) + user.do_attack_animation(src) + Die() + return + +/obj/item/clothing/mask/facehugger/bullet_act() + Die() + return + +/obj/item/clothing/mask/facehugger/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + if(exposed_temperature > T0C+80) + Die() + return + +/obj/item/clothing/mask/facehugger/equipped(mob/M) + ..() + Attach(M) + +/obj/item/clothing/mask/facehugger/Crossed(atom/target) + HasProximity(target) + return + +/obj/item/clothing/mask/facehugger/on_found(mob/finder as mob) + if(stat == CONSCIOUS) + HasProximity(finder) + return 1 + return + +/obj/item/clothing/mask/facehugger/HasProximity(atom/movable/AM as mob|obj) + if(CanHug(AM)) + Attach(AM) + +/obj/item/clothing/mask/facehugger/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/facehugger/throw_impact(atom/hit_atom) + ..() + if(stat == CONSCIOUS) + icon_state = "[initial(icon_state)]" + throwing = 0 + GoIdle(30,100) //stunned for a few seconds - allows throwing them to be useful for positioning but not as an offensive action (unless you're setting up a trap) + +/obj/item/clothing/mask/facehugger/proc/Attach(M as mob) + + if((!iscorgi(M) && !iscarbon(M))) + return + + if(attached) + return + + var/mob/living/carbon/C = M + if(istype(C) && locate(/obj/item/organ/internal/xenos/hivenode) in C.internal_organs) + return + + + attached++ + spawn(MAX_IMPREGNATION_TIME) + attached = 0 + + 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("\red \b [src] leaps at [L]'s face!") + + 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("\red \b [src] tears [W] off of [target]'s face!") + + target.equip_to_slot(src, slot_wear_mask) + target.contents += src // Monkey sanity check - Snapshot + + if(!sterile) L.Paralyse(MAX_IMPREGNATION_TIME/6) //something like 25 ticks = 20 seconds with the default settings + + GoIdle() //so it doesn't jump the people that tear it off + + spawn(rand(MIN_IMPREGNATION_TIME,MAX_IMPREGNATION_TIME)) + Impregnate(L) + + return + +/obj/item/clothing/mask/facehugger/proc/Impregnate(mob/living/target as mob) + if(!target || target.wear_mask != src || target.stat == DEAD) //was taken off or something + return + + if(!sterile) + new /obj/item/alien_embryo(target) + target.status_flags |= XENO_HOST + + target.visible_message("\red \b [src] falls limp after violating [target]'s face!") + + Die() + icon_state = "[initial(icon_state)]_impregnated" + + else + target.visible_message("\red \b [src] violates [target]'s face!") + return + +/obj/item/clothing/mask/facehugger/proc/GoActive() + if(stat == DEAD || stat == CONSCIOUS) + return + + stat = CONSCIOUS + icon_state = "[initial(icon_state)]" + + return + +/obj/item/clothing/mask/facehugger/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/facehugger/proc/Die() + if(stat == DEAD) + return + +/* RemoveActiveIndicators() */ + + icon_state = "[initial(icon_state)]_dead" + stat = DEAD + + src.visible_message("\red \b[src] curls up into a ball!") + + return + +/proc/CanHug(var/mob/M) + + if(iscorgi(M)) + return 1 + + if(!iscarbon(M)) + return 0 + + var/mob/living/carbon/C = M + if(istype(C) && locate(/obj/item/organ/internal/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 +*/ \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/species/xenomorphs/alien_powers.dm b/code/modules/mob/living/carbon/human/species/xenomorphs/alien_powers.dm new file mode 100644 index 0000000000..b615205a01 --- /dev/null +++ b/code/modules/mob/living/carbon/human/species/xenomorphs/alien_powers.dm @@ -0,0 +1,310 @@ +/proc/alien_queen_exists(var/ignore_self,var/mob/living/carbon/human/self) + for(var/mob/living/carbon/human/Q in living_mob_list) + if(self && ignore_self && self == Q) + continue + if(Q.species.name != "Xenomorph Queen") + continue + if(!Q.key || !Q.client || Q.stat) + continue + return 1 + return 0 + +/mob/living/carbon/human/proc/gain_plasma(var/amount) + + var/obj/item/organ/internal/xenos/plasmavessel/I = internal_organs_by_name[O_PLASMA] + if(!istype(I)) return + + if(amount) + I.stored_plasma += amount + I.stored_plasma = max(0,min(I.stored_plasma,I.max_plasma)) + +/mob/living/carbon/human/proc/check_alien_ability(var/cost,var/needs_foundation,var/needs_organ) + + var/obj/item/organ/internal/xenos/plasmavessel/P = internal_organs_by_name[O_PLASMA] + if(!istype(P)) + src << "Your plasma vessel has been removed!" + return + + if(needs_organ) + var/obj/item/organ/internal/I = internal_organs_by_name[needs_organ] + if(!I) + src << "Your [needs_organ] has been removed!" + return + else if((I.status & ORGAN_CUT_AWAY) || I.is_broken()) + src << "Your [needs_organ] is too damaged to function!" + return + + if(P.stored_plasma < cost) + src << "\red You don't have enough phoron stored to do that." + return 0 + + if(needs_foundation) + var/turf/T = get_turf(src) + var/has_foundation + if(T) + //TODO: Work out the actual conditions this needs. + if(!(istype(T,/turf/space))) + has_foundation = 1 + if(!has_foundation) + src << "\red You need a solid foundation to do that on." + return 0 + + P.stored_plasma -= cost + return 1 + +// Free abilities. +/mob/living/carbon/human/proc/transfer_plasma(mob/living/carbon/human/M as mob in oview()) + set name = "Transfer Plasma" + set desc = "Transfer Plasma to another alien" + set category = "Abilities" + + if (get_dist(src,M) <= 1) + src << "You need to be closer." + return + + var/obj/item/organ/internal/xenos/plasmavessel/I = M.internal_organs_by_name[O_PLASMA] + if(!istype(I)) + src << "Their plasma vessel is missing." + return + + var/amount = input("Amount:", "Transfer Plasma to [M]") as num + if (amount) + amount = abs(round(amount)) + if(check_alien_ability(amount,0,O_PLASMA)) + M.gain_plasma(amount) + M << "[src] has transfered [amount] plasma to you." + src << "You have transferred [amount] plasma to [M]." + return + +// Queen verbs. +/mob/living/carbon/human/proc/lay_egg() + + set name = "Lay Egg (75)" + set desc = "Lay an egg to produce huggers to impregnate prey with." + set category = "Abilities" + + if(!config.aliens_allowed) + src << "You begin to lay an egg, but hesitate. You suspect it isn't allowed." + verbs -= /mob/living/carbon/human/proc/lay_egg + return + + if(locate(/obj/effect/alien/egg) in get_turf(src)) + src << "There's already an egg here." + return + + if(check_alien_ability(75,1,O_EGG)) + visible_message("[src] has laid an egg!") + new /obj/effect/alien/egg(loc) + + return + +// Drone verbs. +/mob/living/carbon/human/proc/evolve() + set name = "Evolve (500)" + set desc = "Produce an interal egg sac capable of spawning children. Only one queen can exist at a time." + set category = "Abilities" + + if(alien_queen_exists()) + src << "We already have an active queen." + return + + if(check_alien_ability(500)) + visible_message("[src] begins to twist and contort!", "You begin to evolve!") + src.set_species("Xenomorph Queen") + + return + +/mob/living/carbon/human/proc/plant() + set name = "Plant Weeds (50)" + set desc = "Plants some alien weeds" + set category = "Abilities" + + if(check_alien_ability(50,1,O_RESIN)) + visible_message("[src] has planted some alien weeds!") + new /obj/effect/alien/weeds/node(loc) + return + +/mob/living/carbon/human/proc/corrosive_acid(O as obj|turf in oview(1)) //If they right click to corrode, an error will flash if its an invalid target./N + set name = "Corrosive Acid (200)" + set desc = "Drench an object in acid, destroying it over time." + set category = "Abilities" + + if(!O in oview(1)) + src << "[O] is too far away." + return + + // OBJ CHECK + var/cannot_melt + if(isobj(O)) + var/obj/I = O + if(I.unacidable) + cannot_melt = 1 + else + if(istype(O, /turf/simulated/wall)) + var/turf/simulated/wall/W = O + if(W.material.flags & MATERIAL_UNMELTABLE) + cannot_melt = 1 + else if(istype(O, /turf/simulated/floor)) +/* var/turf/simulated/floor/F = O //Turfs are qdel'd to space (Even asteroid tiles), will need to be touched by someone smarter than myself. -Mech + if(F.flooring && (F.flooring.flags & TURF_ACID_IMMUNE)) +*/ + cannot_melt = 1 + + if(cannot_melt) + src << "You cannot dissolve this object." + return + + if(check_alien_ability(200,0,O_ACID)) + new /obj/effect/alien/acid(get_turf(O), O) + visible_message("[src] vomits globs of vile stuff all over [O]. It begins to sizzle and melt under the bubbling mess of acid!") + + return + +/mob/living/carbon/human/proc/neurotoxin(mob/target as mob in oview()) + set name = "Spit Neurotoxin (50)" + set desc = "Spits neurotoxin at someone, paralyzing them for a short time if they are not wearing protective gear." + set category = "Abilities" + + if(!check_alien_ability(50,0,O_ACID)) + return + + if(stat || paralysis || stunned || weakened || lying || restrained() || buckled) + src << "You cannot spit neurotoxin in your current state." + return + + visible_message("[src] spits neurotoxin at [target]!", "You spit neurotoxin at [target].") + + var/obj/item/projectile/energy/neurotoxin/A = new(get_turf(src)) + A.firer = src + A.launch(target) + return + +/mob/living/carbon/human/proc/resin() // -- TLE + set name = "Secrete Resin (75)" + set desc = "Secrete tough malleable resin." + set category = "Abilities" + + var/choice = input("Choose what you wish to shape.","Resin building") as null|anything in list("resin door","resin wall","resin membrane","resin nest") //would do it through typesof but then the player choice would have the type path and we don't want the internal workings to be exposed ICly - Urist + if(!choice) + return + + if(!check_alien_ability(75,1,O_RESIN)) + return + + visible_message("[src] vomits up a thick purple substance and begins to shape it!", "You shape a [choice].") + switch(choice) + if("resin door") + new /obj/structure/simple_door/resin(loc) + if("resin wall") + new /obj/effect/alien/resin/wall(loc) + if("resin membrane") + new /obj/effect/alien/resin/membrane(loc) + if("resin nest") + new /obj/structure/bed/nest(loc) + return + +/mob/living/carbon/human/proc/leap() + set category = "Abilities" + set name = "Leap" + set desc = "Leap at a target and grab them aggressively." + + if(last_special > world.time) + return + + if(stat || paralysis || stunned || weakened || lying || restrained() || buckled) + src << "You cannot leap in your current state." + return + + var/list/choices = list() + for(var/mob/living/M in view(6,src)) + if(!istype(M,/mob/living/silicon)) + choices += M + choices -= src + + var/mob/living/T = input(src,"Who do you wish to leap at?") as null|anything in choices + + if(!T || !src || src.stat) return + + if(get_dist(get_turf(T), get_turf(src)) > 4) return + + if(last_special > world.time) + return + + if(stat || paralysis || stunned || weakened || lying || restrained() || buckled) + src << "You cannot leap in your current state." + return + + last_special = world.time + 75 + status_flags |= LEAPING + + src.visible_message("\The [src] leaps at [T]!") + src.throw_at(get_step(get_turf(T),get_turf(src)), 4, 1, src) + playsound(src.loc, 'sound/voice/shriek1.ogg', 50, 1) + + sleep(5) + + if(status_flags & LEAPING) status_flags &= ~LEAPING + + if(!src.Adjacent(T)) + src << "You miss!" + return + + T.Weaken(3) + + var/use_hand = "left" + if(l_hand) + if(r_hand) + src << "You need to have one hand free to grab someone." + return + else + use_hand = "right" + + src.visible_message("\The [src] seizes [T] aggressively!") + + var/obj/item/weapon/grab/G = new(src,T) + if(use_hand == "left") + l_hand = G + else + r_hand = G + + G.state = GRAB_PASSIVE + G.icon_state = "grabbed1" + G.synch() + +/mob/living/carbon/human/proc/gut() + set category = "Abilities" + set name = "Gut" + set desc = "While grabbing someone aggressively, rip their guts out or tear them apart." + + if(last_special > world.time) + return + + if(stat || paralysis || stunned || weakened || lying) + src << "\red You cannot do that in your current state." + return + + var/obj/item/weapon/grab/G = locate() in src + if(!G || !istype(G)) + src << "\red You are not grabbing anyone." + return + + if(G.state < GRAB_AGGRESSIVE) + src << "\red You must have an aggressive grab to gut your prey!" + return + + last_special = world.time + 50 + + visible_message("\The [src] rips viciously at \the [G.affecting]'s body with its claws!") + + if(istype(G.affecting,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = G.affecting + H.apply_damage(50,BRUTE) + if(H.stat == 2) + H.gib() + + else + var/mob/living/M = G.affecting + if(!istype(M)) return //wut + M.apply_damage(50,BRUTE) + if(M.stat == 2) + M.gib() diff --git a/code/modules/mob/living/carbon/human/species/xenomorphs/alien_species.dm b/code/modules/mob/living/carbon/human/species/xenomorphs/alien_species.dm new file mode 100644 index 0000000000..e9a1ec1673 --- /dev/null +++ b/code/modules/mob/living/carbon/human/species/xenomorphs/alien_species.dm @@ -0,0 +1,326 @@ +//Stand-in until this is made more lore-friendly. +/datum/species/xenos + name = "Xenomorph" + name_plural = "Xenomorphs" + + default_language = "Xenomorph" + language = "Hivemind" + unarmed_types = list(/datum/unarmed_attack/claws/strong, /datum/unarmed_attack/bite/strong) + hud_type = /datum/hud_data/alien + rarity_value = 3 + + has_fine_manipulation = 0 + siemens_coefficient = 0 + gluttonous = 3 + + brute_mod = 0.5 // Hardened carapace. + burn_mod = 2 // Weak to fire. + + warning_low_pressure = 50 + hazard_low_pressure = -1 + + cold_level_1 = 50 + cold_level_2 = -1 + cold_level_3 = -1 + + flags = NO_SCAN | NO_PAIN | NO_SLIP | NO_POISON | NO_MINOR_CUT + spawn_flags = SPECIES_IS_RESTRICTED + + reagent_tag = IS_XENOS + + blood_color = "#05EE05" + flesh_color = "#282846" + gibbed_anim = "gibbed-a" + dusted_anim = "dust-a" + death_message = "lets out a waning guttural screech, green blood bubbling from its maw." + death_sound = 'sound/voice/hiss6.ogg' + + speech_sounds = list('sound/voice/hiss1.ogg','sound/voice/hiss2.ogg','sound/voice/hiss3.ogg','sound/voice/hiss4.ogg') + speech_chance = 100 + + breath_type = null + poison_type = null + + vision_flags = SEE_SELF|SEE_MOBS + + has_organ = list( + O_HEART = /obj/item/organ/internal/heart, + O_BRAIN = /obj/item/organ/internal/brain/xeno, + O_PLASMA = /obj/item/organ/internal/xenos/plasmavessel, + O_HIVE = /obj/item/organ/internal/xenos/hivenode, + O_NUTRIENT = /obj/item/organ/internal/diona/nutrients + ) + + bump_flag = ALIEN + swap_flags = ~HEAVY + push_flags = (~HEAVY) ^ ROBOT + + var/alien_number = 0 + var/caste_name = "creature" // Used to update alien name. + var/weeds_heal_rate = 1 // Health regen on weeds. + var/weeds_plasma_rate = 5 // Plasma regen on weeds. + + has_limbs = list( + BP_TORSO = list("path" = /obj/item/organ/external/chest), + BP_GROIN = list("path" = /obj/item/organ/external/groin), + BP_HEAD = list("path" = /obj/item/organ/external/head/no_eyes), + BP_L_ARM = list("path" = /obj/item/organ/external/arm), + BP_R_ARM = list("path" = /obj/item/organ/external/arm/right), + BP_L_LEG = list("path" = /obj/item/organ/external/leg), + BP_R_LEG = list("path" = /obj/item/organ/external/leg/right), + BP_L_HAND = list("path" = /obj/item/organ/external/hand), + BP_R_HAND = list("path" = /obj/item/organ/external/hand/right), + BP_L_FOOT = list("path" = /obj/item/organ/external/foot), + BP_R_FOOT = list("path" = /obj/item/organ/external/foot/right) + ) + +/datum/species/xenos/get_bodytype() + return "Xenomorph" + +/datum/species/xenos/get_random_name() + return "alien [caste_name] ([alien_number])" + +/datum/species/xenos/can_understand(var/mob/other) + + if(istype(other,/mob/living/carbon/alien/larva)) + return 1 + + return 0 + +/datum/species/xenos/hug(var/mob/living/carbon/human/H,var/mob/living/target) + H.visible_message("[H] caresses [target] with its scythe-like arm.", \ + "You caress [target] with your scythe-like arm.") + +/datum/species/xenos/handle_post_spawn(var/mob/living/carbon/human/H) + + if(H.mind) + H.mind.assigned_role = "Alien" + H.mind.special_role = "Alien" + + alien_number++ //Keep track of how many aliens we've had so far. + H.real_name = "alien [caste_name] ([alien_number])" + H.name = H.real_name + + ..() + +/datum/species/xenos/handle_environment_special(var/mob/living/carbon/human/H) + + var/turf/T = H.loc + if(!T) return + var/datum/gas_mixture/environment = T.return_air() + if(!environment) return + + if(environment.gas["phoron"] > 0 || locate(/obj/effect/alien/weeds) in T) + if(!regenerate(H)) + var/obj/item/organ/internal/xenos/plasmavessel/P = H.internal_organs_by_name[O_PLASMA] + P.stored_plasma += weeds_plasma_rate + P.stored_plasma = min(max(P.stored_plasma,0),P.max_plasma) + ..() + +/datum/species/xenos/proc/regenerate(var/mob/living/carbon/human/H) + var/heal_rate = weeds_heal_rate + var/mend_prob = 10 + if (!H.resting) + heal_rate = weeds_heal_rate / 3 + mend_prob = 1 + + //first heal damages + if (H.getBruteLoss() || H.getFireLoss() || H.getOxyLoss() || H.getToxLoss()) + H.adjustBruteLoss(-heal_rate) + H.adjustFireLoss(-heal_rate) + H.adjustOxyLoss(-heal_rate) + H.adjustToxLoss(-heal_rate) + if (prob(5)) + H << "You feel a soothing sensation come over you..." + return 1 + + //next internal organs + for(var/obj/item/organ/I in H.internal_organs) + if(I.damage > 0) + I.damage = max(I.damage - heal_rate, 0) + if (prob(5)) + H << "You feel a soothing sensation within your [I.parent_organ]..." + return 1 + + //next mend broken bones, approx 10 ticks each + for(var/obj/item/organ/external/E in H.bad_external_organs) + if (E.status & ORGAN_BROKEN) + if (prob(mend_prob)) + if (E.mend_fracture()) + H << "You feel something mend itself inside your [E.name]." + return 1 + + return 0 +/* +/datum/species/xenos/handle_login_special(var/mob/living/carbon/human/H) + H.AddInfectionImages() + ..() + +/datum/species/xenos/handle_logout_special(var/mob/living/carbon/human/H) + H.RemoveInfectionImages() + ..() +*/ +/datum/species/xenos/drone + name = "Xenomorph Drone" + caste_name = "drone" + weeds_plasma_rate = 15 + slowdown = 1 + tail = "xenos_drone_tail" + rarity_value = 5 + + icobase = 'icons/mob/human_races/xenos/r_xenos_drone.dmi' + deform = 'icons/mob/human_races/xenos/r_xenos_drone.dmi' + + has_organ = list( + O_HEART = /obj/item/organ/internal/heart, + O_BRAIN = /obj/item/organ/internal/brain/xeno, + O_PLASMA = /obj/item/organ/internal/xenos/plasmavessel/queen, + O_ACID = /obj/item/organ/internal/xenos/acidgland, + O_HIVE = /obj/item/organ/internal/xenos/hivenode, + O_RESIN = /obj/item/organ/internal/xenos/resinspinner, + O_NUTRIENT = /obj/item/organ/internal/diona/nutrients + ) + + inherent_verbs = list( + /mob/living/proc/ventcrawl, + /mob/living/carbon/human/proc/regurgitate, + /mob/living/carbon/human/proc/plant, + /mob/living/carbon/human/proc/transfer_plasma, + /mob/living/carbon/human/proc/evolve, + /mob/living/carbon/human/proc/resin, + /mob/living/carbon/human/proc/corrosive_acid + ) + +/datum/species/xenos/drone/handle_post_spawn(var/mob/living/carbon/human/H) + + var/mob/living/carbon/human/A = H + if(!istype(A)) + return ..() + ..() + +/datum/species/xenos/hunter + + name = "Xenomorph Hunter" + weeds_plasma_rate = 5 + caste_name = "hunter" + slowdown = -2 + total_health = 150 + tail = "xenos_hunter_tail" + + icobase = 'icons/mob/human_races/xenos/r_xenos_hunter.dmi' + deform = 'icons/mob/human_races/xenos/r_xenos_hunter.dmi' + + has_organ = list( + O_HEART = /obj/item/organ/internal/heart, + O_BRAIN = /obj/item/organ/internal/brain/xeno, + O_PLASMA = /obj/item/organ/internal/xenos/plasmavessel/hunter, + O_HIVE = /obj/item/organ/internal/xenos/hivenode, + O_NUTRIENT = /obj/item/organ/internal/diona/nutrients + ) + + inherent_verbs = list( + /mob/living/proc/ventcrawl, + /mob/living/carbon/human/proc/tackle, + /mob/living/carbon/human/proc/gut, + /mob/living/carbon/human/proc/leap, + /mob/living/carbon/human/proc/psychic_whisper, + /mob/living/carbon/human/proc/regurgitate + ) + +/datum/species/xenos/sentinel + name = "Xenomorph Sentinel" + weeds_plasma_rate = 10 + caste_name = "sentinel" + slowdown = 0 + total_health = 125 + tail = "xenos_sentinel_tail" + + icobase = 'icons/mob/human_races/xenos/r_xenos_sentinel.dmi' + deform = 'icons/mob/human_races/xenos/r_xenos_sentinel.dmi' + + has_organ = list( + O_HEART = /obj/item/organ/internal/heart, + O_BRAIN = /obj/item/organ/internal/brain/xeno, + O_PLASMA = /obj/item/organ/internal/xenos/plasmavessel/sentinel, + O_ACID = /obj/item/organ/internal/xenos/acidgland, + O_HIVE = /obj/item/organ/internal/xenos/hivenode, + O_NUTRIENT = /obj/item/organ/internal/diona/nutrients + ) + + inherent_verbs = list( + /mob/living/proc/ventcrawl, + /mob/living/carbon/human/proc/tackle, + /mob/living/carbon/human/proc/regurgitate, + /mob/living/carbon/human/proc/transfer_plasma, + /mob/living/carbon/human/proc/corrosive_acid, + /mob/living/carbon/human/proc/neurotoxin + ) + +/datum/species/xenos/queen + + name = "Xenomorph Queen" + total_health = 250 + weeds_heal_rate = 5 + weeds_plasma_rate = 20 + caste_name = "queen" + slowdown = 4 + tail = "xenos_queen_tail" + rarity_value = 10 + + icobase = 'icons/mob/human_races/xenos/r_xenos_queen.dmi' + deform = 'icons/mob/human_races/xenos/r_xenos_queen.dmi' + + has_organ = list( + O_HEART = /obj/item/organ/internal/heart, + O_BRAIN = /obj/item/organ/internal/brain/xeno, + O_EGG = /obj/item/organ/internal/xenos/eggsac, + O_PLASMA = /obj/item/organ/internal/xenos/plasmavessel/queen, + O_ACID = /obj/item/organ/internal/xenos/acidgland, + O_HIVE = /obj/item/organ/internal/xenos/hivenode, + O_RESIN = /obj/item/organ/internal/xenos/resinspinner, + O_NUTRIENT = /obj/item/organ/internal/diona/nutrients + ) + + inherent_verbs = list( + /mob/living/proc/ventcrawl, + /mob/living/carbon/human/proc/psychic_whisper, + /mob/living/carbon/human/proc/regurgitate, + /mob/living/carbon/human/proc/lay_egg, + /mob/living/carbon/human/proc/plant, + /mob/living/carbon/human/proc/transfer_plasma, + /mob/living/carbon/human/proc/corrosive_acid, + /mob/living/carbon/human/proc/neurotoxin, + /mob/living/carbon/human/proc/resin + ) + +/datum/species/xenos/queen/handle_login_special(var/mob/living/carbon/human/H) + ..() + // Make sure only one official queen exists at any point. + if(!alien_queen_exists(1,H)) + H.real_name = "alien queen ([alien_number])" + H.name = H.real_name + else + H.real_name = "alien princess ([alien_number])" + H.name = H.real_name + +/datum/hud_data/alien + + icon = 'icons/mob/screen1_alien.dmi' + has_a_intent = 1 + has_m_intent = 1 + has_warnings = 1 + has_hands = 1 + has_drop = 1 + has_throw = 1 + has_resist = 1 + has_pressure = 0 + has_nutrition = 0 + has_bodytemp = 0 + has_internals = 0 + + gear = list( + "o_clothing" = list("loc" = ui_belt, "name" = "Suit", "slot" = slot_wear_suit, "state" = "equip", "dir" = SOUTH), + "head" = list("loc" = ui_id, "name" = "Hat", "slot" = slot_head, "state" = "hair"), + "storage1" = list("loc" = ui_storage1, "name" = "Left Pocket", "slot" = slot_l_store, "state" = "pocket"), + "storage2" = list("loc" = ui_storage2, "name" = "Right Pocket", "slot" = slot_r_store, "state" = "pocket"), + ) diff --git a/code/modules/mob/living/carbon/human/species/xenomorphs/xenomorphs.dm b/code/modules/mob/living/carbon/human/species/xenomorphs/xenomorphs.dm new file mode 100644 index 0000000000..3fb6958427 --- /dev/null +++ b/code/modules/mob/living/carbon/human/species/xenomorphs/xenomorphs.dm @@ -0,0 +1,52 @@ +proc/create_new_xenomorph(var/alien_caste,var/target) + + target = get_turf(target) + if(!target || !alien_caste) return + + var/mob/living/carbon/human/new_alien = new(target) + new_alien.set_species("Xenomorph [alien_caste]") + return new_alien + +/mob/living/carbon/human/xdrone/New(var/new_loc) + h_style = "Bald" + ..(new_loc, "Xenomorph Drone") + +/mob/living/carbon/human/xsentinel/New(var/new_loc) + h_style = "Bald" + ..(new_loc, "Xenomorph Sentinel") + +/mob/living/carbon/human/xhunter/New(var/new_loc) + h_style = "Bald" + ..(new_loc, "Xenomorph Hunter") + +/mob/living/carbon/human/xqueen/New(var/new_loc) + h_style = "Bald" + ..(new_loc, "Xenomorph Queen") + +// I feel like we should generalize/condense down all the various icon-rendering antag procs. +/*---------------------------------------- +Proc: AddInfectionImages() +Des: Gives the client of the alien an image on each infected mob. +----------------------------------------*/ +/* +/mob/living/carbon/human/proc/AddInfectionImages() + if (client) + for (var/mob/living/C in mob_list) + if(C.status_flags & XENO_HOST) + var/obj/item/alien_embryo/A = locate() in C + var/I = image('icons/mob/alien.dmi', loc = C, icon_state = "infected[A.stage]") + client.images += I + return +*/ +/*---------------------------------------- +Proc: RemoveInfectionImages() +Des: Removes all infected images from the alien. +----------------------------------------*/ +/* +/mob/living/carbon/human/proc/RemoveInfectionImages() + if (client) + for(var/image/I in client.images) + if(dd_hasprefix_case(I.icon_state, "infected")) + qdel(I) + return +*/ diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index ba5b24dbe7..e183b2796c 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -1,4 +1,10 @@ // fun if you want to typecast humans/monkeys/etc without writing long path-filled lines. +/proc/isxenomorph(A) + if(istype(A, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = A + return istype(H.species, /datum/species/xenos) + return 0 + /proc/issmall(A) if(A && istype(A, /mob/living)) var/mob/living/L = A diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index 085f601aef..82c0a1e40f 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -161,6 +161,30 @@ qdel(src) return O +//human -> alien +/mob/living/carbon/human/proc/Alienize() + if (transforming) + return + for(var/obj/item/W in src) + drop_from_inventory(W) + regenerate_icons() + transforming = 1 + canmove = 0 + icon = null + invisibility = 101 + for(var/t in organs) + qdel(t) + + var/alien_caste = pick("Hunter","Sentinel","Drone") + var/mob/living/carbon/human/new_xeno = create_new_xenomorph(alien_caste,loc) + + new_xeno.a_intent = I_HURT + new_xeno.key = key + + new_xeno << "You are now an alien." + qdel(src) + return + /mob/living/carbon/human/proc/slimeize(adult as num, reproduce as num) if (transforming) return diff --git a/code/modules/organs/subtypes/xenos.dm b/code/modules/organs/subtypes/xenos.dm new file mode 100644 index 0000000000..95024a6355 --- /dev/null +++ b/code/modules/organs/subtypes/xenos.dm @@ -0,0 +1,51 @@ +//XENOMORPH ORGANS +/obj/item/organ/internal/xenos + name = "xeno organ" + icon = 'icons/effects/blood.dmi' + desc = "It smells like an accident in a chemical factory." + +/obj/item/organ/internal/xenos/eggsac + name = "egg sac" + parent_organ = BP_GROIN + icon_state = "xgibmid1" + organ_tag = O_EGG + +/obj/item/organ/internal/xenos/plasmavessel + name = "plasma vessel" + parent_organ = BP_TORSO + icon_state = "xgibdown1" + organ_tag = O_PLASMA + var/stored_plasma = 0 + var/max_plasma = 500 + +/obj/item/organ/internal/xenos/plasmavessel/queen + name = "bloated plasma vessel" + stored_plasma = 200 + max_plasma = 500 + +/obj/item/organ/internal/xenos/plasmavessel/sentinel + stored_plasma = 100 + max_plasma = 250 + +/obj/item/organ/internal/xenos/plasmavessel/hunter + name = "tiny plasma vessel" + stored_plasma = 100 + max_plasma = 150 + +/obj/item/organ/internal/xenos/acidgland + name = "acid gland" + parent_organ = BP_HEAD + icon_state = "xgibtorso" + organ_tag = O_ACID + +/obj/item/organ/internal/xenos/hivenode + name = "hive node" + parent_organ = BP_TORSO + icon_state = "xgibmid2" + organ_tag = O_HIVE + +/obj/item/organ/internal/xenos/resinspinner + name = "resin spinner" + parent_organ = BP_HEAD + icon_state = "xgibmid2" + organ_tag = O_RESIN diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm index 25f6025b98..0bb6b223ab 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm @@ -258,6 +258,10 @@ /datum/reagent/toxin/plantbgone/touch_obj(var/obj/O, var/volume) if(istype(O, /obj/effect/plant)) qdel(O) + else if(istype(O, /obj/effect/alien/weeds/)) + var/obj/effect/alien/weeds/alien_weeds = O + alien_weeds.health -= rand(15, 35) + alien_weeds.healthcheck() /datum/reagent/toxin/plantbgone/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) if(alien == IS_DIONA) diff --git a/code/modules/surgery/organs_internal.dm b/code/modules/surgery/organs_internal.dm index 205089773d..9dc0f65836 100644 --- a/code/modules/surgery/organs_internal.dm +++ b/code/modules/surgery/organs_internal.dm @@ -12,6 +12,47 @@ var/obj/item/organ/external/affected = target.get_organ(target_zone) return affected && affected.open == (affected.encased ? 3 : 2) + +////////////////////////////////////////////////////////////////// +// ALIEN EMBRYO SURGERY // +////////////////////////////////////////////////////////////////// // Here for future reference incase it's needed. See: Alien_embryo.dm and Alien_facehugger.dm +/* +/datum/surgery_step/internal/remove_embryo + allowed_tools = list( + /obj/item/weapon/surgical/hemostat = 100, \ + /obj/item/weapon/wirecutters = 75, \ + /obj/item/weapon/material/kitchen/utensil/fork = 20 + ) + blood_level = 2 + + min_duration = 80 + max_duration = 100 + + can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/embryo = 0 + for(var/obj/item/alien_embryo/A in target) + embryo = 1 + break + + if (!hasorgans(target)) + return + var/obj/item/organ/external/affected = target.get_organ(target_zone) + return ..() && affected && embryo && affected.open == 3 && target_zone == BP_TORSO + + begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + var/msg = "[user] starts to pull something out from [target]'s ribcage with \the [tool]." + var/self_msg = "You start to pull something out from [target]'s ribcage with \the [tool]." + user.visible_message(msg, self_msg) + target.custom_pain("Something hurts horribly in your chest!",1) + ..() + + end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) + user.visible_message("[user] rips the larva out of [target]'s ribcage!", + "You rip the larva out of [target]'s ribcage!") + + for(var/obj/item/alien_embryo/A in target) + A.loc = A.loc.loc +*/ ////////////////////////////////////////////////////////////////// // CHEST INTERNAL ORGAN SURGERY // ////////////////////////////////////////////////////////////////// diff --git a/icons/mob/human_races/xenos/r_xenos_drone.dmi b/icons/mob/human_races/xenos/r_xenos_drone.dmi new file mode 100644 index 0000000000..19094d66ed Binary files /dev/null and b/icons/mob/human_races/xenos/r_xenos_drone.dmi differ diff --git a/icons/mob/human_races/xenos/r_xenos_hunter.dmi b/icons/mob/human_races/xenos/r_xenos_hunter.dmi new file mode 100644 index 0000000000..a6ce545f3a Binary files /dev/null and b/icons/mob/human_races/xenos/r_xenos_hunter.dmi differ diff --git a/icons/mob/human_races/xenos/r_xenos_queen.dmi b/icons/mob/human_races/xenos/r_xenos_queen.dmi new file mode 100644 index 0000000000..efb5558ac1 Binary files /dev/null and b/icons/mob/human_races/xenos/r_xenos_queen.dmi differ diff --git a/icons/mob/human_races/xenos/r_xenos_sentinel.dmi b/icons/mob/human_races/xenos/r_xenos_sentinel.dmi new file mode 100644 index 0000000000..5b250c7445 Binary files /dev/null and b/icons/mob/human_races/xenos/r_xenos_sentinel.dmi differ diff --git a/icons/mob/screen1_alien.dmi b/icons/mob/screen1_alien.dmi index b21cd203dd..6e9b9eccf8 100644 Binary files a/icons/mob/screen1_alien.dmi and b/icons/mob/screen1_alien.dmi differ diff --git a/polaris.dme b/polaris.dme index 7c8dfd1d64..c9e64f810f 100644 --- a/polaris.dme +++ b/polaris.dme @@ -315,6 +315,7 @@ #include "code\game\antagonist\antagonist_print.dm" #include "code\game\antagonist\antagonist_update.dm" #include "code\game\antagonist\alien\borer.dm" +#include "code\game\antagonist\alien\xenomorph.dm" #include "code\game\antagonist\outsider\commando.dm" #include "code\game\antagonist\outsider\deathsquad.dm" #include "code\game\antagonist\outsider\ert.dm" @@ -747,6 +748,7 @@ #include "code\game\objects\effects\spiders.dm" #include "code\game\objects\effects\step_triggers.dm" #include "code\game\objects\effects\zone_divider.dm" +#include "code\game\objects\effects\alien\aliens.dm" #include "code\game\objects\effects\chem\chemsmoke.dm" #include "code\game\objects\effects\chem\foam.dm" #include "code\game\objects\effects\chem\water.dm" @@ -1009,6 +1011,7 @@ #include "code\game\objects\structures\crates_lockers\closets\secure\scientist.dm" #include "code\game\objects\structures\crates_lockers\closets\secure\secure_closets.dm" #include "code\game\objects\structures\crates_lockers\closets\secure\security.dm" +#include "code\game\objects\structures\stool_bed_chair_nest\alien_nests.dm" #include "code\game\objects\structures\stool_bed_chair_nest\bed.dm" #include "code\game\objects\structures\stool_bed_chair_nest\chairs.dm" #include "code\game\objects\structures\stool_bed_chair_nest\stools.dm" @@ -1115,6 +1118,7 @@ #include "code\modules\admin\secrets\fun_secrets\turn_humans_into_monkeys.dm" #include "code\modules\admin\secrets\random_events\gravity.dm" #include "code\modules\admin\secrets\random_events\trigger_cordical_borer_infestation.dm" +#include "code\modules\admin\secrets\random_events\trigger_xenomorph_infestation.dm" #include "code\modules\admin\verbs\adminhelp.dm" #include "code\modules\admin\verbs\adminjump.dm" #include "code\modules\admin\verbs\adminpm.dm" @@ -1620,6 +1624,9 @@ #include "code\modules\mob\living\carbon\alien\diona\progression.dm" #include "code\modules\mob\living\carbon\alien\diona\say_understands.dm" #include "code\modules\mob\living\carbon\alien\diona\update_icons.dm" +#include "code\modules\mob\living\carbon\alien\larva\larva.dm" +#include "code\modules\mob\living\carbon\alien\larva\life.dm" +#include "code\modules\mob\living\carbon\alien\larva\progression.dm" #include "code\modules\mob\living\carbon\brain\brain.dm" #include "code\modules\mob\living\carbon\brain\death.dm" #include "code\modules\mob\living\carbon\brain\emote.dm" @@ -1664,6 +1671,9 @@ #include "code\modules\mob\living\carbon\human\species\station\prometheans.dm" #include "code\modules\mob\living\carbon\human\species\station\seromi.dm" #include "code\modules\mob\living\carbon\human\species\station\station.dm" +#include "code\modules\mob\living\carbon\human\species\xenomorphs\alien_powers.dm" +#include "code\modules\mob\living\carbon\human\species\xenomorphs\alien_species.dm" +#include "code\modules\mob\living\carbon\human\species\xenomorphs\xenomorphs.dm" #include "code\modules\mob\living\carbon\metroid\death.dm" #include "code\modules\mob\living\carbon\metroid\emote.dm" #include "code\modules\mob\living\carbon\metroid\examine.dm" @@ -1834,6 +1844,7 @@ #include "code\modules\organs\subtypes\unathi.dm" #include "code\modules\organs\subtypes\unbreakable.dm" #include "code\modules\organs\subtypes\vox.dm" +#include "code\modules\organs\subtypes\xenos.dm" #include "code\modules\overmap\_defines.dm" #include "code\modules\overmap\sectors.dm" #include "code\modules\overmap\ships\ship.dm"