diff --git a/code/__defines/mobs.dm b/code/__defines/mobs.dm index 4bc19b6ca3..68b313d9a1 100644 --- a/code/__defines/mobs.dm +++ b/code/__defines/mobs.dm @@ -26,11 +26,11 @@ #define BORGXRAY 0x4 #define BORGMATERIAL 8 -#define HOSTILE_STANCE_IDLE 1 -#define HOSTILE_STANCE_ALERT 2 -#define HOSTILE_STANCE_ATTACK 3 -#define HOSTILE_STANCE_ATTACKING 4 -#define HOSTILE_STANCE_TIRED 5 +#define STANCE_IDLE 1 +#define STANCE_ALERT 2 +#define STANCE_ATTACK 3 +#define STANCE_ATTACKING 4 +#define STANCE_TIRED 5 #define LEFT 1 #define RIGHT 2 @@ -186,3 +186,8 @@ #define MOB_PULL_SMALLER 1 #define MOB_PULL_SAME 2 #define MOB_PULL_LARGER 3 + +//XENOBIO2 FLAGS +#define NOMUT 0 +#define COLORMUT 1 +#define SPECIESMUT 2 diff --git a/code/_helpers/global_lists.dm b/code/_helpers/global_lists.dm index f00e97d484..7ce97d62e6 100644 --- a/code/_helpers/global_lists.dm +++ b/code/_helpers/global_lists.dm @@ -231,3 +231,5 @@ var/global/list/string_slot_flags = list( . += " has: [t]\n" world << . */ +//Hexidecimal numbers +var/global/list/hexNums = list("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F") diff --git a/code/_macros.dm b/code/_macros.dm index e8caac8345..45e67c7530 100644 --- a/code/_macros.dm +++ b/code/_macros.dm @@ -36,3 +36,5 @@ #define issilicon(A) istype(A, /mob/living/silicon) #define isslime(A) istype(A, /mob/living/carbon/slime) + +#define isxeno(A) istype(A, /mob/living/simple_animal/xeno) diff --git a/code/controllers/verbs.dm b/code/controllers/verbs.dm index bb7bf300d0..ee361c9888 100644 --- a/code/controllers/verbs.dm +++ b/code/controllers/verbs.dm @@ -25,7 +25,7 @@ usr.client.debug_variables(antag) message_admins("Admin [key_name_admin(usr)] is debugging the [antag.role_text] template.") -/client/proc/debug_controller(controller in list("Master","Ticker","Ticker Process","Air","Jobs","Sun","Radio","Supply","Shuttles","Emergency Shuttle","Configuration","pAI", "Cameras", "Transfer Controller", "Gas Data","Event","Plants","Alarm","Nano","Chemistry","Vote")) +/client/proc/debug_controller(controller in list("Master","Ticker","Ticker Process","Air","Jobs","Sun","Radio","Supply","Shuttles","Emergency Shuttle","Configuration","pAI", "Cameras", "Transfer Controller", "Gas Data","Event","Plants","Alarm","Nano","Chemistry","Vote","Xenobio")) set category = "Debug" set name = "Debug Controller" set desc = "Debug the various periodic loop controllers for the game (be careful!)" @@ -95,5 +95,8 @@ if("Vote") debug_variables(vote) feedback_add_details("admin_verb", "DVote") + if("Xenobio") + debug_variables(xenobio_controller) + feedback_add_details("admin_verb", "DXenobio") message_admins("Admin [key_name_admin(usr)] is debugging the [controller] controller.") return diff --git a/code/game/machinery/kitchen/smartfridge.dm b/code/game/machinery/kitchen/smartfridge.dm index ac13a52bc4..8790bb337f 100644 --- a/code/game/machinery/kitchen/smartfridge.dm +++ b/code/game/machinery/kitchen/smartfridge.dm @@ -57,15 +57,20 @@ return 0 /obj/machinery/smartfridge/secure/extract - name = "\improper Slime Extract Storage" - desc = "A refrigerated storage unit for slime extracts" + name = "\improper Biological Sample Storage" + desc = "A refrigerated storage unit for xenobiological samples." req_access = list(access_research) /obj/machinery/smartfridge/secure/extract/accept_check(var/obj/item/O as obj) - if(istype(O,/obj/item/slime_extract)) + if(istype(O,/obj/item/xenoproduct/)) return 1 return 0 +/obj/machinery/smartfridge/secure/extract/New() + for(var/i=1 to 5) + var/obj/item/xenoproduct/slime/core/C = new(src) + C.traits = new() + /obj/machinery/smartfridge/secure/medbay name = "\improper Refrigerated Medicine Storage" desc = "A refrigerated storage unit for storing medicine and chemicals." diff --git a/code/game/machinery/telecomms/machine_interactions.dm b/code/game/machinery/telecomms/machine_interactions.dm index 2b3561395f..002da7bc53 100644 --- a/code/game/machinery/telecomms/machine_interactions.dm +++ b/code/game/machinery/telecomms/machine_interactions.dm @@ -196,7 +196,7 @@ // Returns a multitool from a user depending on their mobtype. -/obj/machinery/telecomms/proc/get_multitool(mob/user as mob) +/obj/machinery/proc/get_multitool(mob/user as mob) //No need to have this being a telecomms specific proc. var/obj/item/device/multitool/P = null // Let's double check diff --git a/code/game/objects/items/devices/multitool.dm b/code/game/objects/items/devices/multitool.dm index e7cb6f3475..cbc60670e7 100644 --- a/code/game/objects/items/devices/multitool.dm +++ b/code/game/objects/items/devices/multitool.dm @@ -21,3 +21,13 @@ origin_tech = list(TECH_MAGNET = 1, TECH_ENGINEERING = 1) var/obj/machinery/telecomms/buffer // simple machine buffer for device linkage var/obj/machinery/clonepod/connecting //same for cryopod linkage + var/obj/machinery/connectable //Used to connect machinery, currently only used by Xenobio2. + +/obj/item/device/multitool/attack_self(mob/user) + var/clear = alert("Do you want to clear the buffers on the [src]?",, "Yes", "No",) + if(clear == "Yes") + buffer = null + connecting = null + connectable = null + else + ..() \ No newline at end of file diff --git a/code/game/objects/items/weapons/grenades/emgrenade.dm b/code/game/objects/items/weapons/grenades/emgrenade.dm index 632c82b474..91b2d8f7e1 100644 --- a/code/game/objects/items/weapons/grenades/emgrenade.dm +++ b/code/game/objects/items/weapons/grenades/emgrenade.dm @@ -1,5 +1,5 @@ /obj/item/weapon/grenade/empgrenade - name = "classic emp grenade" + name = "emp grenade" icon_state = "emp" item_state = "empgrenade" origin_tech = list(TECH_MATERIAL = 2, TECH_MAGNET = 3) @@ -12,7 +12,7 @@ /obj/item/weapon/grenade/empgrenade/low_yield name = "low yield emp grenade" - desc = "A weaker variant of the classic emp grenade" + desc = "A weaker variant of the EMP grenade" icon_state = "lyemp" item_state = "lyempgrenade" origin_tech = list(TECH_MATERIAL = 2, TECH_MAGNET = 3) diff --git a/code/game/objects/items/weapons/stunbaton.dm b/code/game/objects/items/weapons/stunbaton.dm index b9a4f616b3..b7e55cddb8 100644 --- a/code/game/objects/items/weapons/stunbaton.dm +++ b/code/game/objects/items/weapons/stunbaton.dm @@ -12,6 +12,7 @@ w_class = 3 origin_tech = list(TECH_COMBAT = 2) attack_verb = list("beaten") + var/lightcolor = "#FF6A00" var/stunforce = 0 var/agonyforce = 60 var/status = 0 //whether the thing is on or not @@ -52,7 +53,7 @@ icon_state = "[initial(name)]" if(icon_state == "[initial(name)]_active") - set_light(1.5, 1, "#FF6A00") + set_light(1.5, 1, lightcolor) else set_light(0) diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 78aca1da78..f049424b02 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -183,6 +183,7 @@ var/list/admin_verbs_debug = list( /client/proc/overlay_random_map, /client/proc/delete_random_map, /client/proc/show_plant_genes, + /client/proc/show_xenobio_genes, /client/proc/enable_debug_verbs, /client/proc/callproc, /client/proc/callproc_target, diff --git a/code/modules/hydroponics/seed.dm b/code/modules/hydroponics/seed.dm index 0974a705ce..6f4f82b8b8 100644 --- a/code/modules/hydroponics/seed.dm +++ b/code/modules/hydroponics/seed.dm @@ -400,7 +400,7 @@ "potassium", "plasticide", "mutationtoxin", - "amutationtoxin", + "docilitytoxin", "inaprovaline", "space_drugs", "paroxetine", diff --git a/code/modules/mob/living/simple_animal/hostile/bear.dm b/code/modules/mob/living/simple_animal/hostile/bear.dm index 91f8aa958c..68a7f8cbd3 100644 --- a/code/modules/mob/living/simple_animal/hostile/bear.dm +++ b/code/modules/mob/living/simple_animal/hostile/bear.dm @@ -57,16 +57,16 @@ switch(stance) - if(HOSTILE_STANCE_TIRED) + if(STANCE_TIRED) stop_automated_movement = 1 stance_step++ if(stance_step >= 10) //rests for 10 ticks if(target_mob && target_mob in ListTargets(10)) - stance = HOSTILE_STANCE_ATTACK //If the mob he was chasing is still nearby, resume the attack, otherwise go idle. + stance = STANCE_ATTACK //If the mob he was chasing is still nearby, resume the attack, otherwise go idle. else - stance = HOSTILE_STANCE_IDLE + stance = STANCE_IDLE - if(HOSTILE_STANCE_ALERT) + if(STANCE_ALERT) stop_automated_movement = 1 var/found_mob = 0 if(target_mob && target_mob in ListTargets(10)) @@ -84,14 +84,14 @@ stance_step-- if(stance_step <= -20) //If we have not found a mob for 20-ish ticks, revert to idle mode - stance = HOSTILE_STANCE_IDLE + stance = STANCE_IDLE if(stance_step >= 7) //If we have been staring at a mob for 7 ticks, - stance = HOSTILE_STANCE_ATTACK + stance = STANCE_ATTACK - if(HOSTILE_STANCE_ATTACKING) + if(STANCE_ATTACKING) if(stance_step >= 20) //attacks for 20 ticks, then it gets tired and needs to rest custom_emote(1, "is worn out and needs to rest." ) - stance = HOSTILE_STANCE_TIRED + stance = STANCE_TIRED stance_step = 0 walk(src, 0) //This stops the bear's walking return @@ -99,15 +99,15 @@ /mob/living/simple_animal/hostile/bear/attackby(var/obj/item/O as obj, var/mob/user as mob) - if(stance != HOSTILE_STANCE_ATTACK && stance != HOSTILE_STANCE_ATTACKING) - stance = HOSTILE_STANCE_ALERT + if(stance != STANCE_ATTACK && stance != STANCE_ATTACKING) + stance = STANCE_ALERT stance_step = 6 target_mob = user ..() /mob/living/simple_animal/hostile/bear/attack_hand(mob/living/carbon/human/M as mob) - if(stance != HOSTILE_STANCE_ATTACK && stance != HOSTILE_STANCE_ATTACKING) - stance = HOSTILE_STANCE_ALERT + if(stance != STANCE_ATTACK && stance != STANCE_ATTACKING) + stance = STANCE_ALERT stance_step = 6 target_mob = M ..() @@ -119,7 +119,7 @@ . = ..() if(.) custom_emote(1,"stares alertly at [.]") - stance = HOSTILE_STANCE_ALERT + stance = STANCE_ALERT /mob/living/simple_animal/hostile/bear/LoseTarget() ..(5) diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm index 3ede3e7458..262aad8e1a 100644 --- a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm +++ b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm @@ -90,7 +90,7 @@ /mob/living/simple_animal/hostile/giant_spider/Life() ..() if(!stat) - if(stance == HOSTILE_STANCE_IDLE) + if(stance == STANCE_IDLE) //1% chance to skitter madly away if(!busy && prob(1)) /*var/list/move_targets = list() @@ -113,7 +113,7 @@ /mob/living/simple_animal/hostile/giant_spider/nurse/Life() ..() if(!stat) - if(stance == HOSTILE_STANCE_IDLE) + if(stance == STANCE_IDLE) var/list/can_see = view(src, 10) //30% chance to stop wandering and do something if(!busy && prob(30)) diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm index 33fb8acd24..c4dcfbd3f1 100644 --- a/code/modules/mob/living/simple_animal/hostile/hostile.dm +++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm @@ -1,234 +1,15 @@ /mob/living/simple_animal/hostile faction = "hostile" - var/stance = HOSTILE_STANCE_IDLE //Used to determine behavior - var/mob/living/target_mob - var/attack_same = 0 - var/ranged = 0 - var/rapid = 0 - var/projectiletype - var/projectilesound - var/casingtype - var/move_to_delay = 4 //delay for the automated movement. - var/list/friends = list() - var/break_stuff_probability = 10 + break_stuff_probability = 10 stop_automated_movement_when_pulled = 0 - var/destroy_surroundings = 1 + destroy_surroundings = 1 a_intent = I_HURT + hostile = 1 - var/shuttletarget = null - var/enroute = 0 - -/mob/living/simple_animal/hostile/proc/FindTarget() - - var/atom/T = null - stop_automated_movement = 0 - for(var/atom/A in ListTargets(10)) - - if(A == src) - continue - - var/atom/F = Found(A) - if(F) - T = F - break - - if(isliving(A)) - var/mob/living/L = A - if(L.faction == src.faction && !attack_same) - continue - else if(L in friends) - continue - else - if(!L.stat) - stance = HOSTILE_STANCE_ATTACK - T = L - break - - else if(istype(A, /obj/mecha)) // Our line of sight stuff was already done in ListTargets(). - var/obj/mecha/M = A - if (M.occupant) - stance = HOSTILE_STANCE_ATTACK - T = M - break - return T - - -/mob/living/simple_animal/hostile/proc/Found(var/atom/A) - return - -/mob/living/simple_animal/hostile/proc/MoveToTarget() - stop_automated_movement = 1 - if(!target_mob || SA_attackable(target_mob)) - stance = HOSTILE_STANCE_IDLE - if(target_mob in ListTargets(10)) - if(ranged) - if(get_dist(src, target_mob) <= 6) - OpenFire(target_mob) - else - walk_to(src, target_mob, 1, move_to_delay) - else - stance = HOSTILE_STANCE_ATTACKING - walk_to(src, target_mob, 1, move_to_delay) - -/mob/living/simple_animal/hostile/proc/AttackTarget() - - stop_automated_movement = 1 - if(!target_mob || SA_attackable(target_mob)) - LoseTarget() - return 0 - if(!(target_mob in ListTargets(10))) - LostTarget() - return 0 - if(get_dist(src, target_mob) <= 1) //Attacking - AttackingTarget() - return 1 - -/mob/living/simple_animal/hostile/proc/AttackingTarget() - if(!Adjacent(target_mob)) - return - if(isliving(target_mob)) - var/mob/living/L = target_mob - L.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext) - return L - if(istype(target_mob,/obj/mecha)) - var/obj/mecha/M = target_mob - M.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext) - return M - -/mob/living/simple_animal/hostile/proc/LoseTarget() - stance = HOSTILE_STANCE_IDLE - target_mob = null - walk(src, 0) - -/mob/living/simple_animal/hostile/proc/LostTarget() - stance = HOSTILE_STANCE_IDLE - walk(src, 0) - - -/mob/living/simple_animal/hostile/proc/ListTargets(var/dist = 7) - var/list/L = hearers(src, dist) - - for (var/obj/mecha/M in mechas_list) - if (M.z == src.z && get_dist(src, M) <= dist) - L += M - - return L - -/mob/living/simple_animal/hostile/death() - ..() - walk(src, 0) /mob/living/simple_animal/hostile/Life() . = ..() if(!.) walk(src, 0) - return 0 - if(client) - return 0 - - if(!stat) - switch(stance) - if(HOSTILE_STANCE_IDLE) - target_mob = FindTarget() - - if(HOSTILE_STANCE_ATTACK) - if(destroy_surroundings) - DestroySurroundings() - MoveToTarget() - - if(HOSTILE_STANCE_ATTACKING) - if(destroy_surroundings) - DestroySurroundings() - AttackTarget() - -/mob/living/simple_animal/hostile/proc/OpenFire(target_mob) - var/target = target_mob - visible_message("\red [src] fires at [target]!", 1) - - var/tturf = get_turf(target) - if(rapid) - spawn(1) - Shoot(tturf, src.loc, src) - if(casingtype) - new casingtype(get_turf(src)) - spawn(4) - Shoot(tturf, src.loc, src) - if(casingtype) - new casingtype(get_turf(src)) - spawn(6) - Shoot(tturf, src.loc, src) - if(casingtype) - new casingtype(get_turf(src)) - else - Shoot(tturf, src.loc, src) - if(casingtype) - new casingtype - - stance = HOSTILE_STANCE_IDLE - target_mob = null - return - - -/mob/living/simple_animal/hostile/proc/Shoot(var/target, var/start, var/user, var/bullet = 0) - if(target == start) - return - - var/obj/item/projectile/A = new projectiletype(user:loc) - playsound(user, projectilesound, 100, 1) - if(!A) return - - if (!istype(target, /turf)) - qdel(A) - return - A.launch(target) - return - -/mob/living/simple_animal/hostile/proc/DestroySurroundings() - if(prob(break_stuff_probability)) - for(var/dir in cardinal) // North, South, East, West - for(var/obj/structure/window/obstacle in get_step(src, dir)) - if(obstacle.dir == reverse_dir[dir]) // So that windows get smashed in the right order - obstacle.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext) - return - var/obj/structure/obstacle = locate(/obj/structure, get_step(src, dir)) - if(istype(obstacle, /obj/structure/window) || istype(obstacle, /obj/structure/closet) || istype(obstacle, /obj/structure/table) || istype(obstacle, /obj/structure/grille)) - obstacle.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext) - - -/mob/living/simple_animal/hostile/proc/check_horde() - return 0 - if(emergency_shuttle.shuttle.location) - if(!enroute && !target_mob) //The shuttle docked, all monsters rush for the escape hallway - if(!shuttletarget && escape_list.len) //Make sure we didn't already assign it a target, and that there are targets to pick - shuttletarget = pick(escape_list) //Pick a shuttle target - enroute = 1 - stop_automated_movement = 1 - spawn() - if(!src.stat) - horde() - - if(get_dist(src, shuttletarget) <= 2) //The monster reached the escape hallway - enroute = 0 - stop_automated_movement = 0 - -/mob/living/simple_animal/hostile/proc/horde() - var/turf/T = get_step_to(src, shuttletarget) - for(var/atom/A in T) - if(istype(A,/obj/machinery/door/airlock)) - var/obj/machinery/door/airlock/D = A - D.open(1) - else if(istype(A,/obj/structure/simple_door)) - var/obj/structure/simple_door/D = A - if(D.density) - D.Open() - else if(istype(A,/obj/structure/cult/pylon)) - A.attack_generic(src, rand(melee_damage_lower, melee_damage_upper)) - else if(istype(A, /obj/structure/window) || istype(A, /obj/structure/closet) || istype(A, /obj/structure/table) || istype(A, /obj/structure/grille)) - A.attack_generic(src, rand(melee_damage_lower, melee_damage_upper)) - Move(T) - FindTarget() - if(!target_mob || enroute) - spawn(10) - if(!src.stat) - horde() + return 0 \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm index 49a3055859..ac352edd1a 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm @@ -5,14 +5,14 @@ if(isliving(A)) var/mob/living/L = A if(!L.stat) - stance = HOSTILE_STANCE_ATTACK + stance = STANCE_ATTACK return L else enemies -= L else if(istype(A, /obj/mecha)) var/obj/mecha/M = A if(M.occupant) - stance = HOSTILE_STANCE_ATTACK + stance = STANCE_ATTACK return A /mob/living/simple_animal/hostile/retaliate/ListTargets() diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 563ebb06f1..08ff09703f 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -66,6 +66,33 @@ var/supernatural = 0 var/purge = 0 + //Pulling hostile mob vars down + var/stance = STANCE_IDLE //Used to determine behavior + var/mob/living/target_mob + var/attack_same = 0 + var/ranged = 0 + var/rapid = 0 + var/projectiletype + var/projectilesound + var/casingtype + var/move_to_delay = 4 //delay for the automated movement. + var/list/friends = list() + var/break_stuff_probability = 0 + var/destroy_surroundings = 0 + var/shuttletarget = null + var/enroute = 0 + + var/list/resistances = list( + HALLOSS = 0, + BRUTE = 1, + BURN = 1, + TOX = 1, + OXY = 0, + CLONE = 0 + ) + + var/hostile = 0 + /mob/living/simple_animal/New() ..() verbs -= /mob/verb/observe @@ -204,6 +231,23 @@ if(!atmos_suitable) adjustBruteLoss(unsuitable_atoms_damage) + + //Hostility + if(!stat && !client && hostile) + switch(stance) + if(STANCE_IDLE) + target_mob = FindTarget() + + if(STANCE_ATTACK) + if(destroy_surroundings) + DestroySurroundings() + MoveToTarget() + + if(STANCE_ATTACKING) + if(destroy_surroundings) + DestroySurroundings() + AttackTarget() + return 1 /mob/living/simple_animal/proc/handle_supernatural() @@ -299,7 +343,7 @@ if(O.force <= resistance) user << "This weapon is ineffective, it does no damage." return 2 - + var/damage = O.force if (O.damtype == HALLOSS) damage = 0 @@ -402,3 +446,191 @@ return /mob/living/simple_animal/ExtinguishMob() return + + //Hostile procs moved down +/mob/living/simple_animal/proc/FindTarget() + + var/atom/T = null + stop_automated_movement = 0 + for(var/atom/A in ListTargets(10)) + + if(A == src) + continue + + var/atom/F = Found(A) + if(F) + T = F + break + + if(isliving(A)) + var/mob/living/L = A + if(L.faction == src.faction && !attack_same) + continue + else if(L in friends) + continue + else + if(!L.stat) + stance = STANCE_ATTACK + T = L + break + + else if(istype(A, /obj/mecha)) // Our line of sight stuff was already done in ListTargets(). + var/obj/mecha/M = A + if (M.occupant) + stance = STANCE_ATTACK + T = M + break + return T + + +/mob/living/simple_animal/proc/Found(var/atom/A) + return + +/mob/living/simple_animal/proc/MoveToTarget() + stop_automated_movement = 1 + if(!target_mob || SA_attackable(target_mob)) + stance = STANCE_IDLE + if(target_mob in ListTargets(10)) + if(ranged) + if(get_dist(src, target_mob) <= 6) + OpenFire(target_mob) + else + walk_to(src, target_mob, 1, move_to_delay) + else + stance = STANCE_ATTACKING + walk_to(src, target_mob, 1, move_to_delay) + +/mob/living/simple_animal/proc/AttackTarget() + + stop_automated_movement = 1 + if(!target_mob || SA_attackable(target_mob)) + LoseTarget() + return 0 + if(!(target_mob in ListTargets(10))) + LostTarget() + return 0 + if(get_dist(src, target_mob) <= 1) //Attacking + AttackingTarget() + return 1 + +/mob/living/simple_animal/proc/AttackingTarget() + if(!Adjacent(target_mob)) + return + if(isliving(target_mob)) + var/mob/living/L = target_mob + L.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext) + return L + if(istype(target_mob,/obj/mecha)) + var/obj/mecha/M = target_mob + M.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext) + return M + +/mob/living/simple_animal/proc/LoseTarget() + stance = STANCE_IDLE + target_mob = null + walk(src, 0) + +/mob/living/simple_animal/proc/LostTarget() + stance = STANCE_IDLE + walk(src, 0) + + +/mob/living/simple_animal/proc/ListTargets(var/dist = 7) + var/list/L = hearers(src, dist) + + for (var/obj/mecha/M in mechas_list) + if (M.z == src.z && get_dist(src, M) <= dist) + L += M + + return L + +/mob/living/simple_animal/proc/OpenFire(target_mob) + var/target = target_mob + visible_message("\red [src] fires at [target]!", 1) + + var/tturf = get_turf(target) + if(rapid) + spawn(1) + Shoot(tturf, src.loc, src) + if(casingtype) + new casingtype(get_turf(src)) + spawn(4) + Shoot(tturf, src.loc, src) + if(casingtype) + new casingtype(get_turf(src)) + spawn(6) + Shoot(tturf, src.loc, src) + if(casingtype) + new casingtype(get_turf(src)) + else + Shoot(tturf, src.loc, src) + if(casingtype) + new casingtype + + stance = STANCE_IDLE + target_mob = null + return + + +/mob/living/simple_animal/proc/Shoot(var/target, var/start, var/user, var/bullet = 0) + if(target == start) + return + + var/obj/item/projectile/A = new projectiletype(user:loc) + playsound(user, projectilesound, 100, 1) + if(!A) return + + if (!istype(target, /turf)) + qdel(A) + return + A.launch(target) + return + +/mob/living/simple_animal/proc/DestroySurroundings() + if(prob(break_stuff_probability)) + for(var/dir in cardinal) // North, South, East, West + for(var/obj/structure/window/obstacle in get_step(src, dir)) + if(obstacle.dir == reverse_dir[dir]) // So that windows get smashed in the right order + obstacle.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext) + return + var/obj/structure/obstacle = locate(/obj/structure, get_step(src, dir)) + if(istype(obstacle, /obj/structure/window) || istype(obstacle, /obj/structure/closet) || istype(obstacle, /obj/structure/table) || istype(obstacle, /obj/structure/grille)) + obstacle.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext) + + +/mob/living/simple_animal/proc/check_horde() + return 0 + if(emergency_shuttle.shuttle.location) + if(!enroute && !target_mob) //The shuttle docked, all monsters rush for the escape hallway + if(!shuttletarget && escape_list.len) //Make sure we didn't already assign it a target, and that there are targets to pick + shuttletarget = pick(escape_list) //Pick a shuttle target + enroute = 1 + stop_automated_movement = 1 + spawn() + if(!src.stat) + horde() + + if(get_dist(src, shuttletarget) <= 2) //The monster reached the escape hallway + enroute = 0 + stop_automated_movement = 0 + +/mob/living/simple_animal/proc/horde() + var/turf/T = get_step_to(src, shuttletarget) + for(var/atom/A in T) + if(istype(A,/obj/machinery/door/airlock)) + var/obj/machinery/door/airlock/D = A + D.open(1) + else if(istype(A,/obj/structure/simple_door)) + var/obj/structure/simple_door/D = A + if(D.density) + D.Open() + else if(istype(A,/obj/structure/cult/pylon)) + A.attack_generic(src, rand(melee_damage_lower, melee_damage_upper)) + else if(istype(A, /obj/structure/window) || istype(A, /obj/structure/closet) || istype(A, /obj/structure/table) || istype(A, /obj/structure/grille)) + A.attack_generic(src, rand(melee_damage_lower, melee_damage_upper)) + Move(T) + FindTarget() + if(!target_mob || enroute) + spawn(10) + if(!src.stat) + horde() \ No newline at end of file diff --git a/code/modules/reagents/Chemistry-Holder.dm b/code/modules/reagents/Chemistry-Holder.dm index 89aa9b76f3..b2d04233f2 100644 --- a/code/modules/reagents/Chemistry-Holder.dm +++ b/code/modules/reagents/Chemistry-Holder.dm @@ -383,6 +383,10 @@ if(type == CHEM_TOUCH) var/datum/reagents/R = C.touching return trans_to_holder(R, amount, multiplier, copy) + else if(isxeno(target)) + var/mob/living/simple_animal/xeno/X = target + var/datum/reagents/R = X.reagents + return trans_to_holder(R, amount, multiplier, copy) else var/datum/reagents/R = new /datum/reagents(amount) . = trans_to_holder(R, amount, multiplier, copy) diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm index 0022026a67..bc0072511a 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Toxins.dm @@ -474,42 +474,46 @@ color = "#13BC5E" /datum/reagent/slimetoxin/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) - if(ishuman(M)) - var/mob/living/carbon/human/H = M - if(H.species.name != "Promethean") - M << "Your flesh rapidly mutates!" - H.set_species("Promethean") - H.shapeshifter_set_colour("#05FF9B") - H.verbs -= /mob/living/carbon/human/proc/shapeshifter_select_colour + if(M.isSynthetic()) + return + + var/mob/living/carbon/human/H = M + if(istype(H) && (H.species.flags & NO_SCAN)) + return + + if(M.dna) + if(prob(removed * 0.1)) + randmuti(M) + if(prob(98)) + randmutb(M) + else + randmutg(M) + domutcheck(M, null) + M.UpdateAppearance() + M.apply_effect(16 * removed, IRRADIATE, 0) /datum/reagent/aslimetoxin - name = "Advanced Mutation Toxin" - id = "amutationtoxin" - description = "An advanced corruptive toxin produced by slimes." + name = "Docility Toxin" + id = "docilitytoxin" + description = "A corruptive toxin produced by slimes." reagent_state = LIQUID - color = "#13BC5E" + color = "#FF69B4" /datum/reagent/aslimetoxin/affect_blood(var/mob/living/carbon/M, var/alien, var/removed) // TODO: check if there's similar code anywhere else - if(M.transforming) + if(M.isSynthetic()) return - M << "Your flesh rapidly mutates!" - M.transforming = 1 - M.canmove = 0 - M.icon = null - M.overlays.Cut() - M.invisibility = 101 - for(var/obj/item/W in M) - if(istype(W, /obj/item/weapon/implant)) //TODO: Carn. give implants a dropped() or something - qdel(W) - continue - W.layer = initial(W.layer) - W.loc = M.loc - W.dropped(M) - var/mob/living/carbon/slime/new_mob = new /mob/living/carbon/slime(M.loc) - new_mob.a_intent = "hurt" - new_mob.universal_speak = 1 - if(M.mind) - M.mind.transfer_to(new_mob) - else - new_mob.key = M.key - qdel(M) + + var/mob/living/carbon/human/H = M + if(istype(H) && (H.species.flags & NO_SCAN)) + return + + if(M.dna) + if(prob(removed * 0.1)) + randmuti(M) + if(prob(98)) + randmutb(M) + else + randmutg(M) + domutcheck(M, null) + M.UpdateAppearance() + M.apply_effect(6 * removed, IRRADIATE, 0) diff --git a/code/modules/reagents/Chemistry-Recipes.dm b/code/modules/reagents/Chemistry-Recipes.dm index 8146069f5c..e9c3df5098 100644 --- a/code/modules/reagents/Chemistry-Recipes.dm +++ b/code/modules/reagents/Chemistry-Recipes.dm @@ -998,333 +998,25 @@ /datum/chemical_reaction/slime var/required = null +//Slimed monkeys /datum/chemical_reaction/slime/can_happen(var/datum/reagents/holder) if(holder.my_atom && istype(holder.my_atom, required)) - var/obj/item/slime_extract/T = holder.my_atom - if(T.Uses > 0) - return ..() + return ..() return 0 - -/datum/chemical_reaction/slime/on_reaction(var/datum/reagents/holder) - var/obj/item/slime_extract/T = holder.my_atom - T.Uses-- - if(T.Uses <= 0) - T.visible_message("\icon[T]\The [T]'s power is consumed in the reaction.") - T.name = "used slime extract" - T.desc = "This extract has been used up." - -//Grey -/datum/chemical_reaction/slime/spawn - name = "Slime Spawn" - id = "m_spawn" - result = null - required_reagents = list("phoron" = 1) - result_amount = 1 - required = /obj/item/slime_extract/grey - -/datum/chemical_reaction/slime/spawn/on_reaction(var/datum/reagents/holder) - holder.my_atom.visible_message("Infused with phoron, the core begins to quiver and grow, and soon a new baby slime emerges from it!") - var/mob/living/carbon/slime/S = new /mob/living/carbon/slime - S.loc = get_turf(holder.my_atom) - ..() - -/datum/chemical_reaction/slime/monkey - name = "Slime Monkey" - id = "m_monkey" - result = null - required_reagents = list("blood" = 1) - result_amount = 1 - required = /obj/item/slime_extract/grey - -/datum/chemical_reaction/slime/monkey/on_reaction(var/datum/reagents/holder) - for(var/i = 1, i <= 3, i++) - var /obj/item/weapon/reagent_containers/food/snacks/monkeycube/M = new /obj/item/weapon/reagent_containers/food/snacks/monkeycube - M.loc = get_turf(holder.my_atom) - ..() - -//Green -/datum/chemical_reaction/slime/mutate - name = "Mutation Toxin" - id = "mutationtoxin" - result = "mutationtoxin" - required_reagents = list("phoron" = 1) - result_amount = 1 - required = /obj/item/slime_extract/green - -//Metal -/datum/chemical_reaction/slime/metal - name = "Slime Metal" - id = "m_metal" - result = null - required_reagents = list("phoron" = 1) - result_amount = 1 - required = /obj/item/slime_extract/metal - -/datum/chemical_reaction/slime/metal/on_reaction(var/datum/reagents/holder) - var/obj/item/stack/material/steel/M = new /obj/item/stack/material/steel - M.amount = 15 - M.loc = get_turf(holder.my_atom) - var/obj/item/stack/material/plasteel/P = new /obj/item/stack/material/plasteel - P.amount = 5 - P.loc = get_turf(holder.my_atom) - ..() - -//Gold - removed -/datum/chemical_reaction/slime/crit - name = "Slime Crit" - id = "m_tele" - result = null - required_reagents = list("phoron" = 1) - result_amount = 1 - required = /obj/item/slime_extract/gold - mix_message = "The slime core fizzles disappointingly." - -//Silver -/datum/chemical_reaction/slime/bork - name = "Slime Bork" - id = "m_tele2" - result = null - required_reagents = list("phoron" = 1) - result_amount = 1 - required = /obj/item/slime_extract/silver - -/datum/chemical_reaction/slime/bork/on_reaction(var/datum/reagents/holder) - var/list/borks = typesof(/obj/item/weapon/reagent_containers/food/snacks) - /obj/item/weapon/reagent_containers/food/snacks - playsound(get_turf(holder.my_atom), 'sound/effects/phasein.ogg', 100, 1) - for(var/mob/living/carbon/human/M in viewers(get_turf(holder.my_atom), null)) - if(M.eyecheck() <= 0) - flick("e_flash", M.flash) - - for(var/i = 1, i <= 4 + rand(1,2), i++) - var/chosen = pick(borks) - var/obj/B = new chosen - if(B) - B.loc = get_turf(holder.my_atom) - if(prob(50)) - for(var/j = 1, j <= rand(1, 3), j++) - step(B, pick(NORTH, SOUTH, EAST, WEST)) - ..() - -//Blue -/datum/chemical_reaction/slime/frost - name = "Slime Frost Oil" - id = "m_frostoil" - result = "frostoil" - required_reagents = list("phoron" = 1) - result_amount = 10 - required = /obj/item/slime_extract/blue - -//Dark Blue -/datum/chemical_reaction/slime/freeze - name = "Slime Freeze" - id = "m_freeze" - result = null - required_reagents = list("phoron" = 1) - result_amount = 1 - required = /obj/item/slime_extract/darkblue - mix_message = "The slime extract begins to vibrate violently!" - -/datum/chemical_reaction/slime/freeze/on_reaction(var/datum/reagents/holder) - ..() - sleep(50) - playsound(get_turf(holder.my_atom), 'sound/effects/phasein.ogg', 100, 1) - for(var/mob/living/M in range (get_turf(holder.my_atom), 7)) - M.bodytemperature -= 140 - M << "You feel a chill!" - -//Orange -/datum/chemical_reaction/slime/casp - name = "Slime Capsaicin Oil" - id = "m_capsaicinoil" - result = "capsaicin" - required_reagents = list("blood" = 1) - result_amount = 10 - required = /obj/item/slime_extract/orange - -/datum/chemical_reaction/slime/fire - name = "Slime fire" - id = "m_fire" - result = null - required_reagents = list("phoron" = 1) - result_amount = 1 - required = /obj/item/slime_extract/orange - mix_message = "The slime extract begins to vibrate violently!" - -/datum/chemical_reaction/slime/fire/on_reaction(var/datum/reagents/holder) - ..() - sleep(50) - var/turf/location = get_turf(holder.my_atom.loc) - for(var/turf/simulated/floor/target_tile in range(0, location)) - target_tile.assume_gas("phoron", 25, 1400) - spawn (0) - target_tile.hotspot_expose(700, 400) - -//Yellow -/datum/chemical_reaction/slime/overload - name = "Slime EMP" - id = "m_emp" - result = null - required_reagents = list("blood" = 1) - result_amount = 1 - required = /obj/item/slime_extract/yellow - -/datum/chemical_reaction/slime/overload/on_reaction(var/datum/reagents/holder, var/created_volume) - ..() - empulse(get_turf(holder.my_atom), 3, 7) - -/datum/chemical_reaction/slime/cell - name = "Slime Powercell" - id = "m_cell" - result = null - required_reagents = list("phoron" = 1) - result_amount = 1 - required = /obj/item/slime_extract/yellow - -/datum/chemical_reaction/slime/cell/on_reaction(var/datum/reagents/holder, var/created_volume) - var/obj/item/weapon/cell/slime/P = new /obj/item/weapon/cell/slime - P.loc = get_turf(holder.my_atom) - -/datum/chemical_reaction/slime/glow - name = "Slime Glow" - id = "m_glow" - result = null - required_reagents = list("water" = 1) - result_amount = 1 - required = /obj/item/slime_extract/yellow - mix_message = "The contents of the slime core harden and begin to emit a warm, bright light." - -/datum/chemical_reaction/slime/glow/on_reaction(var/datum/reagents/holder, var/created_volume) - ..() - var/obj/item/device/flashlight/slime/F = new /obj/item/device/flashlight/slime - F.loc = get_turf(holder.my_atom) - -//Purple -/datum/chemical_reaction/slime/psteroid - name = "Slime Steroid" - id = "m_steroid" - result = null - required_reagents = list("phoron" = 1) - result_amount = 1 - required = /obj/item/slime_extract/purple - -/datum/chemical_reaction/slime/psteroid/on_reaction(var/datum/reagents/holder, var/created_volume) - ..() - var/obj/item/weapon/slimesteroid/P = new /obj/item/weapon/slimesteroid - P.loc = get_turf(holder.my_atom) - -/datum/chemical_reaction/slime/jam - name = "Slime Jam" - id = "m_jam" - result = "slimejelly" - required_reagents = list("sugar" = 1) - result_amount = 10 - required = /obj/item/slime_extract/purple - -//Dark Purple -/datum/chemical_reaction/slime/plasma - name = "Slime Plasma" - id = "m_plasma" - result = null - required_reagents = list("phoron" = 1) - result_amount = 1 - required = /obj/item/slime_extract/darkpurple - -/datum/chemical_reaction/slime/plasma/on_reaction(var/datum/reagents/holder) - ..() - var/obj/item/stack/material/phoron/P = new /obj/item/stack/material/phoron - P.amount = 10 - P.loc = get_turf(holder.my_atom) - -//Red -/datum/chemical_reaction/slime/glycerol - name = "Slime Glycerol" - id = "m_glycerol" - result = "glycerol" - required_reagents = list("phoron" = 1) - result_amount = 8 - required = /obj/item/slime_extract/red - -/datum/chemical_reaction/slime/bloodlust - name = "Bloodlust" - id = "m_bloodlust" - result = null - required_reagents = list("blood" = 1) - result_amount = 1 - required = /obj/item/slime_extract/red - -/datum/chemical_reaction/slime/bloodlust/on_reaction(var/datum/reagents/holder) - ..() - for(var/mob/living/carbon/slime/slime in viewers(get_turf(holder.my_atom), null)) - slime.rabid = 1 - slime.visible_message("The [slime] is driven into a frenzy!") - -//Pink -/datum/chemical_reaction/slime/ppotion - name = "Slime Potion" - id = "m_potion" - result = null - required_reagents = list("phoron" = 1) - result_amount = 1 - required = /obj/item/slime_extract/pink - -/datum/chemical_reaction/slime/ppotion/on_reaction(var/datum/reagents/holder) - ..() - var/obj/item/weapon/slimepotion/P = new /obj/item/weapon/slimepotion - P.loc = get_turf(holder.my_atom) - -//Black -/datum/chemical_reaction/slime/mutate2 - name = "Advanced Mutation Toxin" - id = "mutationtoxin2" - result = "amutationtoxin" - required_reagents = list("phoron" = 1) - result_amount = 1 - required = /obj/item/slime_extract/black - -//Oil -/datum/chemical_reaction/slime/explosion - name = "Slime Explosion" - id = "m_explosion" - result = null - required_reagents = list("phoron" = 1) - result_amount = 1 - required = /obj/item/slime_extract/oil - mix_message = "The slime extract begins to vibrate violently!" - -/datum/chemical_reaction/slime/explosion/on_reaction(var/datum/reagents/holder) - ..() - sleep(50) - explosion(get_turf(holder.my_atom), 1, 3, 6) - -//Light Pink -/datum/chemical_reaction/slime/potion2 - name = "Slime Potion 2" - id = "m_potion2" - result = null - result_amount = 1 - required = /obj/item/slime_extract/lightpink - required_reagents = list("phoron" = 1) - -/datum/chemical_reaction/slime/potion2/on_reaction(var/datum/reagents/holder) - ..() - var/obj/item/weapon/slimepotion2/P = new /obj/item/weapon/slimepotion2 - P.loc = get_turf(holder.my_atom) - -//Adamantine + /datum/chemical_reaction/slime/golem - name = "Slime Golem" - id = "m_golem" + name = "Prometheans" + id = "m_promethean" result = null - required_reagents = list("phoron" = 1) + required_reagents = list("mutationtoxin" = 1) result_amount = 1 - required = /obj/item/slime_extract/adamantine + required = /obj/item/weapon/reagent_containers/food/snacks/monkeycube /datum/chemical_reaction/slime/golem/on_reaction(var/datum/reagents/holder) - ..() - var/obj/effect/golemrune/Z = new /obj/effect/golemrune - Z.loc = get_turf(holder.my_atom) - Z.announce_to_ghosts() - + var/location = get_turf(holder.my_atom) + new /obj/item/slime_cube(location) + qdel(holder.my_atom) + /* Food */ /datum/chemical_reaction/tofu diff --git a/code/modules/xenobio2/_xeno_setup.dm b/code/modules/xenobio2/_xeno_setup.dm new file mode 100644 index 0000000000..a08cb54681 --- /dev/null +++ b/code/modules/xenobio2/_xeno_setup.dm @@ -0,0 +1,211 @@ +//Important definitions for xenos, traits datum. + +//Definitions for gene grouping. +#define GENE_XENO_BIOCHEMISTRY "biochemistry" +#define GENE_XENO_HEALTH "health" +#define GENE_XENO_RESISTANCES "resistances" +#define GENE_XENO_INTERNAL "internal" +#define GENE_XENO_COLOR "color" +#define GENE_XENO_GLOW "glow" +#define GENE_XENO_LEARN "learn" +#define GENE_XENO_SPEAK "speak" +#define GENE_XENO_SPEED "speed" +#define GENE_XENO_SPECIAL "special" + +#define ALL_XENO_GENES list(GENE_XENO_BIOCHEMISTRY, GENE_XENO_HEALTH, GENE_XENO_RESISTANCES, GENE_XENO_INTERNAL, GENE_XENO_COLOR, GENE_XENO_LEARN, GENE_XENO_SPEAK, GENE_XENO_SPEED, GENE_XENO_SPECIAL) + +//Definitions for traits. + +#define TRAIT_XENO_COLOR "color" +#define TRAIT_XENO_CHEMISTRY "chems" +#define TRAIT_XENO_CHEMVOL "chem_vol" +#define TRAIT_XENO_HEALTH "health" +#define TRAIT_XENO_HUNGER "hunger" +#define TRAIT_XENO_STARVEDAMAGE "starvedamage" +#define TRAIT_XENO_EATS "eats" +#define TRAIT_XENO_CHROMATIC "chrom" +#define TRAIT_XENO_HOSTILE "hostile" +#define TRAIT_XENO_BIOLUMESCENT "biolum" +#define TRAIT_XENO_BIO_COLOR "biocolor" +#define TRAIT_XENO_GLOW_STRENGTH "biostrength" +#define TRAIT_XENO_GLOW_RANGE "biorange" +#define TRAIT_XENO_TOXIC_CHEMS "tox_chems" +#define TRAIT_XENO_NUTRITIONAL_CHEMS "nutr_chems" +#define TRAIT_XENO_HEALING_CHEMS "heal_chems" +#define TRAIT_XENO_MUTATING_CHEMS "mut_chems" +#define TRAIT_XENO_SPEED "speed" +#define TRAIT_XENO_COLDRES "cold_resistance" +#define TRAIT_XENO_HEATRES "heat_resistance" +#define TRAIT_XENO_LEARNCHANCE "learn_chance" +#define TRAIT_XENO_CANLEARN "can_learn" +#define TRAIT_XENO_SPEAKCHANCE "speak_chance" +#define TRAIT_XENO_CANSPEAK "can_speak" +#define TRAIT_XENO_STRENGTH "melee_strength" +#define TRAIT_XENO_STR_RANGE "melee_range" + +//Maleability defines. +#define MAX_MALEABLE 2 +#define MINOR_MALEABLE 1 +#define MIN_MALEABLE 0 + +var/global/list/xenoChemList = list("mutationtoxin", + "psilocybin", + "mindbreaker", + "impedrezene", + "cryptobiolin", + "space_drugs", + "chloralhydrate", + "stoxin", + "mutagen", + "lexorin", + "pacid", + "cyanide", + "phoron", + "plasticide", + "amatoxin", + "carbon", + "radium", + "sacid", + "sugar", + "kelotane", + "dermaline", + "anti_toxin", + "dexalin", + "synaptizine", + "alkysine", + "imidazoline", + "peridaxon", + "rezadone", + "mutationtoxin", + "docilitytoxin") + +/datum/xeno/traits + var/list/traits = list() + var/list/chemlist = list() + var/list/chems = list() + var/source = "unknown" + +/datum/xeno/traits/proc/set_trait(var/trait, var/newval) + traits["[trait]"] = newval + return + +/datum/xeno/traits/proc/get_trait(var/trait) + var/val = traits["[trait]"] + return val + +/datum/xeno/traits/New() + ..() + set_trait(TRAIT_XENO_COLOR, "#CACACA") + set_trait(TRAIT_XENO_CHEMVOL, 100) + set_trait(TRAIT_XENO_HEALTH, 20) + set_trait(TRAIT_XENO_HUNGER, 2) + set_trait(TRAIT_XENO_STARVEDAMAGE, 0) + set_trait(TRAIT_XENO_EATS, 1) + set_trait(TRAIT_XENO_CHROMATIC, 0) + set_trait(TRAIT_XENO_HOSTILE, 0) + set_trait(TRAIT_XENO_BIOLUMESCENT, 0) + set_trait(TRAIT_XENO_BIO_COLOR, "#CACACA") + set_trait(TRAIT_XENO_GLOW_STRENGTH, 0) + set_trait(TRAIT_XENO_GLOW_RANGE, 0) + set_trait(TRAIT_XENO_SPEED, 4) + set_trait(TRAIT_XENO_COLDRES, 20) + set_trait(TRAIT_XENO_HEATRES, 20) + set_trait(TRAIT_XENO_LEARNCHANCE, 100) + set_trait(TRAIT_XENO_CANLEARN, 1) + set_trait(TRAIT_XENO_SPEAKCHANCE, 1) + set_trait(TRAIT_XENO_CANSPEAK, 1) + set_trait(TRAIT_XENO_STRENGTH, 0) + set_trait(TRAIT_XENO_STR_RANGE, 0) + +/datum/xeno/traits/proc/get_gene(var/genetype) + + if(!genetype) return 0 + + var/datum/xeno/genes/G = new() + G.genetype = genetype + G.values = list() + + switch(genetype) + if(GENE_XENO_BIOCHEMISTRY) + G.values["[TRAIT_XENO_CHEMVOL]"] = get_trait(TRAIT_XENO_CHEMVOL) + G.chems = chems + if(GENE_XENO_HEALTH) + G.values["[TRAIT_XENO_HEALTH]"] = get_trait(TRAIT_XENO_HEALTH) + G.values["[TRAIT_XENO_STRENGTH]"] = get_trait(TRAIT_XENO_STRENGTH) + G.values["[TRAIT_XENO_STR_RANGE]"] = get_trait(TRAIT_XENO_STR_RANGE) + if(GENE_XENO_RESISTANCES) + G.values["[TRAIT_XENO_COLDRES]"] = get_trait(TRAIT_XENO_HEALTH) + G.values["[TRAIT_XENO_HEATRES]"] = get_trait(TRAIT_XENO_STRENGTH) + if(GENE_XENO_INTERNAL) + G.values["[TRAIT_XENO_NUTRITIONAL_CHEMS]"] = get_trait(TRAIT_XENO_NUTRITIONAL_CHEMS) + G.values["[TRAIT_XENO_HEALING_CHEMS]"] = get_trait(TRAIT_XENO_HEALING_CHEMS) + G.values["[TRAIT_XENO_TOXIC_CHEMS]"] = get_trait(TRAIT_XENO_TOXIC_CHEMS) + G.values["[TRAIT_XENO_MUTATING_CHEMS]"] = get_trait(TRAIT_XENO_MUTATING_CHEMS) + if(GENE_XENO_COLOR) + G.values["[TRAIT_XENO_COLOR]"] = get_trait(TRAIT_XENO_COLOR) + G.values["[TRAIT_XENO_BIO_COLOR]"] = get_trait(TRAIT_XENO_BIO_COLOR) + if(GENE_XENO_GLOW) + G.values["[TRAIT_XENO_BIOLUMESCENT]"] = get_trait(TRAIT_XENO_BIOLUMESCENT) + G.values["[TRAIT_XENO_GLOW_RANGE]"] = get_trait(TRAIT_XENO_GLOW_RANGE) + G.values["[TRAIT_XENO_GLOW_STRENGTH]"] = get_trait(TRAIT_XENO_GLOW_STRENGTH) + if(GENE_XENO_LEARN) + G.values["[TRAIT_XENO_LEARNCHANCE]"] = get_trait(TRAIT_XENO_LEARNCHANCE) + G.values["[TRAIT_XENO_CANLEARN]"] = get_trait(TRAIT_XENO_CANLEARN) + if(GENE_XENO_SPEAK) + G.values["[TRAIT_XENO_SPEAKCHANCE]"] = get_trait(TRAIT_XENO_SPEAKCHANCE) + G.values["[TRAIT_XENO_CANSPEAK]"] = get_trait(TRAIT_XENO_CANSPEAK) + if(GENE_XENO_SPEED) + G.values["[TRAIT_XENO_SPEED]"] = get_trait(TRAIT_XENO_SPEED) + if(GENE_XENO_SPECIAL) + G.values["[TRAIT_XENO_HOSTILE]"] = get_trait(TRAIT_XENO_HOSTILE) + G.values["[TRAIT_XENO_CHROMATIC]"] = get_trait(TRAIT_XENO_CHROMATIC) + + return G + +/datum/xeno/traits/proc/apply_gene(var/datum/xeno/genes/genes) + if(!genes.genetype) return 0 + + switch(genes.genetype) + if(GENE_XENO_BIOCHEMISTRY) + set_trait(TRAIT_XENO_CHEMVOL, genes.values["[TRAIT_XENO_CHEMVOL]"]) + for(var/reagent in genes.chems) + chems[reagent] = genes[reagent] + + if(GENE_XENO_HEALTH) + set_trait(TRAIT_XENO_HEALTH, genes.values["[TRAIT_XENO_HEALTH]"]) + set_trait(TRAIT_XENO_STRENGTH, genes.values["[TRAIT_XENO_STRENGTH]"]) + set_trait(TRAIT_XENO_STR_RANGE, genes.values["[TRAIT_XENO_STR_RANGE]"]) + if(GENE_XENO_RESISTANCES) + set_trait(TRAIT_XENO_COLDRES, genes.values["[TRAIT_XENO_COLDRES]"]) + set_trait(TRAIT_XENO_HEATRES, genes.values["[TRAIT_XENO_HEATRES]"]) + if(GENE_XENO_INTERNAL) + set_trait(TRAIT_XENO_NUTRITIONAL_CHEMS, genes.values["[TRAIT_XENO_NUTRITIONAL_CHEMS]"]) + set_trait(TRAIT_XENO_HEALING_CHEMS, genes.values["[TRAIT_XENO_HEALING_CHEMS]"]) + set_trait(TRAIT_XENO_TOXIC_CHEMS, genes.values["[TRAIT_XENO_TOXIC_CHEMS]"]) + set_trait(TRAIT_XENO_MUTATING_CHEMS, genes.values["[TRAIT_XENO_MUTATING_CHEMS]"]) + if(GENE_XENO_COLOR) + set_trait(TRAIT_XENO_COLOR, genes.values["[TRAIT_XENO_COLOR]"]) + set_trait(TRAIT_XENO_BIO_COLOR, genes.values["[TRAIT_XENO_BIO_COLOR]"]) + if(GENE_XENO_GLOW) + set_trait(TRAIT_XENO_BIOLUMESCENT, genes.values["[TRAIT_XENO_BIOLUMESCENT]"]) + set_trait(TRAIT_XENO_GLOW_RANGE, genes.values["[TRAIT_XENO_GLOW_RANGE]"]) + set_trait(TRAIT_XENO_GLOW_STRENGTH, genes.values["[TRAIT_XENO_GLOW_STRENGTH]"]) + if(GENE_XENO_LEARN) + set_trait(TRAIT_XENO_LEARNCHANCE, genes.values["[TRAIT_XENO_LEARNCHANCE]"]) + set_trait(TRAIT_XENO_CANLEARN, genes.values["[TRAIT_XENO_CANLEARN]"]) + if(GENE_XENO_SPEAK) + set_trait(TRAIT_XENO_SPEAKCHANCE, genes.values["[TRAIT_XENO_SPEAKCHANCE]"]) + set_trait(TRAIT_XENO_CANSPEAK, genes.values["[TRAIT_XENO_CANSPEAK]"]) + if(GENE_XENO_SPEED) + set_trait(TRAIT_XENO_SPEED ,genes.values["[TRAIT_XENO_SPEED]"]) + if(GENE_XENO_SPECIAL) + set_trait(TRAIT_XENO_HOSTILE, genes.values["[TRAIT_XENO_HOSTILE]"]) + set_trait(TRAIT_XENO_CHROMATIC, genes.values["[TRAIT_XENO_CHROMATIC]"]) + +/datum/xeno/genes + var/genetype //Label for specifying what gene is used. + var/list/values //What's going to be put into specific traits + var/list/chems + + + \ No newline at end of file diff --git a/code/modules/xenobio2/controller.dm b/code/modules/xenobio2/controller.dm new file mode 100644 index 0000000000..112d667c0f --- /dev/null +++ b/code/modules/xenobio2/controller.dm @@ -0,0 +1,44 @@ +//Used to create the gene mask. Shamelessly stolen from the plant controller and cut down. + +/client/proc/show_xenobio_genes() + set category = "Debug" + set name = "Show Xenobio Genes" + set desc = "Prints the round's plant xenobio masks." + + if(!holder) return + + if(!xenobio_controller || !xenobio_controller.gene_tag_masks) + usr << "Gene masks not set." + return + + for(var/mask in xenobio_controller.gene_tag_masks) + usr << "[mask]: [xenobio_controller.gene_tag_masks[mask]]" + +var/global/datum/controller/xenobio/xenobio_controller // Set in New(). + +/datum/controller/xenobio + + var/list/gene_tag_masks = list() // Gene obfuscation for delicious trial and error goodness. + +/datum/controller/xenobio/New() + if(xenobio_controller && xenobio_controller != src) + log_debug("Rebuilding xenobio controller.") + qdel(xenobio_controller) + xenobio_controller = src + setup() + + +/datum/controller/xenobio/proc/setup() + + var/list/used_masks = list() + var/list/xenobio_traits = ALL_XENO_GENES + while(xenobio_traits && xenobio_traits.len) + var/gene_tag = pick(xenobio_traits) + var/gene_mask = "[uppertext(num2hex(rand(0,255)))]" + + while(gene_mask in used_masks) + gene_mask = "[uppertext(num2hex(rand(0,255)))]" + + used_masks += gene_mask + xenobio_traits -= gene_tag + gene_tag_masks[gene_tag] = gene_mask \ No newline at end of file diff --git a/code/modules/xenobio2/machinery/core_extractor.dm b/code/modules/xenobio2/machinery/core_extractor.dm new file mode 100644 index 0000000000..818e3e6510 --- /dev/null +++ b/code/modules/xenobio2/machinery/core_extractor.dm @@ -0,0 +1,191 @@ +/* + Here lives the slime core extractor + This machine extracts slime cores at the cost of the slime itself. + To create more of these slimes, stick the slime core in the extractor. +*/ +/obj/machinery/slime/extractor + name = "Slime extractor" + desc = "A machine for cutting up slimes to get to their cores." + icon = 'icons/obj/xenoarchaeology.dmi' + icon_state = "scanner_0old" + density = 1 + anchored = 1 + circuit = /obj/item/weapon/circuitboard/slimeextractor + var/inuse + var/mob/living/simple_animal/xeno/slime/occupant = null + var/occupiedcolor = "#22FF22" + var/emptycolor = "#FF2222" + var/operatingcolor = "#FFFF22" + + +/obj/machinery/slime/extractor/New() + ..() + update_light_color() + circuit = new circuit(src) + component_parts = list() + component_parts += new /obj/item/weapon/stock_parts/manipulator(src) + component_parts += new /obj/item/weapon/stock_parts/manipulator(src) + component_parts += new /obj/item/weapon/stock_parts/matter_bin(src) + component_parts += new /obj/item/weapon/stock_parts/micro_laser(src) + component_parts += new /obj/item/weapon/stock_parts/micro_laser(src) + RefreshParts() + +/obj/machinery/slime/extractor/attackby(var/obj/item/W, var/mob/user) + + //Let's try to deconstruct first. + if(istype(W, /obj/item/weapon/screwdriver) && !inuse) + default_deconstruction_screwdriver(user, W) + return + + if(istype(W, /obj/item/weapon/crowbar)) + default_deconstruction_crowbar(user, W) + return + + if(panel_open) + user << "Close the panel first!" + + var/obj/item/weapon/grab/G = W + + if(!istype(G)) + return ..() + + if(G.state < 2) + user << "You need a better grip to do that!" + return + + move_into_extractor(user,G.affecting) + +/obj/machinery/slime/extractor/MouseDrop_T(mob/target, mob/user) + if(user.stat || user.restrained()) + return + move_into_extractor(user,target) + +/obj/machinery/slime/extractor/proc/move_into_extractor(var/mob/user,var/mob/living/victim) + + if(src.occupant) + user << "The core extractor is full, empty it first!" + return + + if(inuse) + user << "The core extractor is locked and running, wait for it to finish." + return + + if(!(istype(victim, /mob/living/simple_animal/xeno/slime)) ) + user << "This is not a suitable subject for the core extractor!" + return + + var/mob/living/simple_animal/xeno/slime/S = victim + if(S.is_child) + user << "This subject is not developed enough for the core extractor!" + return + + user.visible_message("[user] starts to put [victim] into the core extractor!") + src.add_fingerprint(user) + if(do_after(user, 30) && victim.Adjacent(src) && user.Adjacent(src) && victim.Adjacent(user) && !occupant) + user.visible_message("[user] stuffs [victim] into the core extractor!") + if(victim.client) + victim.client.perspective = EYE_PERSPECTIVE + victim.client.eye = src + victim.forceMove(src) + src.occupant = victim + update_light_color() + +/obj/machinery/slime/extractor/proc/update_light_color() + if(src.occupant && !(inuse)) + set_light(2, 2, occupiedcolor) + else if(src.occupant) + set_light(2, 2, operatingcolor) + else + set_light(2, 2, emptycolor) + +/obj/machinery/slime/extractor/proc/extract_cores() + if(!src.occupant) + src.visible_message("\icon[src] [src] pings unhappily.") + else if(inuse) + return + + inuse = 1 + update_light_color() + spawn(30) + icon_state = "scanner_1old" + for(var/i=1 to occupant.cores) + var/obj/item/xenoproduct/slime/core/C = new(src) + C.traits = occupant.traitdat + + C.create_reagents(C.traits.traits[TRAIT_XENO_CHEMVOL]) + for(var/reagent in occupant.traitdat.chems) + C.reagents.add_reagent(reagent, occupant.traitdat.chems[reagent]) + + C.color = C.traits.traits[TRAIT_XENO_COLOR] + if(occupant.traitdat.get_trait(TRAIT_XENO_BIOLUMESCENT)) + C.set_light(occupant.traitdat.get_trait(TRAIT_XENO_GLOW_STRENGTH),occupant.traitdat.get_trait(TRAIT_XENO_GLOW_RANGE), occupant.traitdat.get_trait(TRAIT_XENO_BIO_COLOR)) + + spawn(30) + icon_state = "scanner_0old" + qdel(occupant) + inuse = 0 + eject_contents() + update_light_color() + src.updateUsrDialog() + +/obj/machinery/slime/extractor/proc/eject_slime() + if(occupant) + occupant.forceMove(loc) + occupant = null + +/obj/machinery/slime/extractor/proc/eject_core() + for(var/obj/thing in (contents - component_parts - circuit)) + thing.forceMove(loc) + +/obj/machinery/slime/extractor/proc/eject_contents() + eject_core() + eject_slime() + +//Here lies the UI +/obj/machinery/slime/extractor/attack_hand(mob/user as mob) + user.set_machine(src) + interact(user) + +/obj/machinery/slime/extractor/interact(mob/user as mob) + var/dat = "" + if(!inuse) + dat = {" + Slime held:
+ [occupant]
+ "} + if (occupant && !(stat & (NOPOWER|BROKEN))) + dat += "Start the core extraction.
" + if(occupant) + dat += "Eject the slime
" + else + dat += "Please wait..." + var/datum/browser/popup = new(user, "Slime Extractor", "Slime Extractor", src) + popup.set_content(dat) + popup.open() + return + + +/obj/machinery/slime/extractor/Topic(href, href_list) + if(..()) + return + usr.set_machine(src) + switch(href_list["action"]) + if ("extract") + extract_cores() + if("eject") + eject_slime() + src.updateUsrDialog() + return + +//Circuit board below, +/obj/item/weapon/circuitboard/slimeextractor + name = T_BOARD("Slime extractor") + build_path = "/obj/machinery/slime/extractor" + board_type = "machine" + origin_tech = list(TECH_DATA = 3, TECH_BIO = 3) + req_components = list( + /obj/item/weapon/stock_parts/manipulator = 2, + /obj/item/weapon/stock_parts/matter_bin = 1, + /obj/item/weapon/stock_parts/micro_laser = 2 + ) + \ No newline at end of file diff --git a/code/modules/xenobio2/machinery/gene_manipulators.dm b/code/modules/xenobio2/machinery/gene_manipulators.dm new file mode 100644 index 0000000000..f5d124a9f1 --- /dev/null +++ b/code/modules/xenobio2/machinery/gene_manipulators.dm @@ -0,0 +1,429 @@ +/* + This file contains: + + Xenobiological disk: + Holds traits that can be taken from cores and transplanted into slimes. + + Biological Product Destructive Analyzer: + Takes certain traits in gene grouping from a core and places them into a disk. + + Biological genetic bombarder: + Takes traits from a disk and replaces/adds to the genes in a xenobiological creature. +*/ +/obj/item/weapon/disk/xenobio + name = "biological data disk" + desc = "A small disk used for carrying data on genetics." + icon = 'icons/obj/hydroponics_machines.dmi' + icon_state = "disk" + w_class = 1.0 + + var/list/genes = list() + var/genesource = "unknown" + +/obj/item/weapon/disk/xenobio/attack_self(var/mob/user as mob) + if(genes.len) + var/choice = alert(user, "Are you sure you want to wipe the disk?", "Xenobiological Data", "No", "Yes") + if(src && user && genes && choice && choice == "Yes" && user.Adjacent(get_turf(src))) + user << "You wipe the disk data." + name = initial(name) + desc = initial(name) + genes = list() + genesource = "unknown" + +/obj/item/weapon/storage/box/xenobiodisk + name = "biological disk box" + desc = "A box of biological data disks, apparently." + +/obj/item/weapon/storage/box/xenobiodisk/New() + ..() + for(var/i = 0 to 7) + new /obj/item/weapon/disk/xenobio(src) + +/obj/machinery/xenobio + density = 1 + anchored = 1 + use_power = 1 + + var/obj/item/weapon/disk/xenobio/loaded_disk //Currently loaded data disk. + + var/open = 0 + var/active = 0 + var/action_time = 5 + var/last_action = 0 + var/eject_disk = 0 + var/failed_task = 0 + var/disk_needs_genes = 0 + +/obj/machinery/xenobio/attack_ai(mob/user as mob) + return attack_hand(user) + +/obj/machinery/xenobio/attack_hand(mob/user as mob) + ui_interact(user) + +/obj/machinery/xenobio/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(default_deconstruction_screwdriver(user, W)) + return + if(default_deconstruction_crowbar(user, W)) + return + if(istype(W,/obj/item/weapon/disk/xenobio)) + if(loaded_disk) + user << "There is already a data disk loaded." + return + else + var/obj/item/weapon/disk/xenobio/B = W + + if(B.genes && B.genes.len) + if(!disk_needs_genes) + user << "That disk already has gene data loaded." + return + else + if(disk_needs_genes) + user << "That disk does not have any gene data loaded." + return + + user.drop_from_inventory(W) + W.forceMove(src) + loaded_disk = W + user << "You load [W] into [src]." + + return + ..() + +/obj/machinery/xenobio/process() + + ..() + if(!active) return + + if(world.time > last_action + action_time) + finished_task() + +/obj/machinery/xenobio/proc/finished_task() + active = 0 + if(failed_task) + failed_task = 0 + visible_message("\icon[src] [src] pings unhappily, flashing a red warning light.") + else + visible_message("\icon[src] [src] pings happily.") + + if(eject_disk) + eject_disk = 0 + if(loaded_disk) + loaded_disk.forceMove(get_turf(src)) + visible_message("\icon[src] [src] beeps and spits out [loaded_disk].") + loaded_disk = null + +/obj/machinery/xenobio/extractor + name = "biological product destructive analyzer" + icon = 'icons/obj/hydroponics_machines.dmi' + icon_state = "traitcopier" + circuit = /obj/item/weapon/circuitboard/bioproddestanalyzer + + var/obj/item/xenoproduct/product + var/datum/xeno/traits/genetics // Currently scanned xeno genetic structure. + var/degradation = 0 // Increments with each scan, stops allowing gene mods after a certain point. + +/obj/machinery/xenobio/extractor/New() + ..() + circuit = new circuit(src) + component_parts = list() + component_parts += new /obj/item/weapon/stock_parts/manipulator(src) + component_parts += new /obj/item/weapon/stock_parts/manipulator(src) + component_parts += new /obj/item/weapon/stock_parts/matter_bin(src) + component_parts += new /obj/item/weapon/stock_parts/scanning_module(src) + component_parts += new /obj/item/weapon/stock_parts/scanning_module(src) + component_parts += new /obj/item/weapon/stock_parts/scanning_module(src) + RefreshParts() + +/obj/machinery/xenobio/extractor/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W,/obj/item/xenoproduct)) + if(product) + user << "There is already a xenobiological product loaded." + return + else + var/obj/item/xenoproduct/B = W + user.drop_from_inventory(B) + B.forceMove(src) + product = B + user << "You load [B] into [src]." + + return + ..() + +/obj/machinery/xenobio/extractor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + if(!user) + return + + var/list/data = list() + + var/list/geneMasks[0] + for(var/gene_tag in xenobio_controller.gene_tag_masks) + geneMasks.Add(list(list("tag" = gene_tag, "mask" = xenobio_controller.gene_tag_masks[gene_tag]))) + data["geneMasks"] = geneMasks + + data["activity"] = active + data["degradation"] = degradation + + if(loaded_disk) + data["disk"] = 1 + else + data["disk"] = 0 + + if(product) + data["loaded"] = "[product.source] [product.product]" + else + data["loaded"] = 0 + + if(genetics) + data["hasGenetics"] = 1 + data["sourceName"] = genetics.source + else + data["hasGenetics"] = 0 + data["sourceName"] = 0 + + ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "xenobio_isolator.tmpl", "B.P.D. Analyzer UI", 470, 450) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/xenobio/proc/eject_disk() + if(!loaded_disk) return + loaded_disk.forceMove(loc) + visible_message("\icon[src] [src] beeps and spits out [loaded_disk].") + loaded_disk = null + +/obj/machinery/xenobio/extractor/Topic(href, href_list) + + if(..()) + return 1 + + if(href_list["eject_product"]) + if(!product) return + + product.forceMove(get_turf(src)) + visible_message("\icon[src] [src] beeps and spits out [product].") + product = null + + if(href_list["eject_disk"]) + eject_disk() + + if(href_list["scan_genome"]) + + if(!product) return + + last_action = world.time + active = 1 + + if(product && product.product) + genetics = product.traits + degradation = 0 + + qdel(product) + product = null + + if(href_list["get_gene"]) + + if(!genetics || !loaded_disk) return + + last_action = world.time + active = 1 + + var/datum/xeno/genes/G = genetics.get_gene(href_list["get_gene"]) + if(!G) return + loaded_disk.genes += G + + loaded_disk.genesource = "[genetics.source]" + + loaded_disk.name += " ([xenobio_controller.gene_tag_masks[href_list["get_gene"]]], [genetics.source])" + loaded_disk.desc += " The label reads \'gene [xenobio_controller.gene_tag_masks[href_list["get_gene"]]], sampled from [genetics.source]\'." + eject_disk = 1 + + degradation += rand(20,60) + if(degradation >= 100) + failed_task = 1 + genetics = null + degradation = 0 + + if(href_list["clear_buffer"]) + if(!genetics) return + genetics = null + degradation = 0 + + usr.set_machine(src) + src.add_fingerprint(usr) + + src.updateUsrDialog() + return + +/obj/machinery/xenobio/editor + name = "biological genetic bombarder" + icon = 'icons/obj/cryogenics.dmi' + icon_state = "cellold0" + disk_needs_genes = 1 + circuit = /obj/item/weapon/circuitboard/biobombarder + + var/mob/living/simple_animal/xeno/slime/occupant + +/obj/machinery/xenobio/editor/New() + ..() + circuit = new circuit(src) + component_parts = list() + component_parts += new /obj/item/weapon/stock_parts/manipulator(src) + component_parts += new /obj/item/weapon/stock_parts/manipulator(src) + component_parts += new /obj/item/weapon/stock_parts/matter_bin(src) + component_parts += new /obj/item/weapon/stock_parts/matter_bin(src) + component_parts += new /obj/item/weapon/stock_parts/scanning_module(src) + component_parts += new /obj/item/weapon/stock_parts/scanning_module(src) + RefreshParts() + +/obj/machinery/xenobio/editor/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W,/obj/item/weapon/grab)) + var/obj/item/weapon/grab/G = W + if(occupant) + user << "There is already an organism loaded." + return + else + if(isxeno(G.affecting)) + var/mob/living/simple_animal/xeno/X = G.affecting + if(do_after(user, 30) && X.Adjacent(src) && user.Adjacent(src) && X.Adjacent(user) && !occupant) + user.drop_from_inventory(G) + X.forceMove(src) + occupant = X + user << "You load [X] into [src]." + else + user << "This specimen is incompatible with the machinery!" + return + ..() + + +/obj/machinery/xenobio/editor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + + if(!user) + return + + var/list/data = list() + + data["activity"] = active + + if(occupant) + data["degradation"] = occupant.stability + else + data["degradation"] = 0 + + if(loaded_disk && loaded_disk.genes.len) + data["disk"] = 1 + data["sourceName"] = loaded_disk.genesource + data["locus"] = "" + + for(var/datum/xeno/genes/X in loaded_disk.genes) + if(data["locus"] != "") data["locus"] += ", " + data["locus"] += "[xenobio_controller.gene_tag_masks[X.genetype]]" + + else + data["disk"] = 0 + data["sourceName"] = 0 + data["locus"] = 0 + + if(occupant) + data["loaded"] = "[occupant]" + else + data["loaded"] = 0 + + ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "xenobio_editor.tmpl", "Biological Genetic Bombarder UI", 470, 450) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/xenobio/editor/Topic(href, href_list) + + if(..()) + return 1 + + if(href_list["apply_gene"]) + if(!loaded_disk || !occupant) return + + last_action = world.time + active = 1 + occupant.nameVar = "modified" + + if(prob(occupant.stability)) + failed_task = 1 + occupant.stability = 101 + + for(var/datum/xeno/genes/gene in loaded_disk.genes) + occupant.traitdat.apply_gene(gene) + occupant.stability += rand(5,10) + occupant.ProcessTraits() + + if(href_list["eject_disk"]) + eject_disk() + + if(href_list["eject_xeno"]) + eject_xeno() + + usr.set_machine(src) + src.add_fingerprint(usr) + +/obj/machinery/xenobio/editor/MouseDrop_T(mob/target, mob/user) + if(user.stat || user.restrained()) + return + move_into_editor(user,target) + +/obj/machinery/xenobio/editor/proc/move_into_editor(var/mob/user,var/mob/living/victim) + + if(src.occupant) + user << "The biological genetic bombarder is full, empty it first!" + return + + if(in_use) + user << "The biological genetic bombarder is locked and running, wait for it to finish." + return + + if(!(istype(victim, /mob/living/simple_animal/xeno/slime)) ) + user << "This is not a suitable subject for the biological genetic bombarder!" + return + + user.visible_message("[user] starts to put [victim] into the biological genetic bombarder!") + src.add_fingerprint(user) + if(do_after(user, 30) && victim.Adjacent(src) && user.Adjacent(src) && victim.Adjacent(user) && !occupant) + user.visible_message("[user] stuffs [victim] into the biological genetic bombarder!") + if(victim.client) + victim.client.perspective = EYE_PERSPECTIVE + victim.client.eye = src + victim.forceMove(src) + occupant = victim + +/obj/machinery/xenobio/editor/proc/eject_contents() + eject_disk() + eject_xeno() + +/obj/machinery/xenobio/editor/proc/eject_xeno() + if(occupant) + occupant.forceMove(loc) + occupant = null + +/obj/item/weapon/circuitboard/bioproddestanalyzer + name = T_BOARD("biological product destructive analyzer") + build_path = "/obj/machinery/xenobio/extractor" + board_type = "machine" + origin_tech = list(TECH_DATA = 4, TECH_BIO = 4) + req_components = list( + /obj/item/weapon/stock_parts/manipulator = 2, + /obj/item/weapon/stock_parts/matter_bin = 1, + /obj/item/weapon/stock_parts/scanning_module = 3 + ) + +/obj/item/weapon/circuitboard/biobombarder + name = T_BOARD("biological genetic bombarder") + build_path = "/obj/machinery/xenobio/editor" + board_type = "machine" + origin_tech = list(TECH_DATA = 4, TECH_BIO = 4) + req_components = list( + /obj/item/weapon/stock_parts/manipulator = 2, + /obj/item/weapon/stock_parts/matter_bin = 2, + /obj/item/weapon/stock_parts/scanning_module = 2 + ) + \ No newline at end of file diff --git a/code/modules/xenobio2/machinery/injector.dm b/code/modules/xenobio2/machinery/injector.dm new file mode 100644 index 0000000000..a3f88825c5 --- /dev/null +++ b/code/modules/xenobio2/machinery/injector.dm @@ -0,0 +1,145 @@ +/* + This file contains: + + Manual Injector: + Manually injects chemicals into a xenobiological creature from a linked machine. + +*/ +/obj/machinery/xenobio2/manualinjector + name = "biological injector" + desc = "Injects biological organisms that are inserted with the contents of an inserted beaker at the command of a remote computer." + density = 1 + anchored = 1 + use_power = 1 + icon = 'icons/obj/biogenerator.dmi' + icon_state = "biogen-work" + var/mob/living/occupant + var/obj/item/weapon/reagent_containers/glass/beaker + var/obj/machinery/computer/xenobio2/computer + + circuit = /obj/item/weapon/circuitboard/xenobioinjectormachine + +/obj/machinery/xenobio2/manualinjector/New() + ..() + var/datum/reagents/R = new/datum/reagents(1000) + reagents = R + R.my_atom = src + beaker = new /obj/item/weapon/reagent_containers/glass/beaker(src) + circuit = new circuit(src) + component_parts = list() + component_parts += new /obj/item/weapon/stock_parts/matter_bin(src) + component_parts += new /obj/item/weapon/stock_parts/matter_bin(src) + component_parts += new /obj/item/weapon/stock_parts/manipulator(src) + component_parts += new /obj/item/weapon/stock_parts/manipulator(src) + RefreshParts() + +/obj/machinery/xenobio2/manualinjector/update_icon() + if(beaker) + if(occupant) + icon_state = "biogen-stand" + else + icon_state = "biogen-work" + else + icon_state = "biogen-empty" + +/obj/machinery/xenobio2/manualinjector/MouseDrop_T(mob/target, mob/user) + if(user.stat || user.restrained()) + return + move_into_injector(user,target) + +/obj/machinery/xenobio2/manualinjector/proc/move_into_injector(var/mob/user,var/mob/living/victim) + if(src.occupant) + user << "The injector is full, empty it first!" + return + + if(!(istype(victim, /mob/living/simple_animal/xeno)) && !emagged) + user << "This is not a suitable subject for the injector!" + return + + user.visible_message("[user] starts to put [victim] into the injector!") + src.add_fingerprint(user) + if(do_after(user, 30) && victim.Adjacent(src) && user.Adjacent(src) && victim.Adjacent(user) && !occupant) + user.visible_message("[user] stuffs [victim] into the injector!") + if(victim.client) + victim.client.perspective = EYE_PERSPECTIVE + victim.client.eye = src + victim.forceMove(src) + src.occupant = victim + +/obj/machinery/xenobio2/manualinjector/proc/eject_contents() + for(var/obj/thing in (contents - component_parts - circuit - beaker)) + thing.forceMove(loc) + if(occupant) + occupant.forceMove(loc) + occupant = null + return + +/obj/machinery/xenobio2/manualinjector/proc/eject_beaker() + if(beaker) + var/obj/item/weapon/reagent_containers/glass/beaker/B = beaker + B.loc = loc + beaker = null + return + +/obj/machinery/xenobio2/manualinjector/proc/inject_reagents() + if(!occupant) + return + if(isxeno(occupant)) + var/mob/living/simple_animal/xeno/X = occupant + beaker.reagents.trans_to_holder(X.reagents, computer.transfer_amount, 1, 0) + else + beaker.reagents.trans_to_mob(occupant, computer.transfer_amount) + +/obj/machinery/xenobio2/manualinjector/attackby(var/obj/item/W, var/mob/user) + + //Let's try to deconstruct first. + if(istype(W, /obj/item/weapon/screwdriver)) + default_deconstruction_screwdriver(user, W) + return + + if(istype(W, /obj/item/weapon/crowbar) && !occupant) + default_deconstruction_crowbar(user, W) + return + + //are you smashing a beaker in me? Well then insert that shit! + if(istype(W, /obj/item/weapon/reagent_containers/glass/beaker)) + beaker = W + user.drop_from_inventory(W) + W.loc = src + return + + //Did you want to link it? + if(istype(W, /obj/item/device/multitool)) + var/obj/item/device/multitool/P = W + if(P.connectable) + if(istype(P.connectable, /obj/machinery/computer/xenobio2)) + var/obj/machinery/computer/xenobio2/C = P.connectable + computer = C + C.injector = src + user << " You link the [src] to the [P.connectable]!" + else + user << " You store the [src] in the [P]'s buffer!" + P.connectable = src + return + + if(panel_open) + user << "Close the panel first!" + + var/obj/item/weapon/grab/G = W + + if(!istype(G)) + return ..() + + if(G.state < 2) + user << "You need a better grip to do that!" + return + + move_into_injector(user,G.affecting) + + +/obj/item/weapon/circuitboard/xenobioinjectormachine + name = T_BOARD("biological injector") + build_path = "/obj/machinery/xenobio2/manualinjector" + board_type = "machine" + origin_tech = list() //To be filled, + req_components = list() //To be filled, \ No newline at end of file diff --git a/code/modules/xenobio2/machinery/injector_computer.dm b/code/modules/xenobio2/machinery/injector_computer.dm new file mode 100644 index 0000000000..d39f791cb7 --- /dev/null +++ b/code/modules/xenobio2/machinery/injector_computer.dm @@ -0,0 +1,113 @@ +/* + This file contains: + + Manual Injector: + Manually injects chemicals into a xenobiological creature from a linked machine. + +*/ +/obj/machinery/computer/xenobio2 + name = "injector control console" + desc = "Used to control mechanized biological injectors." + icon_keyboard = "med_key" + icon_screen = "dna" + light_color = "#315ab4" + use_power = 1 + idle_power_usage = 250 + active_power_usage = 500 + circuit = /obj/item/weapon/circuitboard/xenobio2computer + var/obj/machinery/xenobio2/manualinjector/injector + var/transfer_amount + var/active + +/obj/machinery/computer/xenobio2/Destroy() + ..() + injector.computer = null + +/obj/machinery/computer/xenobio2/attack_hand(mob/user) + if(..()) + return 1 + ui_interact(user) + +/obj/machinery/computer/xenobio2/attackby(var/obj/item/W, var/mob/user) + + //Did you want to link it? + if(istype(W, /obj/item/device/multitool)) + var/obj/item/device/multitool/P = W + if(P.connectable) + if(istype(P.connectable, /obj/machinery/xenobio2/manualinjector)) + var/obj/machinery/xenobio2/manualinjector/I = P.connectable + injector = I + I.computer = src + user << " You link the [src] to the [P.connectable]!" + else + user << " You store the [src] in the [P]'s buffer!" + P.connectable = src + return + + ..() + +/obj/machinery/computer/xenobio2/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + if(!user) + return + if(!injector) + return + + var/list/data = list() + + data["activity"] = active + data["beaker"] = injector.beaker + if(injector.occupant) + data["occupied"] = 1 + if(isxeno(injector.occupant)) + var/mob/living/simple_animal/xeno/X = injector.occupant + data["instability"] = (X.mut_level / X.mut_max) * 100 + else + data["instability"] = null + + if(injector.beaker) + data["reagentAmount"] = injector.beaker.reagents.total_volume + data["reagentMax"] = injector.beaker.reagents.maximum_volume + data["reagentMin"] = 0 + else + data["reagentAmount"] = null + data["reagentMax"] = 1 + data["reagentMin"] = 0 + + if(injector.occupant) + data["occupantHealth"] = injector.occupant.health + data["occupantHealthMax"] = injector.occupant.maxHealth + else + data["occupantHealth"] = null + data["occupantHealthMax"] = null + + ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "xenobio_computer.tmpl", "Injector Control Console UI", 470, 450) + ui.set_initial_data(data) + ui.open() + ui.set_auto_update(1) + +/obj/machinery/computer/xenobio2/Topic(href, href_list) + + if(..()) + return 1 + + if(href_list["inject_target"]) + active = 1 + spawn(5) + injector.inject_reagents() + active = 0 + if(href_list["eject_occupant"]) + injector.eject_contents() + + if(href_list["eject_beaker"]) + injector.eject_beaker() + + usr.set_machine(src) + src.add_fingerprint(usr) + +/obj/item/weapon/circuitboard/xenobio2computer + name = T_BOARD("injector control console") + build_path = "/obj/item/weapon/circuitboard/xenobio2computer" + board_type = "computer" + origin_tech = list() //To be filled, diff --git a/code/modules/xenobio2/machinery/slime_replicator.dm b/code/modules/xenobio2/machinery/slime_replicator.dm new file mode 100644 index 0000000000..77b70bc3b8 --- /dev/null +++ b/code/modules/xenobio2/machinery/slime_replicator.dm @@ -0,0 +1,147 @@ +/* + Here lives the slime replicator + This machine consumes cores to create a slime. + To create more of these cores, stick the slime core in the extractor. +*/ +/obj/machinery/slime/replicator + name = "slime core growth apparatus" + desc = "A machine for creating slimes from cores. Amazing!" + icon = 'icons/obj/xenoarchaeology.dmi' + icon_state = "restruct_0" + density = 1 + anchored = 1 + circuit = /obj/item/weapon/circuitboard/slimereplicator + var/obj/item/xenoproduct/slime/core/core = null + var/inuse + var/occupiedcolor = "#22FF22" + var/emptycolor = "#FF2222" + var/operatingcolor = "#FFFF22" + +/obj/machinery/slime/replicator/New() + ..() + circuit = new circuit(src) + component_parts = list() + component_parts += new /obj/item/weapon/stock_parts/manipulator(src) + component_parts += new /obj/item/weapon/stock_parts/manipulator(src) + component_parts += new /obj/item/weapon/stock_parts/matter_bin(src) + component_parts += new /obj/item/weapon/stock_parts/micro_laser(src) + RefreshParts() + update_light_color() + + +/obj/machinery/slime/replicator/attackby(var/obj/item/W, var/mob/user) + //Let's try to deconstruct first. + if(istype(W, /obj/item/weapon/screwdriver) && !inuse) + default_deconstruction_screwdriver(user, W) + return + + if(istype(W, /obj/item/weapon/crowbar)) + default_deconstruction_crowbar(user, W) + return + + var/obj/item/xenoproduct/slime/core/G = W + + if(!istype(G)) + return ..() + + if(core) + user << "[src] is already filled!" + return + if(panel_open) + user << "Close the panel first!" + core = G + user.drop_from_inventory(G) + G.forceMove(src) + update_light_color() + +/obj/machinery/slime/replicator/proc/update_light_color() + if(src.core && !(inuse)) + set_light(2, 2, occupiedcolor) + else if(src.core) + set_light(2, 2, operatingcolor) + else + set_light(2, 2, emptycolor) + +/obj/machinery/slime/replicator/proc/replicate_slime() + if(!src.core) + src.visible_message("\icon[src] [src] pings unhappily.") + else if(inuse) + return + + inuse = 1 + update_light_color() + icon_state = "restruct_1" + spawn(30) + var/mob/living/simple_animal/xeno/slime/S = new(src) + S.traitdat = core.traits + S.ProcessTraits() + qdel(core) + spawn(30) + inuse = 0 + eject_slime() + icon_state = "restruct_0" + update_light_color() + src.updateUsrDialog() + +/obj/machinery/slime/replicator/proc/eject_slime() + for(var/mob/thing in contents) + thing.forceMove(loc) + +/obj/machinery/slime/replicator/proc/eject_core() + if(core) + core.forceMove(loc) + core = null + +/obj/machinery/slime/replicator/proc/eject_contents() + eject_slime() + eject_core() + +//Here lies the UI +/obj/machinery/slime/replicator/attack_hand(mob/user as mob) + user.set_machine(src) + interact(user) + +/obj/machinery/slime/replicator/interact(mob/user as mob) + var/dat = "" + if(!inuse) + dat = {" + Slime core container holds:
+ [core]
+ "} + if (core && !(stat & (NOPOWER|BROKEN))) + dat += "Start the replication process
" + if(core) + dat += "Eject the core
" + else + dat += "Please wait..." + var/datum/browser/popup = new(user, "Slime Replicator", "Slime Replicator", src) + popup.set_content(dat) + popup.open() + return + + +/obj/machinery/slime/replicator/Topic(href, href_list) + if(..()) + return + usr.set_machine(src) + switch(href_list["action"]) + if ("replicate") + replicate_slime() + if("eject") + eject_core() + src.updateUsrDialog() + return + +//Circuit board below, +/obj/item/weapon/circuitboard/slimereplicator + name = T_BOARD("Slime replicator") + build_path = "/obj/machinery/slime/replicator" + board_type = "machine" + origin_tech = list(TECH_DATA = 3, TECH_BIO = 3) + req_components = list( + /obj/item/weapon/stock_parts/manipulator = 2, + /obj/item/weapon/stock_parts/matter_bin = 1, + /obj/item/weapon/stock_parts/micro_laser = 1 + ) + + \ No newline at end of file diff --git a/code/modules/xenobio2/mob/slime/slime life.dm b/code/modules/xenobio2/mob/slime/slime life.dm new file mode 100644 index 0000000000..4853454476 --- /dev/null +++ b/code/modules/xenobio2/mob/slime/slime life.dm @@ -0,0 +1,55 @@ +/* +Slime specific life events go here. +*/ +#define HAPPYLEVEL 200 +#define ANGRYLEVEL 10 +/mob/living/simple_animal/xeno/slime/Life() + . = ..() + if(..()) + if(health) + if(is_child) + if(nutrition >= 275) + growthcounter++ + nutrition -= hunger_factor + if(nutrition <= 75) + growthcounter-- + if(growthcounter >= growthpoint) + src.GrowUp() + + else + if(nutrition < 0) + nutrition = 0 + if((prob(10) && !emote_on)) //Slimes might display their food-based emotions over time. + var/image/I = new(src.icon) + I.color = "#FFFFFF" + I.layer = src.layer + 0.2 + if((nutrition >= HAPPYLEVEL)) + if((nutrition >= 1.5 * HAPPYLEVEL)) + I.icon_state = "aslime-:33" + else + I.icon_state = "aslime-:3" + + else if((nutrition > ANGRYLEVEL)) + if((nutrition >= 10 * ANGRYLEVEL)) + I.icon_state = "aslime-pout" + else if((nutrition >= 5 * ANGRYLEVEL)) + I.icon_state = "aslime-sad" + else + I.icon_state = "aslime-angry" + overlays += I + emote_on = 1 + spawn(30) + GenerateAdultIcon() + emote_on = null + + else + if(is_child) + icon_state = "slime baby dead" + else + overlays.Cut() + icon_state = "slime adult dead" + color = traitdat.traits[TRAIT_XENO_COLOR] + + return 0 //Everything worked okay + + return //xeno/Life() returned 0. \ No newline at end of file diff --git a/code/modules/xenobio2/mob/slime/slime procs.dm b/code/modules/xenobio2/mob/slime/slime procs.dm new file mode 100644 index 0000000000..56ad5d6050 --- /dev/null +++ b/code/modules/xenobio2/mob/slime/slime procs.dm @@ -0,0 +1,114 @@ +/* +Slime specific procs go here. +*/ +#define SHINYOVERLAY 0 +#define LIGHTOVERLAY 1 +#define MAXOVERLAY 2 //Should be 1 + last overlay, to give the chance for matte slimes + +/mob/living/simple_animal/xeno/slime/RandomizeTraits() + traitdat.traits[TRAIT_XENO_COLDRES] = rand(30,270) + traitdat.traits[TRAIT_XENO_HEATRES] = rand(30,270) + traitdat.traits[TRAIT_XENO_CHEMVOL] = round(rand(20,40)) //Wow, a slime core with the capacity to hold 2/3rd's a beaker's worth of chemicals. + traitdat.traits[TRAIT_XENO_HEALTH] = round(rand(50, 75)) + traitdat.traits[TRAIT_XENO_HUNGER] = rand(1, 20) + traitdat.traits[TRAIT_XENO_STARVEDAMAGE] = rand(1, 4) + traitdat.traits[TRAIT_XENO_EATS] = prob(95) //Odds are, that thing'll need to eat. + traitdat.traits[TRAIT_XENO_CHROMATIC] = prob(5) + if(traitdat.traits[TRAIT_XENO_CHROMATIC]) + traitdat.traits[TRAIT_XENO_HOSTILE] = 0 + else + traitdat.traits[TRAIT_XENO_HOSTILE] = prob(30) + traitdat.traits[TRAIT_XENO_GLOW_STRENGTH] = round(rand(1,3)) + traitdat.traits[TRAIT_XENO_GLOW_RANGE] = round(rand(1,3)) + traitdat.traits[TRAIT_XENO_STRENGTH] = round(rand(4,9)) + traitdat.traits[TRAIT_XENO_STR_RANGE] =round(rand(0,2)) + traitdat.traits[TRAIT_XENO_CANLEARN] = prob(68) + traitdat.traits[TRAIT_XENO_SPEED] = round(rand(-10,10)) + + + +/mob/living/simple_animal/xeno/slime/proc/GrowUp() + GenerateAdult() + + maxHealth = traitdat.get_trait(TRAIT_XENO_HEALTH) + health = maxHealth + is_child = 0 + + return 1 + +/mob/living/simple_animal/xeno/slime/Mutate() + ..() + cores = round(rand(1,9)) + if(is_child) + RandomizeTraits() + GenerateChild() + else + GenerateAdult() + +/mob/living/simple_animal/xeno/slime/proc/GenerateChild() + overlays.Cut() + name = "[nameVar] baby slime" + real_name = "[nameVar] baby slime" + desc = "A shifting blob of [nameVar] goo." + icon_state = "slime baby" + icon_living = "slime baby" + icon_dead = "slime baby dead" + color = traitdat.traits[TRAIT_XENO_COLOR] + maxHealth = traitdat.traits[TRAIT_XENO_HEALTH]/2 + health = maxHealth + + return 1 + +/mob/living/simple_animal/xeno/slime/proc/GenerateAdult() + overlays.Cut() + name = "[nameVar] slime" + real_name = "[nameVar] slime" + desc = "A shifting mass of [nameVar] goo." + color = "" + icon_state = "" + overlay = round(rand(0, MAXOVERLAY)) + GenerateAdultIcon() + +/mob/living/simple_animal/xeno/slime/proc/GenerateAdultIcon() //Hack and slash adventure game to make slimes have no color on light effects later + overlays.Cut() + var/image/Img = new(src.icon) + Img.icon_state = "slime adult" + Img.color = traitdat.traits[TRAIT_XENO_COLOR] + Img.layer = src.layer + overlays += Img + + switch(overlay) + if(SHINYOVERLAY) + var/image/I = new(src.icon) + I.icon = src.icon + I.icon_state = "slime shiny" + I.layer = src.layer + 0.1 + I.color = "#FFFFFF" + overlays += I + if(LIGHTOVERLAY) + var/image/I = new(src.icon) + I.icon = src.icon + I.icon_state = "" + I.icon_state = "slime light" + I.layer = src.layer + 0.1 + I.color = "#FFFFFF" + overlays += I + +/mob/living/simple_animal/xeno/slime/handle_reagents() + if(!stasis) + if(!reagents) + return + if(reagents.total_volume <= 0) + return + if(reagents.has_reagent("docilitytoxin")) //Toxin that makes them docile? Good for quelling angry mobs. + hostile = 0 + traitdat.traits[TRAIT_XENO_HOSTILE] = 0 + ..() + +/mob/living/simple_animal/xeno/slime/ProcessTraits() + ..() + if(is_child) + GenerateChild() + else + GenerateAdult() + \ No newline at end of file diff --git a/code/modules/xenobio2/mob/slime/slime.dm b/code/modules/xenobio2/mob/slime/slime.dm new file mode 100644 index 0000000000..8ef1efb5cc --- /dev/null +++ b/code/modules/xenobio2/mob/slime/slime.dm @@ -0,0 +1,92 @@ +/* +Slime definitions, Life and New live here. +*/ +/mob/living/simple_animal/xeno/slime //Adult values are found here + nameVar = "grey" //When mutated, nameVar might change. + desc = "A shifting, mass of goo." + speak_emote = list("garbles", "chirps", "blurbles") + colored = 1 + color = "#CACACA" + icon = 'icons/mob/slime2.dmi' + icon_state = "slime adult" + icon_living = "slime adult" + icon_dead = "slime adult dead" + internal_vol = 200 + mut_max = 200 + mutable = COLORMUT + var/is_child = 1 + var/cores = 3 + var/growthcounter = 0 + var/growthpoint = 150 //At what point they grow up. + var/shiny = 0 + move_to_delay = 17 //Slimes shouldn't be able to go faster than humans. + default_chems = list("slimejelly" = 5) + attacktext = "absorbed some of" + response_help = "pats" + response_disarm = "tries to stop" + response_harm = "hits" + + var/emote_on = null + + maleable = MAX_MALEABLE + + //Slimes can speak all of the languages, oh no! + universal_speak = 1 + speak_chance = 1 + speak = list("Hello?", + "Where is this going?", + "What is that?", + "What is in the box?", + "Cargo.", + "Transport?", + "Special?", + "Slime?") + + //Overlay information + var/overlay = 1 // 1 = normal lighting, 0 = shiny, 2 = too shiny, -1 = no overlay + + chemreact = list( "nutriment" = list("nutr" = 0.5), + "radium" = list("toxic" = 0.3, "mut" = 1), + "mutagen" = list("nutr" = 0.4, "mut" = 2), + "water" = list("nutr" = -0.1), + "milk" = list("nutr" = 0.3), + "sacid" = list("toxic" = 1), + "pacid" = list("toxic" = 2), + "chlorine" = list("toxic" = 0.5), + "ammonia" = list("toxic" = 0.5), + "sodawater" = list("toxic" = 0.1, "nutr" = -0.1), + "beer" = list("nutr" = 0.6), + "diethylamine" = list("nutr" = 0.9), + "sugar" = list("toxic" = 0.4, "nutr" = 0.2), + "eznutrient" = list("nutr" = 0.8), + "cryoxadone" = list("toxic" = 0.4), + "flourine" = list("toxic" = 0.1), + "robustharvest" = list("nutr" = 1.5), + "glucose" = list("nutr" = 0.5), + "blood" = list("nutr" = 0.75, "toxic" = 0.05, "mut" = 0.45), + "fuel" = list("toxic" = 0.4), + "toxin" = list("toxic" = 0.5), + "carpotoxin" = list("toxic" = 1, "mut" = 1.5), + "phoron" = list("toxic" = 1.5, "mut" = 0.03), + "cyanide" = list("toxic" = 3.5), + "slimejelly" = list("nutr" = 0.5), + "amutationtoxin" = list("toxic" = 0.1, "heal" = 1.5, "mut" = 3), + "mutationtoxin" = list("toxic" = 0.1, "heal" = 1, "mut" = 1.5), + "gold" = list("heal" = 0.3, "nutr" = 0.7, "mut" = 0.3), + "uranium" = list("heal" = 0.3, "toxic" = 0.7, "mut" = 1.2), + "glycerol" = list("nutr" = 0.6), + "woodpulp" = list("heal" = 0.1, "nutr" = 0.7), + "docilitytoxin" = list("nutr" = 0.3) ) + +/mob/living/simple_animal/xeno/slime/New() + ..() + for(var/datum/language/L in (typesof(/datum/language) - /datum/language)) + languages += L + speak += "[station_name()]?" + traitdat.source = "Slime" + resistances[BURN] = 4 + resistances[BRUTE] = 0.2 + resistances[TOX] = 1.5 + GenerateChild() + return 1 + \ No newline at end of file diff --git a/code/modules/xenobio2/mob/slime/slime_core.dm b/code/modules/xenobio2/mob/slime/slime_core.dm new file mode 100644 index 0000000000..fff19a231f --- /dev/null +++ b/code/modules/xenobio2/mob/slime/slime_core.dm @@ -0,0 +1,12 @@ +/* +Slime core lives here. +*/ +/obj/item/xenoproduct/slime/core + name = "slime core" + desc = "Gooey." + icon = 'icons/mob/slime2.dmi' + icon_state = "slime extract" + source = "Slime" + product = "core" + + \ No newline at end of file diff --git a/code/modules/xenobio2/mob/slime/slime_monkey.dm b/code/modules/xenobio2/mob/slime/slime_monkey.dm new file mode 100644 index 0000000000..f302f9104a --- /dev/null +++ b/code/modules/xenobio2/mob/slime/slime_monkey.dm @@ -0,0 +1,65 @@ +/* +Slime cube lives here. +*/ +/obj/item/slime_cube + name = "slimy monkey cube" + desc = "Wonder what might come out of this." + icon = 'icons/mob/slime2.dmi' + icon_state = "slime cube" + var/searching = 0 + +/obj/item/slime_cube/attack_self(mob/user as mob) + if(!searching) + user << "You stare at the slimy cube, watching as some activity occurs." + icon_state = "slime cube active" + searching = 1 + request_player() + spawn(600) reset_search() + +/obj/item/slime_cube/proc/request_player() + for(var/mob/observer/dead/O in player_list) + if(!O.MayRespawn()) + continue + if(O.client) + if(O.client.prefs.be_special & BE_ALIEN) + question(O.client) + +/obj/item/slime_cube/proc/question(var/client/C) + spawn(0) + if(!C) return + var/response = alert(C, "Someone is requesting a soul for a promethean. Would you like to play as one?", "Promethean request", "Yes", "No", "Never for this round") + if(response == "Yes") + response = alert(C, "Are you sure you want to play as a promethean?", "Promethean request", "Yes", "No") + if(!C || 2 == searching) return //handle logouts that happen whilst the alert is waiting for a response, and responses issued after a brain has been located. + if(response == "Yes") + transfer_personality(C.mob) + else if (response == "Never for this round") + C.prefs.be_special ^= BE_ALIEN + +/obj/item/slime_cube/proc/reset_search() //We give the players sixty seconds to decide, then reset the timer. + icon_state = "slime cube" + if(searching == 1) + searching = 0 + var/turf/T = get_turf_or_move(src.loc) + for (var/mob/M in viewers(T)) + M.show_message("The activity in the cube dies down. Maybe it will spark another time.") + +/obj/item/slime_cube/proc/transfer_personality(var/mob/candidate) + announce_ghost_joinleave(candidate, 0, "They are a promethean now.") + src.searching = 2 + var/mob/living/carbon/human/S = new(get_turf(src)) + S.client = candidate.client + S. << "You are a promethean, brought into existence on [station_name()]." + S.mind.assigned_role = "Promethean" + S.set_species("Promethean") + S.shapeshifter_set_colour("#05FF9B") + for(var/mob/M in viewers(get_turf_or_move(loc))) + M.show_message("The monkey cube suddenly takes the shape of a humanoid!") + var/newname = sanitize(input(S, "You are a Promethean. Would you like to change your name to something else?", "Name change") as null|text, MAX_NAME_LEN) + if (newname) + S.real_name = newname + S.name = S.real_name + S.dna.real_name = newname + if(S.mind) S.mind.name = S.name + qdel(src) + \ No newline at end of file diff --git a/code/modules/xenobio2/mob/xeno procs.dm b/code/modules/xenobio2/mob/xeno procs.dm new file mode 100644 index 0000000000..4684d9d9d1 --- /dev/null +++ b/code/modules/xenobio2/mob/xeno procs.dm @@ -0,0 +1,168 @@ +/* +Basic definition of creatures for Xenobiology + +Includes: +Proc for metabolism +Proc for mutating +Procs for copying speech, if applicable +Procs for targeting +*/ +/mob/living/simple_animal/xeno/proc/ProcessTraits() + if(maleable >= MAX_MALEABLE) + maxHealth = traitdat.get_trait(TRAIT_XENO_HEALTH) + health = maxHealth + if(traitdat.chemlist.len) //Let's make sure that this has a length. + chemreact = traitdat.chemlist + else + traitdat.chemlist = chemreact + chromatic = traitdat.traits[TRAIT_XENO_CHROMATIC] + if(maleable >= MINOR_MALEABLE) + if(colored) + color = traitdat.traits[TRAIT_XENO_COLOR] + speed = traitdat.traits[TRAIT_XENO_SPEED] + hunger_factor = traitdat.traits[TRAIT_XENO_HUNGER] + starve_damage = traitdat.traits[TRAIT_XENO_STARVEDAMAGE] + minbodytemp = T20C - traitdat.traits[TRAIT_XENO_COLDRES] + maxbodytemp = T20C + traitdat.traits[TRAIT_XENO_HEATRES] + + if(traitdat.traits[TRAIT_XENO_BIOLUMESCENT]) + set_light(traitdat.traits[TRAIT_XENO_GLOW_RANGE], traitdat.traits[TRAIT_XENO_GLOW_STRENGTH], traitdat.traits[TRAIT_XENO_BIO_COLOR]) + else + set_light(0, 0, "#000000") //Should kill any light that shouldn't be there. + if(!(chromatic)) + hostile = 0 //No. No laser-reflecting hostile creatures. Bad. + else + hostile = traitdat.traits[TRAIT_XENO_HOSTILE] + + speed = traitdat.traits[TRAIT_XENO_SPEED] + + if(traitdat.traits[TRAIT_XENO_CANSPEAK]) + speak_chance = traitdat.traits[TRAIT_XENO_SPEAKCHANCE] + else + speak_chance = 0 + + melee_damage_lower = traitdat.get_trait(TRAIT_XENO_STRENGTH) - traitdat.get_trait(TRAIT_XENO_STR_RANGE) + melee_damage_upper = traitdat.traits[TRAIT_XENO_STRENGTH] + traitdat.get_trait(TRAIT_XENO_STR_RANGE) + + + +//Metabolism proc, simplified for xenos. Heavily based on botanical metabolism. +/mob/living/simple_animal/xeno/proc/handle_reagents() + if(!stasis) + if(!reagents) + return + if(reagents.total_volume <= 0) + return + + //Let's handle some chemical smoke, for scientific smoke bomb purposes. + for(var/obj/effect/effect/smoke/chem/smoke in view(1, src)) + if(smoke.reagents.total_volume) + smoke.reagents.trans_to_mob(src, 10, CHEM_BLOOD, copy = 1) + + reagents.trans_to_obj(temp_chem_holder, min(reagents.total_volume,rand(1,4))) + var/reagent_total + var/list/reagent_response = list() + for(var/datum/reagent/R in temp_chem_holder.reagents.reagent_list) + + reagent_total = temp_chem_holder.reagents.get_reagent_amount(R.id) + + reagent_response = chemreact[R.id] + + if(reagent_response["toxic"]) + adjustToxLoss(reagent_response["toxic"] * reagent_total) + + if(reagent_response["heal"]) + heal_overall_damage(reagent_response["heal"] * reagent_total) + + if(reagent_response["nutr"]) + nutrition += reagent_response["nutr"] * reagent_total + + if(reagent_response["mut"]) + mut_level += reagent_response["mut"] * reagent_total + + temp_chem_holder.reagents.clear_reagents() + + return 1 //Everything worked out okay. + + return 0 + +/mob/living/simple_animal/xeno/proc/Mutate() + nameVar = "mutated" + if((COLORMUT & mutable)) + traitdat.traits[TRAIT_XENO_COLOR] = "#" + for(var/i=0, i<6, i++) + traitdat.traits[TRAIT_XENO_COLOR] += pick(hexNums) + traitdat.traits[TRAIT_XENO_BIO_COLOR] = "#" + for(var/i=0, i<6, i++) + traitdat.traits[TRAIT_XENO_BIO_COLOR] += pick(hexNums) + + RandomChemicals() + //if(SPECIESMUT & mutable) + //Placeholder, currently no xenos that have species mutations. + RandomizeTraits() + ProcessTraits() + return 1 + +/mob/living/simple_animal/xeno/proc/RandomizeTraits() + return + +/mob/living/simple_animal/xeno/hear_say(var/message, var/verb = "says", var/datum/language/language, var/alt_name = "",var/italics = 0, var/mob/speaker = null) + if(traitdat.traits[TRAIT_XENO_CANLEARN]) + /* + Until this gets sorted out to a functioning point, or waiting on Psi's saycode update. + var/learned_message = say_understands(speaker, language) + if(!message || isxeno(speaker)) + return + if(learned_message) //Is it understood? + var/complete_message = ",[language.key] [message]" + if(!(complete_message in speak)) + speech_buffer.Add(complete_message) + log_debug("Added '[complete_message]'.") + else + */ + if(!(message in speak)) + speech_buffer.Add(message) + ..(message,verb,language,alt_name,italics,speaker) + +/mob/living/simple_animal/xeno/proc/ProcessSpeechBuffer() + if(speech_buffer.len) + if(prob(traitdat.get_trait(TRAIT_XENO_LEARNCHANCE)) && traitdat.get_trait(TRAIT_XENO_CANLEARN)) + var/chosen = pick(speech_buffer) + speak.Add(chosen) + /* Uncoment for logging of speech list. + log_debug("Added [chosen] to speak list.") + log_debug("Speechlist cut.") */ + speech_buffer.Cut() +// +/mob/living/simple_animal/xeno/proc/BuildReagentLists() + return + +/mob/living/simple_animal/xeno/proc/bulet_act(var/obj/item/projectile/P) + //Shamelessly stolen from ablative armor. + if((traitdat.traits[TRAIT_XENO_CHROMATIC]) && istype(P, /obj/item/projectile/beam)) + visible_message("") + // Find a turf near or on the original location to bounce to + var/new_x = P.starting.x + pick(0, -1, 1, -2, 2) + var/new_y = P.starting.y + pick(0, -1, 1, -2, 2) + var/turf/curloc = get_turf(src) + + // redirect the projectile + P.redirect(new_x, new_y, curloc, src) + + return + else + ..() + +/mob/living/simple_animal/xeno/proc/RandomChemicals() + traitdat.chems.Cut() //Clear the amount first. + + var/num_chems = round(rand(1,4)) + var/list/chemchoices = xenoChemList + + for(var/i = 1 to num_chems) + var/chemtype = pick(chemchoices) + chemchoices -= chemtype + var/chemamount = rand(1,5) + traitdat.chems[chemtype] = chemamount + + traitdat.chems += default_chems diff --git a/code/modules/xenobio2/mob/xeno.dm b/code/modules/xenobio2/mob/xeno.dm new file mode 100644 index 0000000000..7b1bf7dfac --- /dev/null +++ b/code/modules/xenobio2/mob/xeno.dm @@ -0,0 +1,97 @@ +//First we define certain flags, can be expanded upon later. + +/* +Basic definition of creatures for Xenobiology +Also includes Life and New +*/ + +/mob/living/simple_animal/xeno + name = "Xeno" + real_name = "Xeno" + desc = "Something's broken, yell at someone." + melee_damage_lower = 0 + melee_damage_upper = 0 + attacktext = "hit" + attack_sound = null + friendly = "touches" + environment_smash = 0 + + var/datum/xeno/traits/traitdat //Trait datum. + + var/internal_vol = 1000 //Internal volume for ingesting/injected reagents + + var/obj/temp_chem_holder //Used in handle_reagents() + + var/mutable = NOMUT //Flag for mutation. + var/nameVar = "Blah" + var/instability = 0 + var/stasis = 0 + var/mut_level = 0 //How mutated a specimen is. Irrelevant while mutable = NOMUT. + var/mut_max = 100000 + var/colored = 1 + var/maleable = MIN_MALEABLE //How easy is it to manipulate traitdat.traits after it's alive. + var/stability = 0 //Used in gene manipulation + + //Traits that might not be maleable. + var/list/chemreact = list() + var/hunger_factor = 10 + var/chromatic = 0 + var/starve_damage = 0 + + //Used for speech learning + var/list/speech_buffer = list() + + var/list/default_chems = list() + + +//Life additions +/mob/living/simple_animal/xeno/Life() + if(src.stat == DEAD) + return 0 + + if(stasis) + stasis-- + if(stasis < 0) + stasis = 0 + return 0 + ..() + handle_reagents() + if((mut_level >= mut_max) && !(mutable & NOMUT)) + Mutate() + mut_level -= mut_max + + ProcessSpeechBuffer() + + //Have to feed the xenos somehow. + if(nutrition < 0) + nutrition = 0 + if((nutrition > 0 ) && traitdat.traits[TRAIT_XENO_EATS]) + if(nutrition >= 300) + nutrition -= hunger_factor + else + if(traitdat.traits[TRAIT_XENO_EATS]) + health = starve_damage + + return 1 //Everything worked okay. + +/mob/living/simple_animal/xeno/New() + + traitdat = new() + + ProcessTraits() + + ..() + if(colored) + color = traitdat.get_trait(TRAIT_XENO_COLOR) + create_reagents(internal_vol) + temp_chem_holder = new() + temp_chem_holder.create_reagents(20) + nutrition = 350 + for(var/R in default_chems) + traitdat.chems[R] = default_chems[R] + + traitdat.source = name + + if(!health) + stat = DEAD + \ No newline at end of file diff --git a/code/modules/xenobio2/mob/xeno_product.dm b/code/modules/xenobio2/mob/xeno_product.dm new file mode 100644 index 0000000000..2ea970c89f --- /dev/null +++ b/code/modules/xenobio2/mob/xeno_product.dm @@ -0,0 +1,12 @@ +/* +Xenobiological product lives here as a basic type. +*/ +/obj/item/xenoproduct + name = "Xenobiological product" + desc = "How did this get here?." + icon = 'icons/mob/slime2.dmi' + icon_state = "slime extract" + var/datum/xeno/traits/traits + var/source = "Unknown" + var/product = "mess" + \ No newline at end of file diff --git a/code/modules/xenobio2/tools/slime_handling_tools.dm b/code/modules/xenobio2/tools/slime_handling_tools.dm new file mode 100644 index 0000000000..b8f37a106f --- /dev/null +++ b/code/modules/xenobio2/tools/slime_handling_tools.dm @@ -0,0 +1,64 @@ +/* What this file contains: + + * A specialized stun prod, for handling fiesty slimes + + * A specialized stun gun, for handling many fiesty slimes + + * A stun projectile for handling xenomorphs. + +*/ +/obj/item/weapon/melee/baton/slime + name = "slimebaton" + desc = "A modified stun baton designed to stun slimes for handling." + icon_state = "slimebaton" + item_state = "slimebaton" + slot_flags = SLOT_BELT + force = 9 + lightcolor = "#33CCFF" + origin_tech = list(TECH_COMBAT = 2, TECH_BIO = 4) + agonyforce = 10 //It's not supposed to be great at stunning human beings. + var/stasisforce = 60 //How much stasis it does to slimes, and 1/3rd to non-slimes. + +/obj/item/weapon/melee/baton/slime/attack(mob/M, mob/user) + if(istype(M, /mob/living/simple_animal/xeno)) + var/mob/living/simple_animal/xeno/X = M + if(istype(M, /mob/living/simple_animal/xeno/slime)) + X.stasis += stasisforce + else + X.stasis += (stasisforce / 6) + ..() + +/obj/item/weapon/melee/baton/slime/loaded/New() + ..() + bcell = new/obj/item/weapon/cell/high(src) + update_icon() + return + + +// Xeno stun gun + projectile +/obj/item/weapon/gun/energy/taser/xeno + name = "xeno taser gun" + desc = "Straight out of NT's testing laboratories, this small gun is used to subdue non-humanoid xeno life forms. While marketed towards handling slimes, it may be useful for other creatures." + icon_state = "taserold" + fire_sound = 'sound/weapons/taser2.ogg' + max_shots = 10 + projectile_type = /obj/item/projectile/beam/stun/xeno + +/obj/item/projectile/beam/stun/xeno + icon_state = "omni" + agony = 4 + var/stasisforce = 40 + + muzzle_type = /obj/effect/projectile/laser_omni/muzzle + tracer_type = /obj/effect/projectile/laser_omni/tracer + impact_type = /obj/effect/projectile/laser_omni/impact + +/obj/item/projectile/beam/stun/xeno/on_hit(var/atom/target, var/blocked = 0) + if(istype(target, /mob/living/simple_animal/xeno)) + var/mob/living/simple_animal/xeno/X = target + if(istype(target, /mob/living/simple_animal/xeno/slime)) + X.stasis += stasisforce + else + X.stasis += (stasisforce / 8) + else + ..() \ No newline at end of file diff --git a/code/world.dm b/code/world.dm index bfa399fe2a..66edcd00d2 100644 --- a/code/world.dm +++ b/code/world.dm @@ -73,6 +73,9 @@ var/global/datum/global_init/init = new () // Set up roundstart seed list. plant_controller = new() + + // Set up roundstart gene masking + xenobio_controller = new() // This is kinda important. Set up details of what the hell things are made of. populate_material_list() diff --git a/html/changelogs/Datraen-Xenobio2Init.yml b/html/changelogs/Datraen-Xenobio2Init.yml new file mode 100644 index 0000000000..98d84e1eb7 --- /dev/null +++ b/html/changelogs/Datraen-Xenobio2Init.yml @@ -0,0 +1,40 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# wip (For works in progress) +# tweak +# soundadd +# sounddel +# rscadd (general adding of nice things) +# rscdel (general deleting of nice things) +# imageadd +# imagedel +# maptweak +# spellcheck (typo fixes) +# experiment +################################# + +# Your name. +author: Datraen + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. +# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. +changes: + - rscdel: "Injecting people with mutationtoxin no longer mutates them into slime people." + - rscdel: "Removes amutationtoxin." + - rscdel: "Removes slime core recipies." + - rscadd: "Adds slime monkey cubes, which are created by injecting monkey cubes with mutationtoxin and activating like a posibrain." + - wip: "Maps for Xenobio2 research labs/stations." diff --git a/icons/mob/items/lefthand.dmi b/icons/mob/items/lefthand.dmi index e852456518..a1dde7b433 100644 Binary files a/icons/mob/items/lefthand.dmi and b/icons/mob/items/lefthand.dmi differ diff --git a/icons/mob/items/righthand.dmi b/icons/mob/items/righthand.dmi index e592cfeafb..105b1fe5a5 100644 Binary files a/icons/mob/items/righthand.dmi and b/icons/mob/items/righthand.dmi differ diff --git a/icons/mob/slime2.dmi b/icons/mob/slime2.dmi new file mode 100644 index 0000000000..33ef237cba Binary files /dev/null and b/icons/mob/slime2.dmi differ diff --git a/icons/obj/weapons.dmi b/icons/obj/weapons.dmi index 54837eeaa9..15152c2159 100644 Binary files a/icons/obj/weapons.dmi and b/icons/obj/weapons.dmi differ diff --git a/maps/polaris-5.dmm b/maps/polaris-5.dmm index 1c7075b1b6..58ce998b1c 100644 --- a/maps/polaris-5.dmm +++ b/maps/polaris-5.dmm @@ -273,7 +273,7 @@ "fm" = (/obj/machinery/atmospherics/pipe/simple/visible/purple{dir = 6},/obj/machinery/light,/turf/simulated/floor/plating,/area/outpost/research/toxins_misc_lab) "fn" = (/obj/structure/table/standard,/obj/machinery/microwave/map,/obj/machinery/status_display{layer = 4; pixel_x = -32; pixel_y = 0},/turf/simulated/floor/tiled,/area/outpost/research/toxins_misc_lab) "fo" = (/obj/machinery/atmospherics/pipe/simple/hidden/purple,/turf/simulated/wall/r_wall,/area/outpost/research/toxins_misc_lab) -"fp" = (/mob/living/carbon/slime,/turf/simulated/floor/reinforced,/area/outpost/research/xenobiology) +"fp" = (/obj/machinery/xenobio2/manualinjector,/turf/simulated/floor/reinforced,/area/outpost/research/xenobiology) "fq" = (/obj/structure/disposalpipe/segment,/obj/machinery/light/small{dir = 4},/turf/simulated/floor/reinforced,/area/outpost/research/xenobiology) "fr" = (/obj/machinery/portable_atmospherics/canister,/turf/simulated/floor/plating,/area/outpost/research/hallway/toxins_hallway) "fs" = (/obj/structure/table/rack,/obj/item/weapon/storage/toolbox/emergency,/obj/item/clothing/accessory/armband/science,/obj/item/clothing/glasses/science,/obj/item/device/radio/intercom{name = "Station Intercom (General)"; pixel_y = -21},/obj/item/device/suit_cooling_unit,/turf/simulated/floor/plating,/area/outpost/research/hallway/toxins_hallway) @@ -290,7 +290,7 @@ "fD" = (/obj/machinery/light{dir = 4; icon_state = "tube1"},/obj/effect/floor_decal/industrial/warning{dir = 6},/turf/simulated/floor/tiled/white,/area/outpost/research/hallway/toxins_hallway) "fE" = (/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction,/turf/space,/area/space) "fF" = (/obj/machinery/atmospherics/pipe/simple/heat_exchanging,/turf/simulated/mineral/floor/ignore_mapgen,/area/mine/explored) -"fG" = (/obj/structure/table/standard,/obj/item/weapon/scalpel{pixel_y = 12},/obj/item/weapon/circular_saw,/obj/machinery/vending/wallmed1{name = "Emergency NanoMed"; pixel_x = -7; pixel_y = 32},/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) +"fG" = (/obj/machinery/vending/wallmed1{name = "Emergency NanoMed"; pixel_x = -7; pixel_y = 32},/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) "fH" = (/obj/structure/disposalpipe/segment,/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) "fI" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "xenobio1"; name = "Containment Blast Doors"; opacity = 0},/obj/structure/cable/blue{d2 = 2; icon_state = "0-2"},/turf/simulated/floor/plating,/area/outpost/research/xenobiology) "fJ" = (/obj/effect/floor_decal/industrial/hatch/yellow,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "xenobio1"; name = "Containment Blast Doors"; opacity = 0},/obj/machinery/door/window/southright{dir = 1; name = "Containment Pen"; req_access = list(47)},/turf/simulated/floor/reinforced,/area/outpost/research/xenobiology) @@ -305,11 +305,11 @@ "fS" = (/obj/machinery/atmospherics/pipe/simple/heat_exchanging,/turf/space,/area/space) "fT" = (/obj/structure/sink{pixel_x = 0; pixel_y = 28},/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) "fU" = (/obj/structure/disposalpipe/segment{dir = 1; icon_state = "pipe-c"},/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) -"fV" = (/obj/structure/disposalpipe/segment{dir = 2; icon_state = "pipe-c"},/obj/machinery/camera/network/research_outpost{c_tag = "OPR - Xenobiology Fore Port"; dir = 2},/obj/machinery/firealarm{dir = 2; pixel_y = 24},/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) +"fV" = (/obj/structure/disposalpipe/segment{dir = 2; icon_state = "pipe-c"},/obj/machinery/camera/network/research_outpost{c_tag = "OPR - Xenobiology Fore Port"; dir = 2},/obj/machinery/firealarm{dir = 2; pixel_y = 24},/obj/machinery/computer/xenobio2,/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) "fW" = (/obj/structure/table/reinforced,/obj/structure/window/reinforced{dir = 4},/obj/structure/cable/blue{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/effect/floor_decal/industrial/warning{dir = 10},/obj/machinery/button/remote/blast_door{id = "xenobio1"; name = "Containment Blast Doors"; pixel_x = 0; pixel_y = 4; req_access = list(55)},/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) "fX" = (/obj/machinery/door/window/southright{name = "Containment Pen"; req_access = list(47)},/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) "fY" = (/obj/machinery/disposal,/obj/structure/disposalpipe/trunk{dir = 1},/obj/structure/window/reinforced{dir = 8},/obj/structure/cable/blue{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) -"fZ" = (/obj/structure/closet/l3closet/scientist,/obj/effect/floor_decal/industrial/warning,/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) +"fZ" = (/obj/effect/floor_decal/industrial/warning,/obj/machinery/computer/xenobio2,/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) "ga" = (/obj/structure/table/reinforced,/obj/structure/window/reinforced{dir = 4},/obj/structure/cable/blue{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/effect/floor_decal/industrial/warning,/obj/machinery/button/remote/blast_door{id = "xenobio2"; name = "Containment Blast Doors"; pixel_x = 0; pixel_y = 4; req_access = list(55)},/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) "gb" = (/obj/machinery/disposal,/obj/structure/disposalpipe/trunk{dir = 1},/obj/structure/window/reinforced{dir = 8},/obj/structure/cable/blue{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/effect/floor_decal/industrial/warning{dir = 6},/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) "gc" = (/obj/machinery/camera/network/research_outpost{c_tag = "OPR - Xenobiology Fore Starboard"; dir = 2},/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) @@ -320,9 +320,9 @@ "gh" = (/obj/structure/window/reinforced{dir = 4},/obj/structure/cable/blue{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/machinery/camera/network/research_outpost{c_tag = "OPR - Toxins Exterior"; dir = 2},/obj/effect/floor_decal/industrial/warning/corner{dir = 1},/turf/simulated/floor/tiled,/area/outpost/research/hallway/catwalk) "gi" = (/obj/structure/window/reinforced{dir = 8},/turf/simulated/floor/airless,/area/mine/explored) "gj" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/firedoor/border_only,/turf/simulated/floor/plating,/area/outpost/research/xenobiology) -"gk" = (/obj/structure/table/rack{dir = 8; layer = 2.9},/obj/item/device/flashlight,/obj/item/device/flashlight,/obj/item/weapon/extinguisher,/turf/simulated/floor/tiled/dark,/area/outpost/research/xenobiology) -"gl" = (/obj/machinery/optable{name = "Xenobiology Operating Table"},/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) -"gm" = (/obj/machinery/computer/operating{name = "Xenobiology Operating Computer"},/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) +"gk" = (/obj/structure/table/rack{dir = 8; layer = 2.9},/obj/item/device/flashlight,/obj/item/device/flashlight,/turf/simulated/floor/tiled/dark,/area/outpost/research/xenobiology) +"gl" = (/obj/machinery/slime/extractor,/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) +"gm" = (/obj/machinery/computer/xenobio2,/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) "gn" = (/obj/structure/cable/blue{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) "go" = (/obj/structure/cable/blue{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) "gp" = (/obj/structure/cable/blue{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/blue{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) @@ -337,7 +337,7 @@ "gy" = (/obj/machinery/atmospherics/pipe/simple/heat_exchanging{dir = 5},/turf/space,/area/space) "gz" = (/obj/machinery/atmospherics/pipe/simple/heat_exchanging{tag = "icon-intact (NORTHWEST)"; icon_state = "intact"; dir = 9},/turf/space,/area/space) "gA" = (/obj/structure/grille,/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/firedoor/border_only,/turf/simulated/floor/plating,/area/outpost/research/xenobiology) -"gB" = (/obj/structure/reagent_dispensers/watertank,/turf/simulated/floor/tiled/dark,/area/outpost/research/xenobiology) +"gB" = (/obj/machinery/recharger/wallcharger/map{pixel_x = -22},/obj/structure/disposalpipe/segment,/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) "gC" = (/obj/structure/extinguisher_cabinet{pixel_x = 7; pixel_y = -32},/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) "gD" = (/obj/machinery/light,/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) "gE" = (/obj/structure/disposalpipe/segment,/obj/machinery/atmospherics/unary/vent_pump/on{dir = 4},/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) @@ -370,7 +370,7 @@ "hf" = (/obj/machinery/shower{pixel_y = 3},/obj/structure/window/reinforced{dir = 8},/turf/simulated/floor/tiled/freezer,/area/outpost/research/xenobiology) "hg" = (/obj/structure/table/standard,/obj/machinery/reagentgrinder,/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) "hh" = (/obj/machinery/smartfridge/secure/extract,/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) -"hi" = (/obj/structure/table/standard,/obj/item/weapon/storage/box/syringes,/obj/item/glass_jar,/obj/item/glass_jar,/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) +"hi" = (/obj/machinery/slime/replicator,/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) "hj" = (/obj/structure/cable/blue{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable/blue{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) "hk" = (/obj/machinery/disposal,/obj/structure/disposalpipe/trunk{dir = 4},/obj/structure/window/reinforced{dir = 1},/obj/structure/cable/blue{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) "hl" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 8},/obj/structure/disposalpipe/segment{dir = 4},/obj/structure/cable/blue{d2 = 8; icon_state = "0-8"},/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "xenobio3"; name = "Containment Blast Doors"; opacity = 0},/turf/simulated/floor/plating,/area/outpost/research/xenobiology) @@ -394,7 +394,7 @@ "hD" = (/obj/structure/disposalpipe/segment{dir = 8; icon_state = "pipe-c"},/obj/structure/cable/blue{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/blue{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/embedded_controller/radio/airlock/access_controller{id_tag = "xeno_airlock_control"; name = "Xenobiology Access Console"; pixel_x = -26; pixel_y = -28; tag_exterior_door = "xeno_airlock_exterior"; tag_interior_door = "xeno_airlock_interior"},/obj/machinery/light_switch{pixel_x = -26; pixel_y = 26},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) "hE" = (/obj/structure/cable/blue{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 4},/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) "hF" = (/obj/structure/cable/blue{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable/blue{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/hologram/holopad,/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) -"hG" = (/obj/structure/table/standard,/obj/item/weapon/reagent_containers/food/snacks/monkeycube/wrapped,/obj/item/weapon/reagent_containers/spray/cleaner,/obj/item/device/slime_scanner,/obj/item/device/slime_scanner,/obj/machinery/light{dir = 4; icon_state = "tube1"},/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) +"hG" = (/obj/machinery/light{dir = 4; icon_state = "tube1"},/obj/structure/table/standard,/obj/item/device/multitool,/obj/item/weapon/gun/energy/taser/xeno,/obj/item/weapon/gun/energy/taser/xeno,/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) "hH" = (/obj/machinery/status_display,/turf/simulated/wall/r_wall,/area/outpost/research/xenobiology) "hI" = (/obj/structure/table/standard,/obj/item/weapon/storage/box/beakers{pixel_x = 2; pixel_y = 2},/obj/machinery/light{dir = 8; icon_state = "tube1"; pixel_y = 0},/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) "hJ" = (/obj/structure/cable/blue{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/hologram/holopad,/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) @@ -411,9 +411,9 @@ "hU" = (/obj/structure/closet/emcloset,/obj/effect/floor_decal/industrial/warning{dir = 10},/obj/machinery/alarm{dir = 1; icon_state = "alarm0"; pixel_y = -22},/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) "hV" = (/obj/structure/closet/l3closet/scientist,/obj/effect/floor_decal/industrial/warning,/obj/machinery/camera/network/research_outpost{c_tag = "OPR - Xenobiology Access"; dir = 1},/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) "hW" = (/obj/machinery/disposal,/obj/structure/disposalpipe/trunk,/obj/structure/sign/deathsposal{pixel_x = 0; pixel_y = 32},/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) -"hX" = (/obj/structure/table/standard,/obj/item/weapon/storage/box/monkeycubes,/obj/item/weapon/storage/box/monkeycubes,/obj/item/weapon/storage/box/monkeycubes,/obj/item/weapon/storage/box/monkeycubes,/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) +"hX" = (/obj/structure/table/standard,/obj/item/weapon/storage/box/monkeycubes,/obj/item/weapon/storage/box/monkeycubes,/obj/item/weapon/storage/box/monkeycubes,/obj/item/weapon/storage/box/monkeycubes,/obj/item/weapon/reagent_containers/food/snacks/monkeycube/wrapped,/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) "hY" = (/obj/structure/table/standard,/obj/item/clothing/gloves/latex,/obj/item/weapon/hand_labeler,/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) -"hZ" = (/obj/structure/table/standard,/obj/item/stack/material/phoron{amount = 5},/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) +"hZ" = (/obj/structure/table/standard,/obj/item/glass_jar,/obj/item/glass_jar,/obj/item/weapon/storage/box/syringes,/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) "ia" = (/obj/structure/cable/blue{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/blue{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) "ib" = (/obj/structure/table/reinforced,/obj/structure/window/reinforced,/obj/structure/cable/blue{d1 = 4; d2 = 8; icon_state = "4-8"},/obj/machinery/button/remote/blast_door{id = "xenobio4"; name = "Containment Blast Doors"; pixel_x = 0; pixel_y = 4; req_access = list(55)},/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) "ic" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "xenobio4"; name = "Containment Blast Doors"; opacity = 0},/obj/structure/cable/blue{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/plating,/area/outpost/research/xenobiology) @@ -432,7 +432,7 @@ "ip" = (/obj/structure/window/reinforced{dir = 8},/obj/machinery/light/small{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/outpost/research/hallway/catwalk) "iq" = (/obj/structure/window/reinforced{dir = 8},/obj/structure/lattice,/turf/simulated/mineral/floor/ignore_mapgen,/area/mine/explored) "ir" = (/obj/structure/table/standard,/obj/item/weapon/paper_bin{pixel_x = -2; pixel_y = 5},/obj/item/weapon/pen/blue{pixel_x = -5; pixel_y = -1},/obj/item/weapon/pen/red{pixel_x = -1; pixel_y = 3},/turf/simulated/floor/tiled/dark,/area/outpost/research/xenobiology) -"is" = (/obj/machinery/requests_console{department = "Science"; departmentType = 2; name = "Science Requests Console"; pixel_x = 0; pixel_y = 30},/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) +"is" = (/obj/effect/floor_decal/industrial/warning{dir = 1},/obj/machinery/xenobio/editor,/turf/simulated/floor/reinforced,/area/outpost/research/xenobiology) "it" = (/obj/machinery/light{dir = 1},/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) "iu" = (/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 4},/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) "iv" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) @@ -444,24 +444,24 @@ "iB" = (/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/light/small,/turf/simulated/floor/reinforced,/area/outpost/research/xenobiology) "iC" = (/obj/structure/disposaloutlet{dir = 1},/obj/structure/disposalpipe/trunk{dir = 8},/turf/simulated/floor/reinforced,/area/outpost/research/xenobiology) "iD" = (/obj/structure/window/reinforced{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/tiled,/area/outpost/research/hallway/catwalk) -"iE" = (/obj/structure/table/standard,/obj/item/weapon/clipboard,/obj/item/weapon/folder,/obj/item/weapon/pen,/turf/simulated/floor/tiled/dark,/area/outpost/research/xenobiology) -"iF" = (/obj/structure/bed/chair/office/light{dir = 8},/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) +"iE" = (/obj/machinery/requests_console{department = "Science"; departmentType = 2; name = "Science Requests Console"; pixel_x = 0; pixel_y = 30},/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) +"iF" = (/obj/structure/table/standard,/obj/item/weapon/clipboard,/obj/item/weapon/folder,/obj/item/weapon/pen,/obj/item/weapon/melee/baton/slime/loaded,/turf/simulated/floor/tiled/dark,/area/outpost/research/xenobiology) "iG" = (/obj/structure/cable/blue{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) "iH" = (/obj/structure/cable/blue{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/structure/cable/blue{d1 = 4; d2 = 8; icon_state = "4-8"},/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) "iI" = (/obj/structure/cable/blue{d1 = 1; d2 = 4; icon_state = "1-4"},/obj/structure/cable/blue{d1 = 1; d2 = 8; icon_state = "1-8"},/obj/machinery/button/remote/blast_door{desc = "A remote control-switch for a door to space."; id = "xenobioout6"; name = "Containment Release Switch"; pixel_x = 0; pixel_y = -28; req_access = list(55)},/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) "iJ" = (/obj/structure/cable/blue{d1 = 2; d2 = 8; icon_state = "2-8"},/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) -"iK" = (/obj/structure/table/standard,/obj/item/weapon/folder/red{pixel_y = 3},/obj/item/weapon/folder/blue{pixel_x = 5},/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) +"iK" = (/obj/structure/bed/chair/office/light,/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) "iL" = (/obj/machinery/camera/network/research_outpost{c_tag = "OPR - Xenobiology Aft Port"; dir = 1},/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) "iM" = (/obj/structure/window/reinforced{dir = 4},/obj/machinery/disposal,/obj/structure/disposalpipe/trunk,/obj/structure/cable/blue{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/effect/floor_decal/industrial/warning{icon_state = "warning"; dir = 9},/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) "iN" = (/obj/machinery/door/window/southright{dir = 1; name = "Containment Pen"; req_access = list(47)},/obj/effect/floor_decal/industrial/warning{dir = 1},/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) "iO" = (/obj/structure/window/reinforced{dir = 8},/obj/structure/table/reinforced,/obj/machinery/button/remote/blast_door{id = "xenobio6"; name = "Containment Blast Doors"; pixel_x = 0; pixel_y = 4; req_access = list(55)},/obj/effect/floor_decal/industrial/warning{dir = 5},/obj/structure/cable/blue{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) "iP" = (/obj/structure/window/reinforced{dir = 4},/obj/machinery/disposal,/obj/structure/disposalpipe/trunk,/obj/effect/floor_decal/industrial/warning{dir = 1},/obj/structure/cable/blue{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) "iQ" = (/obj/structure/window/reinforced{dir = 8},/obj/structure/table/reinforced,/obj/machinery/button/remote/blast_door{id = "xenobio5"; name = "Containment Blast Doors"; pixel_x = 0; pixel_y = 4; req_access = list(55)},/obj/structure/cable/blue{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/effect/floor_decal/industrial/warning{dir = 5},/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) -"iR" = (/obj/machinery/camera/network/research_outpost{c_tag = "OPR - Xenobiology Aft Starboard"; dir = 1},/obj/machinery/newscaster{pixel_y = -32},/obj/machinery/light,/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) -"iS" = (/obj/structure/table/steel,/obj/item/clothing/glasses/science,/obj/item/weapon/extinguisher,/turf/simulated/floor/tiled/dark,/area/outpost/research/xenobiology) +"iR" = (/obj/structure/table/standard,/obj/item/weapon/folder/red{pixel_y = 3},/obj/item/weapon/folder/blue{pixel_x = 5},/obj/item/weapon/reagent_containers/spray/cleaner,/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) +"iS" = (/obj/machinery/camera/network/research_outpost{c_tag = "OPR - Xenobiology Aft Starboard"; dir = 1},/obj/machinery/newscaster{pixel_y = -32},/obj/machinery/light,/obj/machinery/computer/xenobio2,/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) "iT" = (/obj/structure/window/reinforced{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8},/turf/simulated/floor/tiled,/area/outpost/research/hallway/catwalk) "iU" = (/obj/structure/window/reinforced{dir = 4},/obj/structure/cable/blue{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/disposalpipe/segment,/turf/simulated/floor/tiled,/area/outpost/research/hallway/catwalk) -"iV" = (/obj/structure/filingcabinet/chestdrawer,/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) +"iV" = (/obj/structure/table/steel,/obj/item/clothing/glasses/science,/turf/simulated/floor/tiled/dark,/area/outpost/research/xenobiology) "iW" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "xenobio6"; name = "Containment Blast Doors"; opacity = 0},/obj/structure/disposalpipe/segment,/obj/structure/cable/blue,/turf/simulated/floor/plating,/area/outpost/research/xenobiology) "iX" = (/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "xenobio6"; name = "Containment Blast Doors"; opacity = 0},/obj/effect/floor_decal/industrial/hatch/yellow,/obj/machinery/door/window/southright{name = "Containment Pen"; req_access = list(47)},/turf/simulated/floor/reinforced,/area/outpost/research/xenobiology) "iY" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "xenobio6"; name = "Containment Blast Doors"; opacity = 0},/obj/structure/cable/blue,/turf/simulated/floor/plating,/area/outpost/research/xenobiology) @@ -469,7 +469,7 @@ "ja" = (/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "xenobio5"; name = "Containment Blast Doors"; opacity = 0},/obj/effect/floor_decal/industrial/hatch/yellow,/obj/machinery/door/window/southright{name = "Containment Pen"; req_access = list(47)},/turf/simulated/floor/reinforced,/area/outpost/research/xenobiology) "jb" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 8},/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "xenobio5"; name = "Containment Blast Doors"; opacity = 0},/obj/structure/cable/blue,/turf/simulated/floor/plating,/area/outpost/research/xenobiology) "jc" = (/obj/structure/extinguisher_cabinet{pixel_x = 25; pixel_y = 0},/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) -"jd" = (/obj/structure/table/rack{dir = 8; layer = 2.9},/obj/item/weapon/storage/toolbox/emergency,/turf/simulated/floor/tiled/dark,/area/outpost/research/xenobiology) +"jd" = (/obj/structure/table/standard,/obj/item/weapon/storage/box/xenobiodisk,/obj/item/weapon/melee/baton/slime/loaded,/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) "je" = (/turf/simulated/wall,/area/outpost/research/xenobiology) "jf" = (/obj/structure/closet,/obj/item/toy/figure/scientist,/obj/item/clothing/accessory/armband/science,/turf/simulated/floor/tiled/dark,/area/outpost/research/xenobiology) "jg" = (/obj/structure/window/reinforced{dir = 4},/obj/structure/cable/blue{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/unary/vent_scrubber/on{dir = 8},/obj/structure/disposalpipe/segment,/turf/simulated/floor/tiled,/area/outpost/research/hallway/catwalk) @@ -1586,6 +1586,10 @@ "Ez" = (/obj/structure/table/steel,/obj/item/weapon/cell/high,/turf/simulated/floor/tiled/asteroid_steel/airless,/area/outpost/mining_main/refinery) "EA" = (/obj/structure/table/steel,/obj/machinery/cell_charger,/turf/simulated/floor/tiled/asteroid_steel/airless,/area/outpost/mining_main/refinery) "EB" = (/obj/effect/floor_decal/industrial/warning/dust/corner,/obj/machinery/light/small,/turf/simulated/floor/tiled/asteroid_steel/airless,/area/outpost/mining_main/refinery) +"EC" = (/obj/item/weapon/stool/padded,/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) +"ED" = (/obj/machinery/xenobio/extractor,/turf/simulated/floor/tiled/dark,/area/outpost/research/xenobiology) +"EE" = (/obj/structure/disposalpipe/segment,/obj/machinery/xenobio/editor,/turf/simulated/floor/reinforced,/area/outpost/research/xenobiology) +"EF" = (/obj/machinery/recharger/wallcharger/map{pixel_x = 32},/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) (1,1,1) = {" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa @@ -1673,22 +1677,22 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadeEeFeGeHeIetadeJeKeLdReMeBeBeNeOEbdRdRdRacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacalalalatauatalalalacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadadadadadadadadeQejeReSeTeBeCeUeCePdRacacacacacacacacaceVeVeVeVeVeVeVeVeVacacacacacacacacacacacacacacacacalalalalamacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaeeWaqeXaiaqeYeZfafbfcfdeCeUfeEcfgdRacacacacacacacacaceVfhfhfieVfhfhfieVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaefsfkaqaqaeaeflaeaeeTeBfmfyfofoacacacacacacacaceVeVeVfhfpfqeVfhfpfqeVeVeVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaeaefrfraegYftfuaefvfwfofofofxdldlacacdlacaceVeVjeeVfhfhfzeVfhfhfzeVfAeVeVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaefsfkaqaqaeaeflaeaeeTeBfmfyfofoacacacacacacacaceVeVeVfhfhfqeVfhfhfqeVeVeVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaeaeaefrfraegYftfuaefvfwfofofofxdldlacacdlacaceVeVjeeVfpfhfzeVfpfhfzeVfAeVeVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadmaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadlaeaeaeaefBfCfDaedRdRfofEfxfFdldldldldlaceVeVfGhWeVfIfJfKeVfLfMfNeVfOfPeVeVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadldldlaeaefQfRaeaedRaafEfSfFfFdldldldldleVeVfTfOfUfVfWfXfYfZgafXgbgcgdfOfAeVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadmaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadldlgegfggghgiaaaafSfSfSfSaadldldldlgjgkfOglgmfHgngogpgqgrgogsfOfOeVeVeVeVeVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadlgtgugvgwgxaaaagygzgygzaaaaaaaadlgAgBgCgDgdgEgFgGgGgHgGgGgGgIgJgKfhgLfheVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadldlgegfggghgiaaaafSfSfSfSaadldldldlgjgkfOglfOfHgngogpgqgrgogsfOgmeVeVeVeVeVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadlgtgugvgwgxaaaagygzgygzaaaaaaaadlgAfAgCgDgdgEgFgGgGgHgGgGgGgIgJgKfpgLfheVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadlgNgMgOgwgxgPaaaaaaaaaaaaaagPgQgReVeVeVeVeVgSgTgUgogVfOfOgdgWgXiofhfhfheVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagtgZgvgwhagQgQgQgQgQgQgQgQhbgZhceVhdhehfeVfHgTgWhghhhifOgdhjhkhlhmhmhneVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagtgZgvgwhagQgQgQgQgQgQgQgQhbgZhceVhdhehfeVgBgTgWhghhhifOgdhjhkhlhmhmhneVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahohphqhrhshshthuhshshshvhshshwhxhyhzhAhBhChDhEhFhGhHhIhJhKhLkkeVhNhNhNeVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahOguorhPhQhQhQhRhQhQhQhShQhQhQhTeVhUhVkreVgWgTgWhXhYhZgWgdiaibicididideVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahOguorhPhQhQhQhRhQhQhQhShQhQhQhTeVhUhVkreVgWgTgWhXhYhZgWgdiaibicisidideVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagPieifigiiihijijijijijijijijijikeVeVeVeVeVilgTimgoingogVgdgWgXmrfhfhfheVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahOipiUiqdldlaaaaaaaaaaaaaaaaaagjirisitgdiuiviwiwixiwiwiwiyhkiziAiBiCeVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahOiDiUiqdldldlaaaaaaaaaaaaaaaagAiEiFfOfOfOiGgoiHiIingoiJfOfOeVeVeVeVeVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahOiDiUiqdldldlaaaaaaaaaaaaaaaaeVeViKfOgdiLiMiNiOhMiPiNiQiRgdfOiSeVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahOiTjgiqdldldlaaaaaaaaaaaaaaaaaaeVeViVfOeViWiXiYeViZjajbeVfOjceVeVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagtiDiUiqdldldlaaaaaaaaaaaaaaaaaaaaeVeVjdeVfzfhfhjefzfhfheVjfeVeVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahOipiUiqdldlaaaaaaaaaaaaaaaaaagjiriEitgdiuiviwiwixiwiwiwiyhkiziAiBiCeVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahOiDiUiqdldldlaaaaaaaaaaaaaaaagAiFfOfOfOfOiGgoiHiIingoiJfOEFeVeVeVeVeVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahOiDiUiqdldldlaaaaaaaaaaaaaaaaeVeViRiKgdiLiMiNiOhMiPiNiQiSgdfOiVeVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahOiTjgiqdldldlaaaaaaaaaaaaaaaaaaeVeVjdECeViWiXiYeViZjajbeVfOjceVeVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaagtiDiUiqdldldlaaaaaaaaaaaaaaaaaaaaeVeVEDeVEEfhfhjefzfhfpeVjfeVeVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadlgtiDjpiqdldldldldlaaaaaaaaaaaaaaaaaaeVeVeVjhfhfhjejhfhfheVeVeVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadlgtiDiUiqdldldldldlaaaaaaaaaaaaaaaaaaaaaaeVjifhfhjejifhfheVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaadlgtiDiUiqdldldldldlaaaaaaaaaaaaaaaaaaaaaaeVjjjjjjeVeVeVeVeVacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacacaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa diff --git a/nano/css/icons.css b/nano/css/icons.css index 746f6e5b09..a6bec0f0d0 100644 --- a/nano/css/icons.css +++ b/nano/css/icons.css @@ -184,6 +184,7 @@ .uiIcon16.icon-pin-s { background-position: -144px -144px; } .uiIcon16.icon-phone { background-position: -160px -144px; } .uiIcon16.icon-list { background-position: -176px -144px; } +.uiIcon16.icon-syringe { background-position: -192px -144px; } .uiIcon16.icon-play { background-position: 0 -160px; } .uiIcon16.icon-pause { background-position: -16px -160px; } .uiIcon16.icon-seek-next { background-position: -32px -160px; } diff --git a/nano/css/shared.css b/nano/css/shared.css index 8b640c3b57..a50f96a3c7 100644 --- a/nano/css/shared.css +++ b/nano/css/shared.css @@ -366,7 +366,7 @@ div.notice { background: #000000; } -.displayBarText { +.displayBarText, .displayBarVerticalText, .displayBarBeakerText{ position: absolute; top: -2px; left: 5px; @@ -384,6 +384,48 @@ div.notice { float: left; } +.displayBarVertical { + position: relative; + width: 16px; + height: 200px; + border: 1px solid #666666; + float: left; + margin: 0 5px 0 0; + overflow: hidden; + background: #40628a; +} + +.displayBarVerticalFill { + width: 100%; + height: 0%; + overflow: hidden; + float: left; + background: #000000; +} + +/*used in xenobio2 computer*/ + +.displayBarBeaker { + position: relative; + width: 100px; + height: 110px; + border-right: 2px solid rgb(102, 179, 255); + border-left: 2px solid rgb(102, 179, 255); + border-bottom: 2px solid rgb(102, 179, 255); + float: left; + margin: 0 5px 0 0; + overflow: hidden; + background: #40628a; +} + +.displayBarBeakerFill { + width: 100%; + height: 0%; + overflow: hidden; + float: left; + background: rgba(153, 204, 255, 0.3); +} + .displayBarFill.alignRight { float: right; } diff --git a/nano/images/uiIcons16.png b/nano/images/uiIcons16.png index 61cfd560c7..2017c88d6c 100644 Binary files a/nano/images/uiIcons16.png and b/nano/images/uiIcons16.png differ diff --git a/nano/js/nano_base_helpers.js b/nano/js/nano_base_helpers.js index 20e6160fed..2f0f59772d 100644 --- a/nano/js/nano_base_helpers.js +++ b/nano/js/nano_base_helpers.js @@ -91,8 +91,8 @@ NanoBaseHelpers = function () capitalizeFirstLetter: function(string) { return string.charAt(0).toUpperCase() + string.slice(1); }, - // Display a bar. Used to show health, capacity, etc. - displayBar: function(value, rangeMin, rangeMax, styleClass, showText) { + // Display a bar. Used to show health, capacity, etc. Use difClass if the entire display bar class should be different + displayBar: function(value, rangeMin, rangeMax, styleClass, showText, difClass) { if (rangeMin < rangeMax) { @@ -126,10 +126,15 @@ NanoBaseHelpers = function () { showText = ''; } + + if (typeof difClass == 'undefined' || !difClass) + { + return '
' + showText + '
'; + } var percentage = Math.round((value - rangeMin) / (rangeMax - rangeMin) * 100); - return '
' + showText + '
'; + return '
' + showText + '
'; }, // Display DNA Blocks (for the DNA Modifier UI) displayDNABlocks: function(dnaString, selectedBlock, selectedSubblock, blockSize, paramKey) { diff --git a/nano/templates/xenobio_computer.tmpl b/nano/templates/xenobio_computer.tmpl new file mode 100644 index 0000000000..9cf053cddd --- /dev/null +++ b/nano/templates/xenobio_computer.tmpl @@ -0,0 +1,57 @@ + + +{{if data.activity}} + Scanning... +{{else}} +
+ {{if data.beaker}} + {{:data.reagentAmount}}u / {{:data.reagentMax}}u + {{:helper.displayBar(data.reagentAmount, data.reagentMax, data.reagentMin, 'good', null, 'displayBarBeaker')}} + {{else}} + ERRR% + {{:helper.displayBar(data.reagentAmount, data.reagentMax, data.reagentMin, 'good', null, 'displayBarBeaker')}} + {{/if}} +
+
+

Sensor Readings:

+ {{if data.occupied}} +
+
+ Instability: +
+
+ {{if data.instability}} + {{:data.instability}}% + {{else}} + ERRR% Please contact your local technician for assistance. + {{/if}} +
+
+ Occupant Health: +
+
+ {{if data.occupantHealth}} + {{:data.occupantHealth}}/{{:data.occupantHealthMax}} + {{else}} + ERRR% Please contact your local technician for assistance. + {{/if}} + {{else}} +
+
+ Injector is not occupied. +
+ {{/if}} +
+
+
+
+

Controls:

+
+ {{:helper.link('Eject Beaker', 'eject', {'eject_beaker' : 1})}} {{:helper.link('Eject Occupant', 'eject', {'eject_occupant' : 1})}} {{:helper.link('Inject Occupant', 'syringe', {'inject_target' : 1})}} +
+
+ +{{/if}} \ No newline at end of file diff --git a/nano/templates/xenobio_editor.tmpl b/nano/templates/xenobio_editor.tmpl new file mode 100644 index 0000000000..d16b3df6b6 --- /dev/null +++ b/nano/templates/xenobio_editor.tmpl @@ -0,0 +1,57 @@ + + +{{if data.activity}} + Scanning... +{{else}} +

Buffered Genetic Data

+ {{if data.disk}} +
+
+ Source: +
+
+ {{:data.sourceName}} +
+
+ Gene decay: +
+
+ {{if data.degradation <= 100}} + {{:data.degradation}}% + {{else}} + FURTHER AMENDMENTS NONVIABLE + {{/if}} +
+
+ Locus: +
+
+ {{:data.locus}} +
+ {{:helper.link('Eject Disk', 'circle-arrow-e', {'eject_disk' : 1}, null)}} +
+ {{else}} +
No disk loaded.
+ {{/if}} +

Loaded Material

+ {{if data.loaded}} +
+
+ Target: +
+
+ {{:data.loaded}} +
+ {{if data.degradation <= 100}} + {{:helper.link('Apply Gene Mods', 'gear', {'apply_gene' : 1}, null)}} + {{/if}} + {{:helper.link('Eject Target', 'circle-arrow-e', {'eject_xeno' : 1}, null)}} +
+ {{else}} +
No target organism loaded
+ {{/if}} +{{/if}} \ No newline at end of file diff --git a/nano/templates/xenobio_isolator.tmpl b/nano/templates/xenobio_isolator.tmpl new file mode 100644 index 0000000000..3bc855a457 --- /dev/null +++ b/nano/templates/xenobio_isolator.tmpl @@ -0,0 +1,74 @@ + + +{{if data.activity}} + Scanning... +{{else}} +

Buffered Genetic Data

+ {{if data.hasGenetics}} +
+
+ Source: +
+
+ {{:data.sourceName}} +
+
+ Gene decay: +
+
+ {{:data.degradation}}% +
+
+ {{if data.disk}} + {{for data.geneMasks}} +
+
+ {{:value.mask}} +
+
+ {{:helper.link('Extract', 'circle-arrow-s', {'get_gene' : value.tag}, null)}} +
+
+ {{empty}} +
Data error. Genetic record corrupt.
+ {{/for}} +
+
+ {{:helper.link('Eject Loaded Disk', 'circle-arrow-e', {'eject_disk' : 1}, null)}} + {{:helper.link('Clear Genetic Buffer', 'gear', {'clear_buffer' : 1}, null)}} +
+ {{else}} +
No disk inserted.
+ {{/if}} + {{else}} +
No data buffered.
+ {{if data.disk}} +
+
+ {{:helper.link('Eject Loaded Disk', 'circle-arrow-e', {'eject_disk' : 1}, null)}} +
+ {{else}} +
No disk inserted.
+ {{/if}} + {{/if}} +

Loaded Material

+ {{if data.loaded}} +
+
+ Product loaded: +
+
+ {{:data.loaded}} +
+
+ {{:helper.link('Process Genome', 'gear', {'scan_genome' : 1}, null)}}{{:helper.link('Eject Product', 'circle-arrow-e', {'eject_product' : 1}, null)}} +
+
+ {{else}} +
No biologocial sample loaded.
+ {{/if}} +{{/if}} \ No newline at end of file diff --git a/polaris.dme b/polaris.dme index e47f97da6e..c09bd6af43 100644 --- a/polaris.dme +++ b/polaris.dme @@ -1894,6 +1894,22 @@ #include "code\modules\virus2\helpers.dm" #include "code\modules\virus2\isolator.dm" #include "code\modules\virus2\items_devices.dm" +#include "code\modules\xenobio2\_xeno_setup.dm" +#include "code\modules\xenobio2\controller.dm" +#include "code\modules\xenobio2\machinery\core_extractor.dm" +#include "code\modules\xenobio2\machinery\gene_manipulators.dm" +#include "code\modules\xenobio2\machinery\injector.dm" +#include "code\modules\xenobio2\machinery\injector_computer.dm" +#include "code\modules\xenobio2\machinery\slime_replicator.dm" +#include "code\modules\xenobio2\mob\xeno procs.dm" +#include "code\modules\xenobio2\mob\xeno.dm" +#include "code\modules\xenobio2\mob\xeno_product.dm" +#include "code\modules\xenobio2\mob\slime\slime life.dm" +#include "code\modules\xenobio2\mob\slime\slime procs.dm" +#include "code\modules\xenobio2\mob\slime\slime.dm" +#include "code\modules\xenobio2\mob\slime\slime_core.dm" +#include "code\modules\xenobio2\mob\slime\slime_monkey.dm" +#include "code\modules\xenobio2\tools\slime_handling_tools.dm" #include "code\modules\xgm\xgm_gas_data.dm" #include "code\modules\xgm\xgm_gas_mixture.dm" #include "code\unit_tests\loadout_tests.dm"