diff --git a/code/ZAS/Airflow.dm b/code/ZAS/Airflow.dm index 8dd637e58f..fde7b78aca 100644 --- a/code/ZAS/Airflow.dm +++ b/code/ZAS/Airflow.dm @@ -22,7 +22,7 @@ mob/proc/airflow_stun() mob/living/silicon/airflow_stun() return -mob/living/carbon/slime/airflow_stun() +mob/living/simple_animal/slime/airflow_stun() return mob/living/carbon/human/airflow_stun() diff --git a/code/__defines/chemistry.dm b/code/__defines/chemistry.dm index 2207ffb075..08131f99bb 100644 --- a/code/__defines/chemistry.dm +++ b/code/__defines/chemistry.dm @@ -34,6 +34,8 @@ #define CE_ALCOHOL_TOXIC "alcotoxic" // Liver damage #define CE_SPEEDBOOST "gofast" // Hyperzine +#define REAGENTS_PER_SHEET 20 + // Chemistry lists. var/list/tachycardics = list("coffee", "inaprovaline", "hyperzine", "nitroglycerin", "thirteenloko", "nicotine") // Increase heart rate. var/list/bradycardics = list("neurotoxin", "cryoxadone", "clonexadone", "space_drugs", "stoxin") // Decrease heart rate. diff --git a/code/__defines/mobs.dm b/code/__defines/mobs.dm index ef00eed334..de957d8b21 100644 --- a/code/__defines/mobs.dm +++ b/code/__defines/mobs.dm @@ -212,4 +212,10 @@ #define FBP_NONE "" #define FBP_CYBORG "Cyborg" #define FBP_POSI "Positronic" -#define FBP_DRONE "Drone" \ No newline at end of file +#define FBP_DRONE "Drone" + +// Used to seperate simple animals by ""intelligence"". +#define SA_PLANT 1 +#define SA_ANIMAL 2 +#define SA_ROBOTIC 3 +#define SA_HUMANOID 4 \ No newline at end of file diff --git a/code/_helpers/unsorted.dm b/code/_helpers/unsorted.dm index 63bac6e134..152f5e2a9a 100644 --- a/code/_helpers/unsorted.dm +++ b/code/_helpers/unsorted.dm @@ -492,8 +492,6 @@ Turf and target are seperate in case you want to teleport some distance from a t moblist.Add(M) for(var/mob/new_player/M in sortmob) moblist.Add(M) - for(var/mob/living/carbon/slime/M in sortmob) - moblist.Add(M) for(var/mob/living/simple_animal/M in sortmob) moblist.Add(M) // for(var/mob/living/silicon/hivebot/M in world) diff --git a/code/_macros.dm b/code/_macros.dm index 454a4eaacd..38b9d15c71 100644 --- a/code/_macros.dm +++ b/code/_macros.dm @@ -40,7 +40,9 @@ #define isvoice(A) istype(A, /mob/living/voice) -#define isslime(A) istype(A, /mob/living/carbon/slime) +#define isslime(A) istype(A, /mob/living/simple_animal/slime) + +#define isbot(A) istype(A, /mob/living/bot) #define isxeno(A) istype(A, /mob/living/simple_animal/xeno) diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm index ac07b8d075..b4eb89b8b3 100644 --- a/code/_onclick/other_mobs.dm +++ b/code/_onclick/other_mobs.dm @@ -58,77 +58,6 @@ setClickCooldown(DEFAULT_ATTACK_COOLDOWN) A.attack_generic(src,rand(5,6),"bitten") -/* - Slimes - Nothing happening here -*/ - -/mob/living/carbon/slime/RestrainedClickOn(var/atom/A) - return - -/mob/living/carbon/slime/UnarmedAttack(var/atom/A, var/proximity) - - if(!..()) - return - - // Eating - if(Victim) - if (Victim == A) - Feedstop() - return - - //should have already been set if we are attacking a mob, but it doesn't hurt and will cover attacking non-mobs too - setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - - var/mob/living/M = A - if (istype(M)) - - switch(src.a_intent) - if (I_HELP) // We just poke the other - M.visible_message("[src] gently pokes [M]!", "[src] gently pokes you!") - if (I_DISARM) // We stun the target, with the intention to feed - var/stunprob = 1 - var/power = max(0, min(10, (powerlevel + rand(0, 3)))) - if (powerlevel > 0 && !istype(A, /mob/living/carbon/slime)) - if(ishuman(M)) - var/mob/living/carbon/human/H = M - stunprob *= max(H.species.siemens_coefficient,0) - - - switch(power * 10) - if(0) stunprob *= 10 - if(1 to 2) stunprob *= 20 - if(3 to 4) stunprob *= 30 - if(5 to 6) stunprob *= 40 - if(7 to 8) stunprob *= 60 - if(9) stunprob *= 70 - if(10) stunprob *= 95 - - if(prob(stunprob)) - powerlevel = max(0, powerlevel-3) - M.visible_message("[src] has shocked [M]!", "[src] has shocked you!") - M.Weaken(power) - M.Stun(power) - M.stuttering = max(M.stuttering, power) - - var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread - s.set_up(5, 1, M) - s.start() - - if(prob(stunprob) && powerlevel >= 8) - M.adjustFireLoss(powerlevel * rand(6,10)) - else if(prob(40)) - M.visible_message("[src] has pounced at [M]!", "[src] has pounced at you!") - M.Weaken(power) - else - M.visible_message("[src] has tried to pounce at [M]!", "[src] has tried to pounce at you!") - M.updatehealth() - if (I_GRAB) // We feed - Wrap(M) - if (I_HURT) // Attacking - A.attack_generic(src, (is_adult ? rand(20,40) : rand(5,25)), "glomped") - else - A.attack_generic(src, (is_adult ? rand(20,40) : rand(5,25)), "glomped") // Basic attack. /* New Players: Have no reason to click on anything at all. @@ -140,15 +69,40 @@ Animals */ /mob/living/simple_animal/UnarmedAttack(var/atom/A, var/proximity) - if(!..()) return + if(prob(spattack_prob)) + if(spattack_min_range <= 1) + target_mob = A + SpecialAtkTarget() + target_mob = null + return + if(melee_damage_upper == 0 && istype(A,/mob/living)) custom_emote(1,"[friendly] [A]!") return setClickCooldown(DEFAULT_ATTACK_COOLDOWN) - var/damage = rand(melee_damage_lower, melee_damage_upper) - if(A.attack_generic(src,damage,attacktext,environment_smash) && loc && attack_sound) - playsound(loc, attack_sound, 50, 1, 1) + if(isliving(A)) + target_mob = A + PunchTarget() + target_mob = null + else + A.attack_generic(src, rand(melee_damage_lower, melee_damage_upper), attacktext) + +/mob/living/simple_animal/RangedAttack(var/atom/A) + setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + var/distance = get_dist(src, A) + + if(prob(spattack_prob) && (distance >= spattack_min_range) && (distance <= spattack_max_range)) + target_mob = A + SpecialAtkTarget() + target_mob = null + return + + if(ranged && distance <= shoot_range) + target_mob = A + ShootTarget(A) + target_mob = null + diff --git a/code/controllers/verbs.dm b/code/controllers/verbs.dm index fcf239c88f..8d02fda2eb 100644 --- a/code/controllers/verbs.dm +++ b/code/controllers/verbs.dm @@ -133,9 +133,6 @@ if("Vote") debug_variables(vote) feedback_add_details("admin_verb", "DVote") - if("Xenobio") - debug_variables(xenobio_controller) - feedback_add_details("admin_verb", "DXenobio") if("Planets") debug_variables(planet_controller) feedback_add_details("admin_verb", "DPlanets") diff --git a/code/datums/mind.dm b/code/datums/mind.dm index cb49518bd8..2c0faffc1e 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -499,7 +499,7 @@ if(!mind.assigned_role) mind.assigned_role = "Assistant" //defualt //slime -/mob/living/carbon/slime/mind_initialize() +/mob/living/simple_animal/slime/mind_initialize() ..() mind.assigned_role = "slime" diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 64ae0722f8..fa533f5d55 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -94,6 +94,8 @@ /atom/movable/proc/throw_impact(atom/hit_atom, var/speed) if(istype(hit_atom,/mob/living)) var/mob/living/M = hit_atom + if(M.buckled == src) + return // Don't hit the thing we're buckled to. M.hitby(src,speed) else if(isobj(hit_atom)) diff --git a/code/game/gamemodes/technomancer/devices/disposable_teleporter.dm b/code/game/gamemodes/technomancer/devices/disposable_teleporter.dm index 0106ff027e..f45461592d 100644 --- a/code/game/gamemodes/technomancer/devices/disposable_teleporter.dm +++ b/code/game/gamemodes/technomancer/devices/disposable_teleporter.dm @@ -63,7 +63,7 @@ targets.Add(T) if(!targets.len) - user << "The teleporter matrix was unable to locate a suitable teleport destination, as all the possibilities \ + user << "\The [src] was unable to locate a suitable teleport destination, as all the possibilities \ were nonexistant or hazardous. Try a different area." return var/turf/simulated/destination = null @@ -75,6 +75,5 @@ user << "You are teleported to \the [A]." uses-- if(uses <= 0) - user << "\The [src] has ran out of uses, and disintegrates from your hands, to prevent \ - reverse engineering by outsiders." + user << "\The [src] has ran out of uses, and disintegrates from your hands" qdel(src) \ No newline at end of file diff --git a/code/game/gamemodes/technomancer/spells/control.dm b/code/game/gamemodes/technomancer/spells/control.dm index 50549ca004..c4591345e5 100644 --- a/code/game/gamemodes/technomancer/spells/control.dm +++ b/code/game/gamemodes/technomancer/spells/control.dm @@ -33,7 +33,7 @@ /mob/living/simple_animal/mouse, /mob/living/simple_animal/parrot, /mob/living/simple_animal/slime, - /mob/living/simple_animal/adultslime, +// /mob/living/simple_animal/adultslime, /mob/living/simple_animal/tindalos, /mob/living/simple_animal/yithian, /mob/living/simple_animal/hostile/bear, diff --git a/code/game/machinery/adv_med.dm b/code/game/machinery/adv_med.dm index f980cfd0b1..31fe02cdcb 100644 --- a/code/game/machinery/adv_med.dm +++ b/code/game/machinery/adv_med.dm @@ -46,8 +46,8 @@ if(occupant) user << "The scanner is already occupied!" return - for(var/mob/living/carbon/slime/M in range(1, H.affecting)) - if(M.Victim == H.affecting) + for(var/mob/living/simple_animal/slime/M in range(1, H.affecting)) + if(M.victim == H.affecting) user << "[H.affecting.name] has a fucking slime attached to them, deal with that first." return var/mob/M = H.affecting @@ -83,8 +83,8 @@ if(O.abiotic()) user << "Subject cannot have abiotic items on." return 0 - for(var/mob/living/carbon/slime/M in range(1, O)) - if(M.Victim == O) + for(var/mob/living/simple_animal/slime/M in range(1, O)) + if(M.victim == O) user << "[O] has a fucking slime attached to them, deal with that first." return 0 diff --git a/code/game/machinery/cryo.dm b/code/game/machinery/cryo.dm index 1e27f61866..33529f4447 100644 --- a/code/game/machinery/cryo.dm +++ b/code/game/machinery/cryo.dm @@ -180,15 +180,16 @@ G.loc = src user.visible_message("[user] adds \a [G] to \the [src]!", "You add \a [G] to \the [src]!") else if(istype(G, /obj/item/weapon/grab)) - if(!ismob(G:affecting)) + var/obj/item/weapon/grab/grab = G + if(!ismob(grab.affecting)) return - for(var/mob/living/carbon/slime/M in range(1,G:affecting)) - if(M.Victim == G:affecting) - usr << "[G:affecting:name] will not fit into the cryo because they have a slime latched onto their head." + for(var/mob/living/simple_animal/slime/M in range(1,grab.affecting)) + if(M.victim == grab.affecting) + usr << "[grab.affecting.name] will not fit into the cryo because they have a slime latched onto their head." return - var/mob/M = G:affecting + var/mob/M = grab.affecting if(put_mob(M)) - qdel(G) + qdel(grab) return /obj/machinery/atmospherics/unary/cryo_cell/MouseDrop_T(var/mob/target, var/mob/user) //Allows borgs to put people into cryo without external assistance @@ -343,8 +344,8 @@ set name = "Move Inside" set category = "Object" set src in oview(1) - for(var/mob/living/carbon/slime/M in range(1,usr)) - if(M.Victim == usr) + for(var/mob/living/simple_animal/slime/M in range(1,usr)) + if(M.victim == usr) usr << "You're too busy getting your life sucked out of you." return if(usr.stat != 0) diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm index 08a1282e52..3ef7fe00a7 100644 --- a/code/game/machinery/cryopod.dm +++ b/code/game/machinery/cryopod.dm @@ -539,8 +539,8 @@ usr << "\The [src] is in use." return - for(var/mob/living/carbon/slime/M in range(1,usr)) - if(M.Victim == usr) + for(var/mob/living/simple_animal/slime/M in range(1,usr)) + if(M.victim == usr) usr << "You're too busy getting your life sucked out of you." return diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm index 5449d3436b..4fc02c70cc 100644 --- a/code/game/machinery/doors/windowdoor.dm +++ b/code/game/machinery/doors/windowdoor.dm @@ -180,6 +180,21 @@ if (src.operating == 1) return + // Fixing. + if(istype(I, /obj/item/weapon/weldingtool) && user.a_intent == I_HELP) + var/obj/item/weapon/weldingtool/WT = I + if(health < maxhealth) + if(WT.remove_fuel(1 ,user)) + to_chat(user, "You begin repairing [src]...") + playsound(src, WT.usesound, 50, 1) + if(do_after(user, 40 * WT.toolspeed, target = src)) + health = maxhealth + update_icon() + to_chat(user, "You repair [src].") + else + to_chat(user, "[src] is already in good condition!") + return + //Emags and ninja swords? You may pass. if (istype(I, /obj/item/weapon/melee/energy/blade)) if(emag_act(10, user)) diff --git a/code/game/machinery/kitchen/smartfridge.dm b/code/game/machinery/kitchen/smartfridge.dm index 5b78f81249..9732b166f0 100644 --- a/code/game/machinery/kitchen/smartfridge.dm +++ b/code/game/machinery/kitchen/smartfridge.dm @@ -65,19 +65,11 @@ req_access = list(access_research) /obj/machinery/smartfridge/secure/extract/accept_check(var/obj/item/O as obj) - if(istype(O,/obj/item/xenoproduct/)) - return 1 - return 0 - -/obj/machinery/smartfridge/secure/extract/New() - ..() - var/datum/stored_item/I = new(src, /obj/item/xenoproduct/slime/core) - item_records.Add(I) - for(var/i=1 to 5) - var/obj/item/xenoproduct/slime/core/C = new(src) - C.traits = new() - C.nameVar = "grey" - I.add_product(C) + if(istype(O, /obj/item/slime_extract)) + return TRUE + if(istype(O, /obj/item/slimepotion)) + return TRUE + return FALSE /obj/machinery/smartfridge/secure/medbay diff --git a/code/game/mecha/equipment/tools/medical_tools.dm b/code/game/mecha/equipment/tools/medical_tools.dm index 1e10e03f4f..acd680ba57 100644 --- a/code/game/mecha/equipment/tools/medical_tools.dm +++ b/code/game/mecha/equipment/tools/medical_tools.dm @@ -39,8 +39,8 @@ if(occupant) occupant_message("The sleeper is already occupied") return - for(var/mob/living/carbon/slime/M in range(1,target)) - if(M.Victim == target) + for(var/mob/living/simple_animal/slime/M in range(1,target)) + if(M.victim == target) occupant_message("[target] will not fit into the sleeper because they have a slime latched onto their head.") return occupant_message("You start putting [target] into [src].") diff --git a/code/game/mecha/equipment/tools/tools.dm b/code/game/mecha/equipment/tools/tools.dm index 4d7ee902d8..a1cbba3102 100644 --- a/code/game/mecha/equipment/tools/tools.dm +++ b/code/game/mecha/equipment/tools/tools.dm @@ -1154,8 +1154,8 @@ usr << "Kinda hard to climb in while handcuffed don't you think?" return - for(var/mob/living/carbon/slime/M in range(1,usr)) - if(M.Victim == usr) + for(var/mob/living/simple_animal/slime/M in range(1,usr)) + if(M.victim == usr) usr << "You're too busy getting your life sucked out of you." return diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index 5d7d16a126..6f117b2f3e 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -1015,8 +1015,8 @@ usr << "Access denied" src.log_append_to_last("Permission denied.") return - for(var/mob/living/carbon/slime/M in range(1,usr)) - if(M.Victim == usr) + for(var/mob/living/simple_animal/slime/M in range(1,usr)) + if(M.victim == usr) usr << "You're too busy getting your life sucked out of you." return // usr << "You start climbing into [src.name]" diff --git a/code/game/objects/buckling.dm b/code/game/objects/buckling.dm index c963a902bb..a26a0de0e8 100644 --- a/code/game/objects/buckling.dm +++ b/code/game/objects/buckling.dm @@ -1,4 +1,6 @@ -/obj + + +/atom/movable var/can_buckle = 0 var/buckle_movable = 0 var/buckle_dir = 0 @@ -6,7 +8,8 @@ var/buckle_require_restraints = 0 //require people to be handcuffed before being able to buckle. eg: pipes var/mob/living/buckled_mob = null -/obj/attack_hand(mob/living/user) + +/atom/movable/attack_hand(mob/living/user) . = ..() if(can_buckle && buckled_mob) user_unbuckle_mob(user) @@ -16,18 +19,20 @@ return attack_hand(user) //Process as if we're a normal person touching the object. return ..() //Otherwise, treat this as an AI click like usual. -/obj/MouseDrop_T(mob/living/M, mob/living/user) +/atom/movable/MouseDrop_T(mob/living/M, mob/living/user) . = ..() if(can_buckle && istype(M)) user_buckle_mob(M, user) -/obj/Destroy() +/atom/movable/Destroy() unbuckle_mob() return ..() -/obj/proc/buckle_mob(mob/living/M) - if(!can_buckle || !istype(M) || (M.loc != loc) || M.buckled || M.pinned.len || (buckle_require_restraints && !M.restrained())) +/atom/movable/proc/buckle_mob(mob/living/M, forced = FALSE, check_loc = TRUE) + if((!can_buckle && !forced) || !istype(M) || M.buckled || M.pinned.len || (buckle_require_restraints && !M.restrained())) + return 0 + if(check_loc && M.loc != loc) return 0 if(buckled_mob) //Handles trying to buckle yourself to the chair when someone is on it M << "\The [src] already has someone buckled to it." @@ -43,7 +48,7 @@ post_buckle_mob(M) return 1 -/obj/proc/unbuckle_mob() +/atom/movable/proc/unbuckle_mob() if(buckled_mob && buckled_mob.buckled == src) . = buckled_mob buckled_mob.buckled = null @@ -54,19 +59,16 @@ post_buckle_mob(.) -/obj/proc/post_buckle_mob(mob/living/M) +/atom/movable/proc/post_buckle_mob(mob/living/M) return -/obj/proc/user_buckle_mob(mob/living/M, mob/user) +/atom/movable/proc/user_buckle_mob(mob/living/M, mob/user, var/forced = FALSE, var/silent = FALSE) if(!ticker) user << "You can't buckle anyone in before the game starts." if(!user.Adjacent(M) || user.restrained() || user.lying || user.stat || istype(user, /mob/living/silicon/pai)) return if(M == buckled_mob) return - if(istype(M, /mob/living/carbon/slime)) - user << "The [M] is too squishy to buckle in." - return add_fingerprint(user) unbuckle_mob() @@ -75,20 +77,21 @@ if(M.loc != src.loc) step_towards(M, src) - . = buckle_mob(M) + . = buckle_mob(M, forced) if(.) - if(M == user) - M.visible_message(\ - "[M.name] buckles themselves to [src].",\ - "You buckle yourself to [src].",\ - "You hear metal clanking.") - else - M.visible_message(\ - "[M.name] is buckled to [src] by [user.name]!",\ - "You are buckled to [src] by [user.name]!",\ - "You hear metal clanking.") + if(!silent) + if(M == user) + M.visible_message(\ + "[M.name] buckles themselves to [src].",\ + "You buckle yourself to [src].",\ + "You hear metal clanking.") + else + M.visible_message(\ + "[M.name] is buckled to [src] by [user.name]!",\ + "You are buckled to [src] by [user.name]!",\ + "You hear metal clanking.") -/obj/proc/user_unbuckle_mob(mob/user) +/atom/movable/proc/user_unbuckle_mob(mob/user) var/mob/living/M = unbuckle_mob() if(M) if(M != user) @@ -104,3 +107,19 @@ add_fingerprint(user) return M +/atom/movable/proc/handle_buckled_mob_movement(newloc,direct) + if(buckled_mob) +// if(!buckled_mob.Move(newloc, direct)) + if(!buckled_mob.forceMove(newloc, direct)) + loc = buckled_mob.loc + last_move = buckled_mob.last_move + buckled_mob.inertia_dir = last_move + return FALSE + else + buckled_mob.set_dir(dir) + return TRUE + +/atom/movable/Move(atom/newloc, direct = 0) + . = ..() + if(. && buckled_mob && !handle_buckled_mob_movement(newloc, direct)) //movement failed due to buckled mob(s) + . = 0 diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm index 996f848849..973cb522e7 100644 --- a/code/game/objects/items/devices/flashlight.dm +++ b/code/game/objects/items/devices/flashlight.dm @@ -448,10 +448,11 @@ /obj/item/device/flashlight/slime gender = PLURAL name = "glowing slime extract" - desc = "A glowing ball of what appears to be amber." + desc = "A slimy ball that appears to be glowing from bioluminesence." icon = 'icons/obj/lighting.dmi' icon_state = "floor1" //not a slime extract sprite but... something close enough! item_state = "slime" + light_color = "#FFF423" w_class = ITEMSIZE_TINY brightness_on = 6 on = 1 //Bio-luminesence has one setting, on. diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index cfd0693b15..d903499ee0 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -364,32 +364,38 @@ REAGENT SCANNER matter = list(DEFAULT_WALL_MATERIAL = 30,"glass" = 20) /obj/item/device/slime_scanner/attack(mob/living/M as mob, mob/living/user as mob) - if (!isslime(M)) + if(!isslime(M)) user << "This device can only scan slimes!" return - var/mob/living/carbon/slime/T = M + var/mob/living/simple_animal/slime/S = M user.show_message("Slime scan results:") - user.show_message(text("[T.colour] [] slime", T.is_adult ? "adult" : "baby")) - user.show_message(text("Nutrition: [T.nutrition]/[]", T.get_max_nutrition())) - if (T.nutrition < T.get_starve_nutrition()) - user.show_message("Warning: slime is starving!") - else if (T.nutrition < T.get_hunger_nutrition()) - user.show_message("Warning: slime is hungry") - user.show_message("Electric change strength: [T.powerlevel]") - user.show_message("Health: [T.health]") - if (T.slime_mutation[4] == T.colour) - user.show_message("This slime does not evolve any further") - else - if (T.slime_mutation[3] == T.slime_mutation[4]) - if (T.slime_mutation[2] == T.slime_mutation[1]) - user.show_message(text("Possible mutation: []", T.slime_mutation[3])) - user.show_message("Genetic destability: [T.mutation_chance/2]% chance of mutation on splitting") - else - user.show_message(text("Possible mutations: [], [], [] (x2)", T.slime_mutation[1], T.slime_mutation[2], T.slime_mutation[3])) - user.show_message("Genetic destability: [T.mutation_chance]% chance of mutation on splitting") - else - user.show_message(text("Possible mutations: [], [], [], []", T.slime_mutation[1], T.slime_mutation[2], T.slime_mutation[3], T.slime_mutation[4])) - user.show_message("Genetic destability: [T.mutation_chance]% chance of mutation on splitting") - if (T.cores > 1) - user.show_message("Anomalious slime core amount detected") - user.show_message("Growth progress: [T.amount_grown]/10") + user.show_message(text("[S.slime_color] [] slime", S.is_adult ? "adult" : "baby")) + + user.show_message("Health: [S.health]") + user.show_message("Mutation Probability: [S.mutation_chance]") + + var/list/mutations = list() + for(var/potential_color in S.slime_mutation) + var/mob/living/simple_animal/slime/slime = potential_color + mutations.Add(initial(slime.slime_color)) + + user.show_message("Potental to mutate into [english_list(mutations)] colors.") + user.show_message("Extract potential: [S.cores]") + + user.show_message(text("Nutrition: [S.nutrition]/[]", S.get_max_nutrition())) + if (S.nutrition < S.get_starve_nutrition()) + user.show_message("Warning: Subject is starving!") + else if (S.nutrition < S.get_hunger_nutrition()) + user.show_message("Warning: Subject is hungry.") + user.show_message("Electric change strength: [S.power_charge]") + + if(S.resentment) + user.show_message("Warning: Subject is harboring resentment.") + if(S.docile) + user.show_message("Subject has been pacified.") + if(S.rabid) + user.show_message("Subject is enraged and extremely dangerous!") + if(S.unity) + user.show_message("Subject is friendly to other slime colors.") + + user.show_message("Growth progress: [S.amount_grown]/10") diff --git a/code/game/objects/items/weapons/implants/implantchair.dm b/code/game/objects/items/weapons/implants/implantchair.dm index 66080882be..44b33721cf 100644 --- a/code/game/objects/items/weapons/implants/implantchair.dm +++ b/code/game/objects/items/weapons/implants/implantchair.dm @@ -76,13 +76,14 @@ attackby(var/obj/item/weapon/G as obj, var/mob/user as mob) if(istype(G, /obj/item/weapon/grab)) - if(!ismob(G:affecting)) + var/obj/item/weapon/grab/grab = G + if(!ismob(grab.affecting)) return - for(var/mob/living/carbon/slime/M in range(1,G:affecting)) - if(M.Victim == G:affecting) - usr << "[G:affecting:name] will not fit into the [src.name] because they have a slime latched onto their head." + for(var/mob/living/simple_animal/slime/M in range(1,grab.affecting)) + if(M.victim == grab.affecting) + usr << "[grab.affecting.name] will not fit into the [src.name] because they have a slime latched onto their head." return - var/mob/M = G:affecting + var/mob/M = grab.affecting if(put_mob(M)) qdel(G) src.updateUsrDialog() diff --git a/code/game/objects/items/weapons/power_cells.dm b/code/game/objects/items/weapons/power_cells.dm index 192f667feb..3a2373c696 100644 --- a/code/game/objects/items/weapons/power_cells.dm +++ b/code/game/objects/items/weapons/power_cells.dm @@ -14,6 +14,8 @@ var/maxcharge = 1000 var/rigged = 0 // true if rigged to explode var/minor_fault = 0 //If not 100% reliable, it will build up faults. + var/self_recharge = FALSE // If true, the cell will recharge itself. + var/charge_amount = 25 // How much power to give, if self_recharge is true. The number is in absolute cell charge, as it gets divided by CELLRATE later. matter = list(DEFAULT_WALL_MATERIAL = 700, "glass" = 50) suicide_act(mob/user) @@ -125,8 +127,10 @@ /obj/item/weapon/cell/slime name = "charged slime core" desc = "A yellow slime core infused with phoron, it crackles with power." - origin_tech = list(TECH_POWER = 2, TECH_BIO = 4) + origin_tech = list(TECH_POWER = 4, TECH_BIO = 5) icon = 'icons/mob/slimes.dmi' //'icons/obj/harvest.dmi' icon_state = "yellow slime extract" //"potato_battery" + description_info = "This 'cell' holds a max charge of 10k and self recharges over time." maxcharge = 10000 matter = null + self_recharge = TRUE diff --git a/code/game/objects/items/weapons/stunbaton.dm b/code/game/objects/items/weapons/stunbaton.dm index 2f4b2f3a8c..1b54df33e6 100644 --- a/code/game/objects/items/weapons/stunbaton.dm +++ b/code/game/objects/items/weapons/stunbaton.dm @@ -90,7 +90,7 @@ icon_state = "[initial(name)]" if(icon_state == "[initial(name)]_active") - set_light(1.5, 1, lightcolor) + set_light(2, 1, lightcolor) else set_light(0) @@ -237,4 +237,16 @@ else user << "[src] already has a cell." else - user << "This cell is not fitted for [src]." \ No newline at end of file + user << "This cell is not fitted for [src]." + +/obj/item/weapon/melee/baton/get_description_interaction() + var/list/results = list() + + if(bcell) + results += "[desc_panel_image("offhand")]to remove the weapon cell." + else + results += "[desc_panel_image("weapon cell")]to add a new weapon cell." + + results += ..() + + return results \ No newline at end of file diff --git a/code/game/objects/random/random.dm b/code/game/objects/random/random.dm index 3afaa7a665..4da7cc6aeb 100644 --- a/code/game/objects/random/random.dm +++ b/code/game/objects/random/random.dm @@ -828,7 +828,6 @@ something, make sure it's not in one of the other lists.*/ /obj/random/maintenance/research/item_to_spawn() return pick(prob(320);/obj/random/maintenance/clean, prob(3);/obj/item/device/analyzer/plant_analyzer, - prob(2);/obj/item/device/analyzer/xeno_analyzer, prob(1);/obj/item/device/flash/synthetic, prob(2);/obj/item/weapon/bucket_sensor, prob(1);/obj/item/weapon/cell/device/weapon, diff --git a/code/game/objects/structures/crates_lockers/closets/l3closet.dm b/code/game/objects/structures/crates_lockers/closets/l3closet.dm index c00875e522..7c54614aa7 100644 --- a/code/game/objects/structures/crates_lockers/closets/l3closet.dm +++ b/code/game/objects/structures/crates_lockers/closets/l3closet.dm @@ -67,6 +67,11 @@ new /obj/item/clothing/suit/bio_suit/scientist(src) new /obj/item/clothing/head/bio_hood/scientist(src) +/obj/structure/closet/l3closet/scientist/double/New() + ..() + new /obj/item/clothing/suit/bio_suit/scientist(src) + new /obj/item/clothing/head/bio_hood/scientist(src) + /obj/structure/closet/l3closet/medical icon_state = "bio_scientist" diff --git a/code/game/objects/structures/crates_lockers/closets/utility_closets.dm b/code/game/objects/structures/crates_lockers/closets/utility_closets.dm index 67a4d3e788..110790aa82 100644 --- a/code/game/objects/structures/crates_lockers/closets/utility_closets.dm +++ b/code/game/objects/structures/crates_lockers/closets/utility_closets.dm @@ -88,6 +88,15 @@ new /obj/item/weapon/extinguisher(src) new /obj/item/clothing/head/hardhat/red(src) +/obj/structure/closet/firecloset/full/double/New() + ..() + new /obj/item/clothing/suit/fire/firefighter(src) + new /obj/item/clothing/mask/gas(src) + new /obj/item/device/flashlight(src) + new /obj/item/weapon/tank/oxygen/red(src) + new /obj/item/weapon/extinguisher(src) + new /obj/item/clothing/head/hardhat/red(src) + /obj/structure/closet/firecloset/update_icon() if(!opened) icon_state = icon_closed @@ -175,6 +184,12 @@ new /obj/item/clothing/shoes/black( src ) new /obj/item/clothing/head/bomb_hood( src ) +/obj/structure/closet/bombcloset/double/New() // Makes two suits. + ..() + new /obj/item/clothing/suit/bomb_suit( src ) + new /obj/item/clothing/under/color/black( src ) + new /obj/item/clothing/shoes/black( src ) + new /obj/item/clothing/head/bomb_hood( src ) /obj/structure/closet/bombclosetsecurity name = "\improper EOD closet" diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 51e37d462f..ca9276c6c2 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -59,10 +59,13 @@ playsound(loc, 'sound/effects/Glasshit.ogg', 100, 1) if(health < maxhealth / 4 && initialhealth >= maxhealth / 4) visible_message("[src] looks like it's about to shatter!" ) + update_icon() else if(health < maxhealth / 2 && initialhealth >= maxhealth / 2) visible_message("[src] looks seriously damaged!" ) + update_icon() else if(health < maxhealth * 3/4 && initialhealth >= maxhealth * 3/4) visible_message("Cracks begin to appear in [src]!" ) + update_icon() return /obj/structure/window/proc/apply_silicate(var/amount) @@ -204,6 +207,8 @@ return if(damage >= 10) visible_message("[user] smashes into [src]!") + if(reinf) + damage = damage / 2 take_damage(damage) else visible_message("\The [user] bonks \the [src] harmlessly.") @@ -212,6 +217,24 @@ /obj/structure/window/attackby(obj/item/W as obj, mob/user as mob) if(!istype(W)) return//I really wish I did not need this + + // Fixing. + if(istype(W, /obj/item/weapon/weldingtool) && user.a_intent == I_HELP) + var/obj/item/weapon/weldingtool/WT = W + if(health < maxhealth) + if(WT.remove_fuel(1 ,user)) + to_chat(user, "You begin repairing [src]...") + playsound(src, WT.usesound, 50, 1) + if(do_after(user, 40 * WT.toolspeed, target = src)) + health = maxhealth + // playsound(src, 'sound/items/Welder.ogg', 50, 1) + update_icon() + to_chat(user, "You repair [src].") + else + to_chat(user, "[src] is already in good condition!") + return + + // Slamming. if (istype(W, /obj/item/weapon/grab) && get_dist(src,user)<2) var/obj/item/weapon/grab/G = W if(istype(G.affecting,/mob/living)) @@ -408,6 +431,15 @@ var/image/I = image(icon, "[basestate][connections[i]]", dir = 1<<(i-1)) overlays += I + // Damage overlays. + var/ratio = health / maxhealth + ratio = Ceiling(ratio * 4) * 25 + + if(ratio > 75) + return + var/image/I = image(icon, "damage[ratio]", layer + 0.1) + overlays += I + return /obj/structure/window/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) @@ -437,6 +469,10 @@ damage_per_fire_tick = 1.0 maxhealth = 40.0 +/obj/structure/window/phoronbasic/full + dir = SOUTHWEST + maxhealth = 80 + /obj/structure/window/phoronreinforced name = "reinforced borosilicate window" desc = "A borosilicate alloy window, with rods supporting it. It seems to be very strong." @@ -449,6 +485,9 @@ damage_per_fire_tick = 1.0 // This should last for 80 fire ticks if the window is not damaged at all. The idea is that borosilicate windows have something like ablative layer that protects them for a while. maxhealth = 80.0 +/obj/structure/window/phoronreinforced/full + dir = SOUTHWEST + maxhealth = 160 /obj/structure/window/reinforced name = "reinforced window" @@ -470,9 +509,9 @@ state = 0 /obj/structure/window/reinforced/full - dir = 5 + dir = SOUTHWEST icon_state = "fwindow" - maxhealth = 60 + maxhealth = 80 /obj/structure/window/reinforced/tinted name = "tinted window" diff --git a/code/game/supplyshuttle.dm b/code/game/supplyshuttle.dm index f7bfd311e2..be376e0f65 100644 --- a/code/game/supplyshuttle.dm +++ b/code/game/supplyshuttle.dm @@ -50,7 +50,7 @@ var/list/mechtoys = list( explosion_resistance = 5 var/list/mobs_can_pass = list( /mob/living/bot, - /mob/living/carbon/slime, + /mob/living/simple_animal/slime, /mob/living/simple_animal/mouse, /mob/living/silicon/robot/drone ) diff --git a/code/game/verbs/suicide.dm b/code/game/verbs/suicide.dm index 6e23d74bbb..8f6beee8d6 100644 --- a/code/game/verbs/suicide.dm +++ b/code/game/verbs/suicide.dm @@ -164,24 +164,3 @@ death(0) else src << "Aborting suicide attempt." - -/mob/living/carbon/slime/verb/suicide() - set hidden = 1 - if (stat == 2) - src << "You're already dead!" - return - - if (suiciding) - src << "You're already committing suicide! Be patient!" - return - - var/confirm = alert("Are you sure you want to commit suicide?", "Confirm Suicide", "Yes", "No") - - if(confirm == "Yes") - suiciding = 30 - setOxyLoss(100) - adjustBruteLoss(100 - getBruteLoss()) - setToxLoss(100) - setCloneLoss(100) - - updatehealth() diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 6b3560a824..84a2320a2f 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -114,8 +114,7 @@ proc/admin_notice(var/message, var/rights) else if(ishuman(M)) body += {"Make AI | Make Robot | - Make Alien | - Make slime + Make Alien "} //Simple Animals diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index ab3fa05d21..f43af3ec86 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -190,7 +190,6 @@ 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/admin/topic.dm b/code/modules/admin/topic.dm index fde36a734c..db16b214b2 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -266,7 +266,7 @@ if("larva") M.change_mob_type( /mob/living/carbon/alien/larva , null, null, delmob ) if("nymph") M.change_mob_type( /mob/living/carbon/alien/diona , null, null, delmob ) if("human") M.change_mob_type( /mob/living/carbon/human , null, null, delmob, href_list["species"]) - if("slime") M.change_mob_type( /mob/living/carbon/slime , null, null, delmob ) + if("slime") M.change_mob_type( /mob/living/simple_animal/slime , null, null, delmob ) if("monkey") M.change_mob_type( /mob/living/carbon/human/monkey , null, null, delmob ) if("robot") M.change_mob_type( /mob/living/silicon/robot , null, null, delmob ) if("cat") M.change_mob_type( /mob/living/simple_animal/cat , null, null, delmob ) @@ -1146,16 +1146,6 @@ log_admin("[key_name(usr)] AIized [key_name(H)]") H.AIize() - else if(href_list["makeslime"]) - if(!check_rights(R_SPAWN)) return - - var/mob/living/carbon/human/H = locate(href_list["makeslime"]) - if(!istype(H)) - usr << "This can only be used on instances of type /mob/living/carbon/human" - return - - usr.client.cmd_admin_slimeize(H) - else if(href_list["makerobot"]) if(!check_rights(R_SPAWN)) return diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index 80ed64458e..a3fd6acf3e 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -100,23 +100,6 @@ paiController.pai_candidates.Remove(candidate) feedback_add_details("admin_verb","MPAI") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! -/client/proc/cmd_admin_slimeize(var/mob/M in mob_list) - set category = "Fun" - set name = "Make slime" - - if(!ticker) - alert("Wait until the game starts") - return - if(ishuman(M)) - log_admin("[key_name(src)] has slimeized [M.key].") - spawn(10) - M:slimeize() - feedback_add_details("admin_verb","MKMET") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! - log_admin("[key_name(usr)] made [key_name(M)] into a slime.") - message_admins("[key_name_admin(usr)] made [key_name(M)] into a slime.", 1) - else - alert("Invalid mob") - /* /client/proc/cmd_admin_monkeyize(var/mob/M in world) set category = "Fun" diff --git a/code/modules/admin/view_variables/helpers.dm b/code/modules/admin/view_variables/helpers.dm index 95945f82e0..81780f2103 100644 --- a/code/modules/admin/view_variables/helpers.dm +++ b/code/modules/admin/view_variables/helpers.dm @@ -68,7 +68,6 @@ - "} /obj/get_view_variables_options() diff --git a/code/modules/admin/view_variables/topic.dm b/code/modules/admin/view_variables/topic.dm index d68d51ae4a..7d0966dc59 100644 --- a/code/modules/admin/view_variables/topic.dm +++ b/code/modules/admin/view_variables/topic.dm @@ -281,20 +281,6 @@ return holder.Topic(href, list("makealien"=href_list["makealien"])) - else if(href_list["makeslime"]) - if(!check_rights(R_SPAWN)) return - - var/mob/living/carbon/human/H = locate(href_list["makeslime"]) - if(!istype(H)) - usr << "This can only be done to instances of type /mob/living/carbon/human" - return - - if(alert("Confirm mob type change?",,"Transform","Cancel") != "Transform") return - if(!H) - usr << "Mob doesn't exist anymore" - return - holder.Topic(href, list("makeslime"=href_list["makeslime"])) - else if(href_list["makeai"]) if(!check_rights(R_SPAWN)) return diff --git a/code/modules/clothing/suits/utility.dm b/code/modules/clothing/suits/utility.dm index 9629a53283..7e951f57e1 100644 --- a/code/modules/clothing/suits/utility.dm +++ b/code/modules/clothing/suits/utility.dm @@ -78,7 +78,8 @@ name = "Radiation Hood" icon_state = "rad" desc = "A hood with radiation protective properties. Label: Made with lead, do not eat insulation" - flags_inv = BLOCKHAIR +// flags_inv = BLOCKHAIR + item_flags = THICKMATERIAL body_parts_covered = HEAD|FACE|EYES armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 60, rad = 100) @@ -94,3 +95,4 @@ slowdown = 1.5 armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 60, rad = 100) flags_inv = HIDEJUMPSUIT|HIDETAIL|HIDETIE|HIDEHOLSTER + item_flags = THICKMATERIAL diff --git a/code/modules/examine/stat_icons.dm b/code/modules/examine/stat_icons.dm index 49b511de2e..b2ed64032a 100644 --- a/code/modules/examine/stat_icons.dm +++ b/code/modules/examine/stat_icons.dm @@ -8,6 +8,8 @@ var/global/list/description_icons = list( "radiation_armor" = image(icon='icons/mob/screen1_stats.dmi',icon_state="radiation_protection"), "biohazard_armor" = image(icon='icons/mob/screen1_stats.dmi',icon_state="biohazard_protection"), + "offhand" = image(icon='icons/mob/screen1_stats.dmi',icon_state="offhand"), + "welder" = image(icon='icons/obj/tools.dmi',icon_state="welder"), "wirecutters" = image(icon='icons/obj/tools.dmi',icon_state="cutters"), "screwdriver" = image(icon='icons/obj/tools.dmi',icon_state="screwdriver"), @@ -19,6 +21,12 @@ var/global/list/description_icons = list( "plasteel sheet" = image(icon='icons/obj/items.dmi',icon_state="sheet-plasteel"), "air tank" = image(icon='icons/obj/tank.dmi',icon_state="oxygen"), + "connector" = image(icon='icons/obj/pipes.dmi',icon_state="connector"), - "connector" = image(icon='icons/obj/pipes.dmi',icon_state="connector") + "stunbaton" = image(icon='icons/obj/weapons.dmi',icon_state="stunbaton_active"), + "slimebaton" = image(icon='icons/obj/weapons.dmi',icon_state="slimebaton_active"), + + "power cell" = image(icon='icons/obj/power.dmi',icon_state="hcell"), + "device cell" = image(icon='icons/obj/power.dmi',icon_state="dcell"), + "weapon cell" = image(icon='icons/obj/power.dmi',icon_state="wcell"), ) diff --git a/code/modules/mob/living/bot/bot.dm b/code/modules/mob/living/bot/bot.dm index 971a04bd22..c839b506fa 100644 --- a/code/modules/mob/living/bot/bot.dm +++ b/code/modules/mob/living/bot/bot.dm @@ -128,6 +128,9 @@ ..(message, null, verb) +/mob/living/bot/speech_bubble_appearance() + return "machine" + /mob/living/bot/Bump(var/atom/A) if(on && botcard && istype(A, /obj/machinery/door)) var/obj/machinery/door/D = A @@ -313,6 +316,18 @@ return L +// Similar to above but not restricted to just cardinal directions. +/turf/proc/TurfsWithAccess(var/obj/item/weapon/card/id/ID) + var/L[] = new() + + for(var/d in alldirs) + var/turf/T = get_step(src, d) + if(istype(T) && !T.density) + if(!LinkBlockedWithAccess(src, T, ID)) + L.Add(T) + return L + + // Returns true if a link between A and B is blocked // Movement through doors allowed if ID has access /proc/LinkBlockedWithAccess(turf/A, turf/B, obj/item/weapon/card/id/ID) diff --git a/code/modules/mob/living/bot/secbot.dm b/code/modules/mob/living/bot/secbot.dm index d6a014c450..9e3a266a64 100644 --- a/code/modules/mob/living/bot/secbot.dm +++ b/code/modules/mob/living/bot/secbot.dm @@ -13,6 +13,7 @@ patrol_speed = 2 target_speed = 3 + var/default_icon_state = "secbot" var/idcheck = 0 // If true, arrests for having weapons without authorization. var/check_records = 0 // If true, arrests people without a record. var/check_arrest = 1 // If true, arrests people who are set to arrest. @@ -21,23 +22,44 @@ var/is_ranged = 0 var/awaiting_surrender = 0 + var/can_next_insult = 0 // Uses world.time + var/stun_strength = 60 // For humans. + var/xeno_stun_strength = 0 // For simple mobs. + var/xeno_harm_strength = 15 // Ditto. + var/baton_glow = "#FF6A00" var/list/threat_found_sounds = list('sound/voice/bcriminal.ogg', 'sound/voice/bjustice.ogg', 'sound/voice/bfreeze.ogg') var/list/preparing_arrest_sounds = list('sound/voice/bgod.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/bsecureday.ogg', 'sound/voice/bradio.ogg', 'sound/voice/bcreep.ogg') + var/list/fighting_sounds = list('sound/voice/biamthelaw.ogg', 'sound/voice/bradio.ogg', 'sound/voice/bjustice.ogg') /mob/living/bot/secbot/beepsky name = "Officer Beepsky" desc = "It's Officer Beep O'sky! Powered by a potato and a shot of whiskey." will_patrol = 1 +/mob/living/bot/secbot/slime + name = "Slime Securitron" + desc = "A little security robot, with a slime baton subsituted for the regular one." + default_icon_state = "slimesecbot" + stun_strength = 10 // Slimebatons aren't meant for humans. + xeno_stun_strength = 5 + xeno_harm_strength = 9 + baton_glow = "#33CCFF" + req_one_access = list(access_research, access_robotics) + botcard_access = list(access_research, access_robotics, access_xenobiology, access_xenoarch, access_tox, access_tox_storage, access_maint_tunnels) + +/mob/living/bot/secbot/slime/slimesky + name = "Doctor Slimesky" + desc = "An old friend of Officer Beep O'sky. He prescribes beatings to rowdy slimes so that real doctors don't need to treat the xenobiologists." + /mob/living/bot/secbot/update_icons() if(on && busy) - icon_state = "secbot-c" + icon_state = "[default_icon_state]-c" else - icon_state = "secbot[on]" + icon_state = "[default_icon_state][on]" if(on) - set_light(2, 1, "#FF6A00") + set_light(2, 1, baton_glow) else set_light(0) @@ -114,6 +136,11 @@ if(!target && health < curhealth && shooter && (shooter in view(world.view, src))) react_to_attack(shooter) +/mob/living/bot/secbot/attack_generic(var/mob/attacker) + if(attacker) + react_to_attack(attacker) + ..() + /mob/living/bot/secbot/proc/react_to_attack(mob/attacker) if(!target) playsound(src.loc, pick(threat_found_sounds), 50) @@ -163,6 +190,7 @@ awaiting_surrender = -1 say("Level [threat] infraction alert!") custom_emote(1, "points at [M.name]!") + playsound(src.loc, pick(threat_found_sounds), 50) return /mob/living/bot/secbot/handleAdjacentTarget() @@ -174,9 +202,25 @@ ++awaiting_surrender else if(declare_arrests) - broadcast_security_hud_message("[src] is [arrest_type ? "detaining" : "arresting"] a level [threat] suspect [target_name(target)] in [get_area(src)].", src) + var/action = arrest_type ? "detaining" : "arresting" + if(istype(target, /mob/living/simple_animal)) + action = "fighting" + broadcast_security_hud_message("[src] is [action] a level [threat] [action != "fighting" ? "suspect" : "threat"] [target_name(target)] in [get_area(src)].", src) UnarmedAttack(target) +// So Beepsky talks while beating up simple mobs. +/mob/living/bot/secbot/proc/insult(var/mob/living/L) + if(can_next_insult > world.time) + return + var/threat = check_threat(L) + if(threat >= 10) + playsound(src.loc, 'sound/voice/binsult.ogg', 75) + can_next_insult = world.time + 20 SECONDS + else + playsound(src.loc, pick(fighting_sounds), 75) + can_next_insult = world.time + 5 SECONDS + + /mob/living/bot/secbot/UnarmedAttack(var/mob/M, var/proximity) if(!..()) return @@ -194,7 +238,7 @@ if(!C.lying || C.handcuffed || arrest_type) cuff = 0 if(!cuff) - C.stun_effect_act(0, 60, null) + C.stun_effect_act(0, stun_strength, null) playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1) do_attack_animation(C) busy = 1 @@ -203,6 +247,7 @@ busy = 0 update_icons() visible_message("\The [C] was prodded by \the [src] with a stun baton!") + insult(C) else playsound(loc, 'sound/weapons/handcuffs.ogg', 30, 1, -2) visible_message("\The [src] is trying to put handcuffs on \the [C]!") @@ -214,8 +259,8 @@ busy = 0 else if(istype(M, /mob/living/simple_animal)) var/mob/living/simple_animal/S = M - S.AdjustStunned(10) - S.adjustBruteLoss(15) + S.Weaken(xeno_stun_strength) + S.adjustBruteLoss(xeno_harm_strength) do_attack_animation(M) playsound(loc, "swing_hit", 50, 1, -1) busy = 1 @@ -224,6 +269,15 @@ busy = 0 update_icons() visible_message("\The [M] was beaten by \the [src] with a stun baton!") + insult(S) + +/mob/living/bot/secbot/slime/UnarmedAttack(var/mob/living/L, var/proximity) + ..() + + if(istype(L, /mob/living/simple_animal/slime)) + var/mob/living/simple_animal/slime/S = L + S.adjust_discipline(2) + /mob/living/bot/secbot/explode() @@ -323,8 +377,12 @@ else if(istype(W, /obj/item/weapon/melee/baton) && build_step == 3) user.drop_item() user << "You complete the Securitron! Beep boop." - var/mob/living/bot/secbot/S = new /mob/living/bot/secbot(get_turf(src)) - S.name = created_name + if(istype(W, /obj/item/weapon/melee/baton/slime)) + var/mob/living/bot/secbot/slime/S = new /mob/living/bot/secbot/slime(get_turf(src)) + S.name = created_name + else + var/mob/living/bot/secbot/S = new /mob/living/bot/secbot(get_turf(src)) + S.name = created_name qdel(W) qdel(src) diff --git a/code/modules/mob/living/carbon/brain/brain.dm b/code/modules/mob/living/carbon/brain/brain.dm index 2905b4fe4d..af4093688b 100644 --- a/code/modules/mob/living/carbon/brain/brain.dm +++ b/code/modules/mob/living/carbon/brain/brain.dm @@ -45,7 +45,7 @@ return 1 if (istype(other, /mob/living/carbon/human)) return 1 - if (istype(other, /mob/living/carbon/slime)) + if (istype(other, /mob/living/simple_animal/slime)) return 1 return ..() diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index b432139325..e37be0e032 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -355,6 +355,9 @@ emp_act //this proc handles being hit by a thrown atom /mob/living/carbon/human/hitby(atom/movable/AM as mob|obj,var/speed = THROWFORCE_SPEED_DIVISOR) +// if(buckled && buckled == AM) +// return // Don't get hit by the thing we're buckled to. + if(istype(AM,/obj/)) var/obj/O = AM diff --git a/code/modules/mob/living/carbon/human/say.dm b/code/modules/mob/living/carbon/human/say.dm index c87338d26c..a0276a15ac 100644 --- a/code/modules/mob/living/carbon/human/say.dm +++ b/code/modules/mob/living/carbon/human/say.dm @@ -38,6 +38,15 @@ say(temp) winset(client, "input", "text=[null]") +/mob/living/carbon/human/speech_bubble_appearance() + if(isSynthetic()) + var/datum/robolimb/robo = isSynthetic() + return robo.speech_bubble_appearance + else + if(species) + return species.speech_bubble_appearance + return "normal" + /mob/living/carbon/human/say_understands(var/mob/other,var/datum/language/speaking = null) if(has_brain_worms()) //Brain worms translate everything. Even mice and alien speak. @@ -55,7 +64,7 @@ return 1 if (istype(other, /mob/living/carbon/brain)) return 1 - if (istype(other, /mob/living/carbon/slime)) + if (istype(other, /mob/living/simple_animal/slime)) return 1 //This is already covered by mob/say_understands() diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm index f547cba9fc..9dc3291215 100644 --- a/code/modules/mob/living/carbon/human/species/species.dm +++ b/code/modules/mob/living/carbon/human/species/species.dm @@ -13,6 +13,8 @@ var/icobase = 'icons/mob/human_races/r_human.dmi' // Normal icon set. var/deform = 'icons/mob/human_races/r_def_human.dmi' // Mutated icon set. + var/speech_bubble_appearance = "normal" // Part of icon_state to use for speech bubbles when talking. See talk.dmi for available icons. + // Damage overlay and masks. var/damage_overlays = 'icons/mob/human_races/masks/dam_human.dmi' var/damage_mask = 'icons/mob/human_races/masks/dam_mask_human.dmi' diff --git a/code/modules/mob/living/carbon/human/species/station/prometheans.dm b/code/modules/mob/living/carbon/human/species/station/prometheans.dm index 802cf43154..3a2eb6af49 100644 --- a/code/modules/mob/living/carbon/human/species/station/prometheans.dm +++ b/code/modules/mob/living/carbon/human/species/station/prometheans.dm @@ -28,6 +28,8 @@ var/datum/species/shapeshifter/promethean/prometheans breath_type = null poison_type = null + speech_bubble_appearance = "slime" + male_cough_sounds = list('sound/effects/slime_squish.ogg') female_cough_sounds = list('sound/effects/slime_squish.ogg') diff --git a/code/modules/mob/living/carbon/metroid/items.dm b/code/modules/mob/living/carbon/metroid/items.dm index c59c6826d5..db66524a29 100644 --- a/code/modules/mob/living/carbon/metroid/items.dm +++ b/code/modules/mob/living/carbon/metroid/items.dm @@ -9,27 +9,27 @@ throw_speed = 3 throw_range = 6 origin_tech = list(TECH_BIO = 4) - var/Uses = 1 // uses before it goes inert + var/uses = 1 // uses before it goes inert var/enhanced = 0 //has it been enhanced before? flags = OPENCONTAINER - - attackby(obj/item/O as obj, mob/user as mob) - if(istype(O, /obj/item/weapon/slimesteroid2)) - if(enhanced == 1) - user << " This extract has already been enhanced!" - return ..() - if(Uses == 0) - user << " You can't enhance a used extract!" - return ..() - user <<"You apply the enhancer. It now has triple the amount of uses." - Uses = 3 - enhanced = 1 - qdel(O) - +/* +/obj/item/slime_extract/attackby(obj/item/O as obj, mob/user as mob) + if(istype(O, /obj/item/weapon/slimesteroid2)) + if(enhanced == 1) + user << " This extract has already been enhanced!" + return ..() + if(Uses == 0) + user << " You can't enhance a used extract!" + return ..() + user <<"You apply the enhancer. It now has triple the amount of uses." + Uses = 3 + enhanced = 1 + qdel(O) +*/ /obj/item/slime_extract/New() ..() - create_reagents(100) - reagents.add_reagent("slimejelly", 30) + create_reagents(5) +// reagents.add_reagent("slimejelly", 30) /obj/item/slime_extract/grey name = "grey slime extract" @@ -51,7 +51,7 @@ name = "purple slime extract" icon_state = "purple slime extract" -/obj/item/slime_extract/darkpurple +/obj/item/slime_extract/dark_purple name = "dark purple slime extract" icon_state = "dark purple slime extract" @@ -71,7 +71,7 @@ name = "blue slime extract" icon_state = "blue slime extract" -/obj/item/slime_extract/darkblue +/obj/item/slime_extract/dark_blue name = "dark blue slime extract" icon_state = "dark blue slime extract" @@ -119,41 +119,66 @@ name = "rainbow slime extract" icon_state = "rainbow slime extract" -////Pet Slime Creation/// +/obj/item/slimepotion + icon = 'icons/obj/chemical.dmi' -/obj/item/weapon/slimepotion +////Pet Slime Creation/// +/* +/obj/item/slimepotion/docility name = "docility potion" desc = "A potent chemical mix that will nullify a slime's powers, causing it to become docile and tame." - icon = 'icons/obj/chemical.dmi' icon_state = "bottle19" - attack(mob/living/carbon/slime/M as mob, mob/user as mob) - if(!istype(M, /mob/living/carbon/slime))//If target is not a slime. - user << " The potion only works on baby slimes!" - return ..() - if(M.is_adult) //Can't tame adults - user << " Only baby slimes can be tamed!" - return..() - if(M.stat) - user << " The slime is dead!" - return..() - if(M.mind) - user << " The slime resists!" - return ..() - var/mob/living/simple_animal/slime/pet = new /mob/living/simple_animal/slime(M.loc) - pet.icon_state = "[M.colour] baby slime" - pet.icon_living = "[M.colour] baby slime" - pet.icon_dead = "[M.colour] baby slime dead" - pet.colour = "[M.colour]" - user <<"You feed the slime the potion, removing it's powers and calming it." - qdel(M) - var/newname = sanitize(input(user, "Would you like to give the slime a name?", "Name your new pet", "pet slime") as null|text, MAX_NAME_LEN) +/obj/item/slimepotion/docility/attack(mob/living/carbon/slime/M as mob, mob/user as mob) + if(!istype(M, /mob/living/carbon/slime))//If target is not a slime. + user << " The potion only works on slimes!" + return ..() +// if(M.is_adult) //Can't tame adults +// user << " Only baby slimes can be tamed!" +// return..() + if(M.stat) + user << " The slime is dead!" + return..() + if(M.mind) + user << " The slime resists!" + return ..() + var/mob/living/simple_animal/slime/pet = new /mob/living/simple_animal/slime(M.loc) + pet.icon_state = "[M.colour] [M.is_adult ? "adult" : "baby"] slime" + pet.icon_living = "[M.colour] [M.is_adult ? "adult" : "baby"] slime" + pet.icon_dead = "[M.colour] [M.is_adult ? "adult" : "baby"] slime dead" + pet.colour = "[M.colour]" + to_chat(user, "You feed the slime the potion, removing it's powers and calming it.") + + qdel(M) + + var/newname = sanitize(input(user, "Would you like to give the slime a name?", "Name your new pet", "pet slime") as null|text, MAX_NAME_LEN) + + if (!newname) + newname = "pet slime" + pet.name = newname + pet.real_name = newname + qdel(src) + +/obj/item/slimepotion/stabilizer + name = "slime stabilizer" + desc = "A potent chemical mix that will reduce the chance of a slime mutating." + icon_state = "potcyan" + +/obj/item/slimepotion/stabilizer/attack(mob/living/carbon/slime/M, mob/user) + if(!isslime(M)) + to_chat(user, "The stabilizer only works on slimes!") + return ..() + if(M.stat) + to_chat(user, "The slime is dead!") + return ..() + if(M.mutation_chance == 0) + to_chat(user, "The slime already has no chance of mutating!") + return ..() + + to_chat(user, "You feed the slime the stabilizer. It is now less likely to mutate.") + M.mutation_chance = Clamp(M.mutation_chance-15,0,100) + qdel(src) - if (!newname) - newname = "pet slime" - pet.name = newname - pet.real_name = newname - qdel(src) /obj/item/weapon/slimepotion2 name = "advanced docility potion" @@ -187,7 +212,7 @@ qdel(src) -/obj/item/weapon/slimesteroid +/obj/item/slimesteroid name = "slime steroid" desc = "A potent chemical mix that will cause a slime to generate more extract." icon = 'icons/obj/chemical.dmi' @@ -211,7 +236,7 @@ M.cores = 3 qdel(src) -/obj/item/weapon/slimesteroid2 +/obj/item/slimesteroid2 name = "extract enhancer" desc = "A potent chemical mix that will give a slime extract three uses." icon = 'icons/obj/chemical.dmi' @@ -229,7 +254,7 @@ target.Uses = 3 target.enahnced = 1 qdel(src)*/ - +*/ /obj/effect/golemrune anchored = 1 desc = "a strange rune used to create golems. It glows when spirits are nearby." diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 8880efe0da..c313b1482c 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -90,9 +90,6 @@ default behaviour is: forceMove(tmob.loc) tmob.forceMove(oldloc) now_pushing = 0 - for(var/mob/living/carbon/slime/slime in view(1,tmob)) - if(slime.Victim == tmob) - slime.UpdateFeed() return if(!can_move_mob(tmob, 0, 0)) @@ -571,7 +568,8 @@ default behaviour is: fire_stacks = 0 /mob/living/proc/rejuvenate() - reagents.clear_reagents() + if(reagents) + reagents.clear_reagents() // shut down various types of badness setToxLoss(0) @@ -642,8 +640,17 @@ default behaviour is: return /mob/living/Move(a, b, flag) - if (buckled) - return +// if (buckled) +// world << "[src].Move() failed; buckled." +// return + + if (buckled && buckled.loc != a) //not updating position + if (!buckled.anchored) + world << "[src].Move(); will return [buckled].Move ." + return buckled.Move(a, b) + else + world << "[src].Move() failed; buckled to anchored [buckled]." + return 0 if (restrained()) stop_pulling() @@ -724,10 +731,6 @@ default behaviour is: if (s_active && !( s_active in contents ) && get_turf(s_active) != get_turf(src)) //check !( s_active in contents ) first so we hopefully don't have to call get_turf() so much. s_active.close(src) - if(update_slimes) - for(var/mob/living/carbon/slime/M in view(1,src)) - M.UpdateFeed(src) - /mob/living/proc/handle_footstep(turf/T) return FALSE diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index 80c0dbc505..dea3c82461 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -298,7 +298,8 @@ proc/get_radio_key_from_channel(var/channel) //The 'post-say' static speech bubble var/speech_bubble_test = say_test(message) - var/image/speech_bubble = image('icons/mob/talk.dmi',src,"h[speech_bubble_test]") + var/speech_type = speech_bubble_appearance() + var/image/speech_bubble = image('icons/mob/talk.dmi',src,"[speech_type][speech_bubble_test]") spawn(30) qdel(speech_bubble) //Main 'say' and 'whisper' message delivery @@ -341,3 +342,6 @@ proc/get_radio_key_from_channel(var/channel) /mob/living/proc/GetVoice() return name + +/mob/proc/speech_bubble_appearance() + return "normal" diff --git a/code/modules/mob/living/silicon/robot/drone/drone_items.dm b/code/modules/mob/living/silicon/robot/drone/drone_items.dm index 7a107d1d0e..87c36b5ac4 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone_items.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone_items.dm @@ -76,11 +76,14 @@ /obj/item/weapon/disk, /obj/item/weapon/circuitboard, /obj/item/weapon/reagent_containers/glass, - /obj/item/weapon/reagent_containers/food/snacks/monkeycube, - /obj/item/xenoproduct/slime/core, /obj/item/device/assembly/prox_sensor, - /obj/item/device/healthanalyzer //to build medibots -// /obj/item/slime_extract, ### Outdated + /obj/item/device/healthanalyzer, //to build medibots + /obj/item/slime_cube, + /obj/item/slime_crystal, + /obj/item/weapon/disposable_teleporter/slime, + /obj/item/slimepotion, + /obj/item/slime_extract, + /obj/item/weapon/reagent_containers/food/snacks/monkeycube, ) diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm index de9517fd0c..70bf0c7475 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -720,6 +720,8 @@ var/global/list/robot_modules = list( src.modules += new /obj/item/weapon/reagent_containers/glass/beaker/large(src) src.modules += new /obj/item/weapon/storage/part_replacer(src) src.modules += new /obj/item/weapon/shockpaddles/robot/jumper(src) + src.modules += new /obj/item/weapon/melee/baton/slime/robot(src) + src.modules += new /obj/item/weapon/gun/energy/taser/xeno/robot(src) src.emag = new /obj/item/weapon/hand_tele(src) var/datum/matter_synth/nanite = new /datum/matter_synth/nanite(10000) diff --git a/code/modules/mob/living/silicon/say.dm b/code/modules/mob/living/silicon/say.dm index 8b721bc24b..359ee492f2 100644 --- a/code/modules/mob/living/silicon/say.dm +++ b/code/modules/mob/living/silicon/say.dm @@ -14,6 +14,9 @@ message_mode = null return radio.talk_into(src,message,message_mode,verb,speaking) +/mob/living/silicon/speech_bubble_appearance() + return "synthetic" + /mob/living/silicon/ai/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name) ..() if(message_mode == "department") diff --git a/code/modules/mob/living/simple_animal/aliens/alien.dm b/code/modules/mob/living/simple_animal/aliens/alien.dm index 7748559017..52f9121855 100644 --- a/code/modules/mob/living/simple_animal/aliens/alien.dm +++ b/code/modules/mob/living/simple_animal/aliens/alien.dm @@ -8,6 +8,7 @@ icon_gib = "syndicate_gib" faction = "xeno" + intelligence_level = SA_HUMANOID cooperative = 1 run_at_them = 0 diff --git a/code/modules/mob/living/simple_animal/aliens/creature.dm b/code/modules/mob/living/simple_animal/aliens/creature.dm index 544a44d001..3de6d687af 100644 --- a/code/modules/mob/living/simple_animal/aliens/creature.dm +++ b/code/modules/mob/living/simple_animal/aliens/creature.dm @@ -7,6 +7,7 @@ icon_dead = "otherthing-dead" faction = "creature" + intelligence_level = SA_ANIMAL maxHealth = 40 health = 40 speed = 8 diff --git a/code/modules/mob/living/simple_animal/aliens/drone.dm b/code/modules/mob/living/simple_animal/aliens/drone.dm index 3c550e862f..2a41e81667 100644 --- a/code/modules/mob/living/simple_animal/aliens/drone.dm +++ b/code/modules/mob/living/simple_animal/aliens/drone.dm @@ -8,6 +8,7 @@ icon_dead = "drone_dead" faction = "malf_drone" + intelligence_level = SA_ROBOTIC maxHealth = 300 health = 300 speed = 8 diff --git a/code/modules/mob/living/simple_animal/aliens/faithless.dm b/code/modules/mob/living/simple_animal/aliens/faithless.dm index 0b41471c32..24eacae40e 100644 --- a/code/modules/mob/living/simple_animal/aliens/faithless.dm +++ b/code/modules/mob/living/simple_animal/aliens/faithless.dm @@ -6,6 +6,7 @@ icon_dead = "faithless_dead" faction = "faithless" + intelligence_level = SA_HUMANOID maxHealth = 50 health = 50 speed = 8 @@ -14,7 +15,7 @@ response_help = "passes through" response_disarm = "shoves" response_harm = "hits" - + harm_intent_damage = 10 melee_damage_lower = 5 melee_damage_upper = 5 diff --git a/code/modules/mob/living/simple_animal/aliens/hivebot.dm b/code/modules/mob/living/simple_animal/aliens/hivebot.dm index 6b15830b9a..d3193adfb6 100644 --- a/code/modules/mob/living/simple_animal/aliens/hivebot.dm +++ b/code/modules/mob/living/simple_animal/aliens/hivebot.dm @@ -7,6 +7,7 @@ icon_dead = "basic" faction = "hivebot" + intelligence_level = SA_ROBOTIC maxHealth = 15 health = 15 speed = 4 diff --git a/code/modules/mob/living/simple_animal/aliens/mimic.dm b/code/modules/mob/living/simple_animal/aliens/mimic.dm index 3373760bf8..b79b524875 100644 --- a/code/modules/mob/living/simple_animal/aliens/mimic.dm +++ b/code/modules/mob/living/simple_animal/aliens/mimic.dm @@ -10,6 +10,7 @@ icon_living = "crate" faction = "mimic" + intelligence_level = SA_ANIMAL maxHealth = 250 health = 250 diff --git a/code/modules/mob/living/simple_animal/aliens/shade.dm b/code/modules/mob/living/simple_animal/aliens/shade.dm index f1b227436e..2d502bc10a 100644 --- a/code/modules/mob/living/simple_animal/aliens/shade.dm +++ b/code/modules/mob/living/simple_animal/aliens/shade.dm @@ -8,6 +8,7 @@ icon_dead = "shade_dead" faction = "cult" + intelligence_level = SA_HUMANOID maxHealth = 50 health = 50 diff --git a/code/modules/mob/living/simple_animal/animals/bat.dm b/code/modules/mob/living/simple_animal/animals/bat.dm index 1d722c0b8a..a429b2ca7f 100644 --- a/code/modules/mob/living/simple_animal/animals/bat.dm +++ b/code/modules/mob/living/simple_animal/animals/bat.dm @@ -8,6 +8,7 @@ icon_gib = "bat_dead" faction = "scarybat" + intelligence_level = SA_ANIMAL maxHealth = 20 health = 20 diff --git a/code/modules/mob/living/simple_animal/animals/bear.dm b/code/modules/mob/living/simple_animal/animals/bear.dm index 228e92e5b7..ea8398afc2 100644 --- a/code/modules/mob/living/simple_animal/animals/bear.dm +++ b/code/modules/mob/living/simple_animal/animals/bear.dm @@ -8,6 +8,7 @@ icon_gib = "bear_gib" faction = "russian" + intelligence_level = SA_ANIMAL cooperative = 1 maxHealth = 60 diff --git a/code/modules/mob/living/simple_animal/animals/carp.dm b/code/modules/mob/living/simple_animal/animals/carp.dm index b8813c8a61..ff626e5eab 100644 --- a/code/modules/mob/living/simple_animal/animals/carp.dm +++ b/code/modules/mob/living/simple_animal/animals/carp.dm @@ -7,6 +7,7 @@ icon_gib = "carp_gib" faction = "carp" + intelligence_level = SA_ANIMAL maxHealth = 25 health = 25 speed = 4 diff --git a/code/modules/mob/living/simple_animal/animals/cat.dm b/code/modules/mob/living/simple_animal/animals/cat.dm index 9b3df51247..b1c1cefb5f 100644 --- a/code/modules/mob/living/simple_animal/animals/cat.dm +++ b/code/modules/mob/living/simple_animal/animals/cat.dm @@ -2,6 +2,7 @@ /mob/living/simple_animal/cat name = "cat" desc = "A domesticated, feline pet. Has a tendency to adopt crewmembers." + intelligence_level = SA_ANIMAL icon_state = "cat2" item_state = "cat2" icon_living = "cat2" diff --git a/code/modules/mob/living/simple_animal/animals/corgi.dm b/code/modules/mob/living/simple_animal/animals/corgi.dm index 1823c5a91e..4be02a9b0b 100644 --- a/code/modules/mob/living/simple_animal/animals/corgi.dm +++ b/code/modules/mob/living/simple_animal/animals/corgi.dm @@ -3,6 +3,7 @@ name = "\improper corgi" real_name = "corgi" desc = "It's a corgi." + intelligence_level = SA_ANIMAL icon_state = "corgi" icon_living = "corgi" icon_dead = "corgi_dead" diff --git a/code/modules/mob/living/simple_animal/animals/crab.dm b/code/modules/mob/living/simple_animal/animals/crab.dm index acb95ac64c..acad7f6378 100644 --- a/code/modules/mob/living/simple_animal/animals/crab.dm +++ b/code/modules/mob/living/simple_animal/animals/crab.dm @@ -5,6 +5,7 @@ icon_state = "crab" icon_living = "crab" icon_dead = "crab_dead" + intelligence_level = SA_ANIMAL wander = 0 stop_automated_movement = 1 diff --git a/code/modules/mob/living/simple_animal/animals/farm_animals.dm b/code/modules/mob/living/simple_animal/animals/farm_animals.dm index adc4fe83bf..2fe58dc76f 100644 --- a/code/modules/mob/living/simple_animal/animals/farm_animals.dm +++ b/code/modules/mob/living/simple_animal/animals/farm_animals.dm @@ -7,6 +7,7 @@ icon_dead = "goat_dead" faction = "goat" + intelligence_level = SA_ANIMAL health = 40 turns_per_move = 5 @@ -88,6 +89,7 @@ icon_living = "cow" icon_dead = "cow_dead" icon_gib = "cow_gib" + intelligence_level = SA_ANIMAL health = 50 turns_per_move = 5 @@ -155,6 +157,7 @@ icon_living = "chick" icon_dead = "chick_dead" icon_gib = "chick_gib" + intelligence_level = SA_ANIMAL health = 1 turns_per_move = 2 @@ -203,6 +206,7 @@ var/global/chicken_count = 0 icon_state = "chicken" icon_living = "chicken" icon_dead = "chicken_dead" + intelligence_level = SA_ANIMAL health = 10 turns_per_move = 3 diff --git a/code/modules/mob/living/simple_animal/animals/fish.dm b/code/modules/mob/living/simple_animal/animals/fish.dm index b2778d3c33..dbbd12a9a3 100644 --- a/code/modules/mob/living/simple_animal/animals/fish.dm +++ b/code/modules/mob/living/simple_animal/animals/fish.dm @@ -4,6 +4,7 @@ desc = "Its a fishy. No touchy fishy." icon = 'icons/mob/fish.dmi' meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat + intelligence_level = SA_ANIMAL // By defautl they can be in any water turf. Subtypes might restrict to deep/shallow etc var/global/list/suitable_turf_types = list( diff --git a/code/modules/mob/living/simple_animal/animals/giant_spider.dm b/code/modules/mob/living/simple_animal/animals/giant_spider.dm index 5cb191726f..7359763e15 100644 --- a/code/modules/mob/living/simple_animal/animals/giant_spider.dm +++ b/code/modules/mob/living/simple_animal/animals/giant_spider.dm @@ -13,6 +13,7 @@ icon_dead = "guard_dead" faction = "spiders" + intelligence_level = SA_ANIMAL maxHealth = 200 health = 200 pass_flags = PASSTABLE diff --git a/code/modules/mob/living/simple_animal/animals/goose.dm b/code/modules/mob/living/simple_animal/animals/goose.dm index ded7c5214a..3b3e3bfa21 100644 --- a/code/modules/mob/living/simple_animal/animals/goose.dm +++ b/code/modules/mob/living/simple_animal/animals/goose.dm @@ -7,6 +7,7 @@ icon_gib = "generic_gib" faction = "geese" + intelligence_level = SA_ANIMAL maxHealth = 15 health = 15 diff --git a/code/modules/mob/living/simple_animal/animals/lizard.dm b/code/modules/mob/living/simple_animal/animals/lizard.dm index 5c986d21bb..e9032a96ef 100644 --- a/code/modules/mob/living/simple_animal/animals/lizard.dm +++ b/code/modules/mob/living/simple_animal/animals/lizard.dm @@ -5,6 +5,7 @@ icon_state = "lizard" icon_living = "lizard" icon_dead = "lizard-dead" + intelligence_level = SA_ANIMAL health = 5 maxHealth = 5 diff --git a/code/modules/mob/living/simple_animal/animals/mouse.dm b/code/modules/mob/living/simple_animal/animals/mouse.dm index 68c54b3d38..4f0cbb9162 100644 --- a/code/modules/mob/living/simple_animal/animals/mouse.dm +++ b/code/modules/mob/living/simple_animal/animals/mouse.dm @@ -6,6 +6,7 @@ item_state = "mouse_gray" icon_living = "mouse_gray" icon_dead = "mouse_gray_dead" + intelligence_level = SA_ANIMAL maxHealth = 5 health = 5 diff --git a/code/modules/mob/living/simple_animal/animals/parrot.dm b/code/modules/mob/living/simple_animal/animals/parrot.dm index 73892b26a1..1e17212708 100644 --- a/code/modules/mob/living/simple_animal/animals/parrot.dm +++ b/code/modules/mob/living/simple_animal/animals/parrot.dm @@ -35,6 +35,7 @@ icon_state = "parrot_fly" icon_living = "parrot_fly" icon_dead = "parrot_dead" + intelligence_level = SA_ANIMAL turns_per_move = 5 pass_flags = PASSTABLE diff --git a/code/modules/mob/living/simple_animal/animals/penguin.dm b/code/modules/mob/living/simple_animal/animals/penguin.dm index 90074edef5..09adf4ed41 100644 --- a/code/modules/mob/living/simple_animal/animals/penguin.dm +++ b/code/modules/mob/living/simple_animal/animals/penguin.dm @@ -5,6 +5,7 @@ icon_living = "penguin" icon_dead = "penguin_dead" icon_gib = "generic_gib" + intelligence_level = SA_ANIMAL maxHealth = 20 health = 20 diff --git a/code/modules/mob/living/simple_animal/animals/spiderbot.dm b/code/modules/mob/living/simple_animal/animals/spiderbot.dm index 79e796d7ff..fbbebff081 100644 --- a/code/modules/mob/living/simple_animal/animals/spiderbot.dm +++ b/code/modules/mob/living/simple_animal/animals/spiderbot.dm @@ -5,6 +5,7 @@ icon_state = "spiderbot-chassis" icon_living = "spiderbot-chassis" icon_dead = "spiderbot-smashed" + intelligence_level = SA_HUMANOID // Because its piloted by players. health = 10 maxHealth = 10 diff --git a/code/modules/mob/living/simple_animal/animals/tomato.dm b/code/modules/mob/living/simple_animal/animals/tomato.dm index ea133a8581..d1bffc6fe1 100644 --- a/code/modules/mob/living/simple_animal/animals/tomato.dm +++ b/code/modules/mob/living/simple_animal/animals/tomato.dm @@ -4,6 +4,7 @@ icon_state = "tomato" icon_living = "tomato" icon_dead = "tomato_dead" + intelligence_level = SA_PLANT faction = "plants" maxHealth = 15 diff --git a/code/modules/mob/living/simple_animal/animals/tree.dm b/code/modules/mob/living/simple_animal/animals/tree.dm index bf97641248..7d31e46772 100644 --- a/code/modules/mob/living/simple_animal/animals/tree.dm +++ b/code/modules/mob/living/simple_animal/animals/tree.dm @@ -6,6 +6,7 @@ icon_living = "pine_1" icon_dead = "pine_1" icon_gib = "pine_1" + intelligence_level = SA_PLANT faction = "carp" //Trees can be carp friends? maxHealth = 250 diff --git a/code/modules/mob/living/simple_animal/animals/worm.dm b/code/modules/mob/living/simple_animal/animals/worm.dm index dfb8a5a195..48ed6039c5 100644 --- a/code/modules/mob/living/simple_animal/animals/worm.dm +++ b/code/modules/mob/living/simple_animal/animals/worm.dm @@ -5,6 +5,7 @@ icon_state = "spaceworm" icon_living = "spaceworm" icon_dead = "spacewormdead" + intelligence_level = SA_ANIMAL maxHealth = 30 diff --git a/code/modules/mob/living/simple_animal/borer/borer.dm b/code/modules/mob/living/simple_animal/borer/borer.dm index 7498c83a7a..e18a345066 100644 --- a/code/modules/mob/living/simple_animal/borer/borer.dm +++ b/code/modules/mob/living/simple_animal/borer/borer.dm @@ -4,6 +4,7 @@ desc = "A small, quivering sluglike creature." speak_emote = list("chirrups") emote_hear = list("chirrups") + intelligence_level = SA_HUMANOID // Player controlled. response_help = "pokes" response_disarm = "prods" response_harm = "stomps on" diff --git a/code/modules/mob/living/simple_animal/constructs/constructs.dm b/code/modules/mob/living/simple_animal/constructs/constructs.dm index 0159e4ab5f..f386016c17 100644 --- a/code/modules/mob/living/simple_animal/constructs/constructs.dm +++ b/code/modules/mob/living/simple_animal/constructs/constructs.dm @@ -7,6 +7,7 @@ response_help = "thinks better of touching" response_disarm = "flailed at" response_harm = "punched" + intelligence_level = SA_HUMANOID // Player controlled. icon_dead = "shade_dead" speed = -1 a_intent = I_HURT diff --git a/code/modules/mob/living/simple_animal/humanoids/clown.dm b/code/modules/mob/living/simple_animal/humanoids/clown.dm index 5bf310b165..ee1341ff38 100644 --- a/code/modules/mob/living/simple_animal/humanoids/clown.dm +++ b/code/modules/mob/living/simple_animal/humanoids/clown.dm @@ -5,6 +5,7 @@ icon_living = "clown" icon_dead = "clown_dead" icon_gib = "clown_gib" + intelligence_level = SA_HUMANOID faction = "clown" maxHealth = 75 diff --git a/code/modules/mob/living/simple_animal/humanoids/head.dm b/code/modules/mob/living/simple_animal/humanoids/head.dm index f0e8b8abde..22460f0990 100644 --- a/code/modules/mob/living/simple_animal/humanoids/head.dm +++ b/code/modules/mob/living/simple_animal/humanoids/head.dm @@ -5,6 +5,7 @@ icon_state = "crab" icon_living = "crab" icon_dead = "crab_dead" + intelligence_level = SA_ANIMAL wander = 0 stop_automated_movement = 1 diff --git a/code/modules/mob/living/simple_animal/humanoids/kobold.dm b/code/modules/mob/living/simple_animal/humanoids/kobold.dm index 8f3ce0d28c..7355fce470 100644 --- a/code/modules/mob/living/simple_animal/humanoids/kobold.dm +++ b/code/modules/mob/living/simple_animal/humanoids/kobold.dm @@ -6,6 +6,7 @@ icon_state = "kobold_idle" icon_living = "kobold_idle" icon_dead = "kobold_dead" + intelligence_level = SA_HUMANOID run_at_them = 0 cooperative = 1 diff --git a/code/modules/mob/living/simple_animal/humanoids/mechamobs.dm b/code/modules/mob/living/simple_animal/humanoids/mechamobs.dm index ae700d60b7..3cfafda91a 100644 --- a/code/modules/mob/living/simple_animal/humanoids/mechamobs.dm +++ b/code/modules/mob/living/simple_animal/humanoids/mechamobs.dm @@ -5,6 +5,7 @@ icon_state = "darkgygax" icon_living = "darkgygax" icon_dead = "darkgygax-broken" + intelligence_level = SA_HUMANOID // Piloted by a human. faction = "syndicate" maxHealth = 300 diff --git a/code/modules/mob/living/simple_animal/humanoids/pirate.dm b/code/modules/mob/living/simple_animal/humanoids/pirate.dm index 02d1a8eb72..f0c7c05ddc 100644 --- a/code/modules/mob/living/simple_animal/humanoids/pirate.dm +++ b/code/modules/mob/living/simple_animal/humanoids/pirate.dm @@ -4,6 +4,7 @@ icon_state = "piratemelee" icon_living = "piratemelee" icon_dead = "piratemelee_dead" + intelligence_level = SA_HUMANOID faction = "pirate" maxHealth = 100 diff --git a/code/modules/mob/living/simple_animal/humanoids/russian.dm b/code/modules/mob/living/simple_animal/humanoids/russian.dm index 96ff3a5177..1589fe2a7d 100644 --- a/code/modules/mob/living/simple_animal/humanoids/russian.dm +++ b/code/modules/mob/living/simple_animal/humanoids/russian.dm @@ -5,6 +5,7 @@ icon_living = "russianmelee" icon_dead = "russianmelee_dead" icon_gib = "syndicate_gib" + intelligence_level = SA_HUMANOID faction = "russian" maxHealth = 100 diff --git a/code/modules/mob/living/simple_animal/humanoids/syndicate.dm b/code/modules/mob/living/simple_animal/humanoids/syndicate.dm index 6dbe2fcfa4..edc46025a9 100644 --- a/code/modules/mob/living/simple_animal/humanoids/syndicate.dm +++ b/code/modules/mob/living/simple_animal/humanoids/syndicate.dm @@ -5,6 +5,7 @@ icon_living = "syndicate" icon_dead = "syndicate_dead" icon_gib = "syndicate_gib" + intelligence_level = SA_HUMANOID faction = "syndicate" maxHealth = 100 @@ -165,6 +166,7 @@ icon = 'icons/mob/critter.dmi' icon_state = "viscerator_attack" icon_living = "viscerator_attack" + intelligence_level = SA_ROBOTIC faction = "syndicate" maxHealth = 15 diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 39f272a8e8..b915411544 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -17,11 +17,12 @@ var/show_stat_health = 1 // Does the percentage health show in the stat panel for the mob var/ai_inactive = 0 // Set to 1 to turn off most AI actions - //Mob icon settings + //Mob icon/appearance settings var/icon_living = "" // The iconstate if we're alive, required var/icon_dead = "" // The iconstate if we're dead, required var/icon_gib = null // The iconstate for being gibbed, optional var/icon_rest = null // The iconstate for resting, optional + var/image/modifier_overlay = null // Holds overlays from modifiers. //Mob talking settings universal_speak = 0 // Can all mobs in the entire universe understand this one? @@ -59,6 +60,7 @@ var/list/loot_list = list() // The list of lootable objects to drop, with "/path = prob%" structure var/recruitable = 0 // Mob can be bossed around var/recruit_cmd_str = "Hey," // The thing you prefix commands with when bossing them around + var/intelligence_level = SA_ANIMAL// How 'smart' the mob is ICly, used to deliniate between animal, robot, and humanoid SAs. //Mob environment settings var/minbodytemp = 250 // Minimum "okay" temperature in kelvin @@ -116,6 +118,7 @@ var/run_at_them = 1 // Don't use A* pathfinding, use walk_to var/move_to_delay = 4 // Delay for the automated movement (deciseconds) var/destroy_surroundings = 1 // Should I smash things to get to my target? + var/astar_adjacent_proc = /turf/proc/CardinalTurfsWithAccess // Proc to use when A* pathfinding. Default makes them bound to cardinals. //Damage resistances var/resistance = 0 // Damage reduction for all types @@ -205,6 +208,7 @@ src.client.screen += src.client.void ai_inactive = 1 handle_stance(STANCE_IDLE) + LoseTarget() src.client << "Mob AI disabled while you are controlling the mob." ..() @@ -241,11 +245,11 @@ /mob/living/simple_animal/update_icon() ..() //Awake and normal - if((stat == CONSCIOUS) && (!icon_rest || !resting)) + if((stat == CONSCIOUS) && (!icon_rest || !resting || !incapacitated(INCAPACITATION_DISABLED) )) icon_state = icon_living //Resting or KO'd - else if(((stat == UNCONSCIOUS) || resting) && icon_rest) + else if(((stat == UNCONSCIOUS) || resting || incapacitated(INCAPACITATION_DISABLED) ) && icon_rest) icon_state = icon_rest //Dead @@ -256,6 +260,26 @@ else icon_state = initial(icon_state) +// If your simple mob's update_icon() call calls overlays.Cut(), this needs to be called after this, or manually apply modifier_overly to overlays. +/mob/living/simple_animal/update_modifier_visuals() + var/image/effects = null + if(modifier_overlay) + overlays -= modifier_overlay + modifier_overlay.overlays.Cut() + effects = modifier_overlay + else + effects = new() + + for(var/datum/modifier/M in modifiers) + if(M.mob_overlay_state) + var/image/I = image("icon" = 'icons/mob/modifier_effects.dmi', "icon_state" = M.mob_overlay_state) + I.appearance_flags = RESET_COLOR // So colored mobs don't affect the overlay. + effects.overlays += I + + modifier_overlay = effects + overlays += modifier_overlay + + /mob/living/simple_animal/Life() ..() @@ -288,7 +312,7 @@ //Resisting out buckles if(stance != STANCE_IDLE && incapacitated(INCAPACITATION_BUCKLED_PARTIALLY)) - resist() + handle_resist() //Resisting out of closets if(istype(loc,/obj/structure/closet)) @@ -300,6 +324,11 @@ return 1 +// Resists out of things. +// Sometimes there are times you want SAs to be buckled to something, so override this for when that is needed. +/mob/living/simple_animal/proc/handle_resist() + resist() + // Peforms the random walk wandering /mob/living/simple_animal/proc/handle_wander_movement() if(isturf(src.loc) && !resting && !buckled && canmove) //Physically capable of moving? @@ -482,6 +511,8 @@ if(Proj.firer) react_to_attack(Proj.firer) + Proj.on_hit(src) + return 0 // When someone clicks us with an empty hand @@ -550,11 +581,9 @@ if(istype(O, /obj/item/weapon/material/knife) || istype(O, /obj/item/weapon/material/knife/butch)) harvest(user) else - if(!O.force) - visible_message("[user] gently taps [src] with \the [O].") - else - O.attack(src, user, user.zone_sel.selecting) - ai_log("attackby() I was weapon'd by: [user]",2) + O.attack(src, user, user.zone_sel.selecting) + ai_log("attackby() I was weapon'd by: [user]",2) + if(O.force) react_to_attack(user) /mob/living/simple_animal/hit_with_weapon(obj/item/O, mob/living/user, var/effective_force, var/hit_zone) @@ -645,18 +674,58 @@ if(3.0) adjustBruteLoss(30) +// Don't understand why simple animals don't use the regular /mob/living health system. /mob/living/simple_animal/adjustBruteLoss(damage) + if(damage > 0) + for(var/datum/modifier/M in modifiers) + if(!isnull(M.incoming_damage_percent)) + damage *= M.incoming_damage_percent + if(!isnull(M.incoming_brute_damage_percent)) + damage *= M.incoming_brute_damage_percent + else if(damage < 0) + for(var/datum/modifier/M in modifiers) + if(!isnull(M.incoming_healing_percent)) + damage *= M.incoming_healing_percent + health = Clamp(health - damage, 0, getMaxHealth()) + updatehealth() /mob/living/simple_animal/adjustFireLoss(damage) + if(damage > 0) + for(var/datum/modifier/M in modifiers) + if(!isnull(M.incoming_damage_percent)) + damage *= M.incoming_damage_percent + if(!isnull(M.incoming_fire_damage_percent)) + damage *= M.incoming_brute_damage_percent + else if(damage < 0) + for(var/datum/modifier/M in modifiers) + if(!isnull(M.incoming_healing_percent)) + damage *= M.incoming_healing_percent + health = Clamp(health - damage, 0, getMaxHealth()) + updatehealth() + +/mob/living/simple_animal/adjustToxLoss(damage) + if(damage > 0) + for(var/datum/modifier/M in modifiers) + if(!isnull(M.incoming_damage_percent)) + damage *= M.incoming_damage_percent + if(!isnull(M.incoming_tox_damage_percent)) + damage *= M.incoming_brute_damage_percent + else if(damage < 0) + for(var/datum/modifier/M in modifiers) + if(!isnull(M.incoming_healing_percent)) + damage *= M.incoming_healing_percent + + health = Clamp(health - damage, 0, getMaxHealth()) + updatehealth() // Check target_mob if worthy of attack (i.e. check if they are dead or empty mecha) /mob/living/simple_animal/proc/SA_attackable(target_mob) ai_log("SA_attackable([target_mob])",3) if (isliving(target_mob)) var/mob/living/L = target_mob - if(!L.stat) + if(L.stat != DEAD) return 1 if (istype(target_mob,/obj/mecha)) var/obj/mecha/M = target_mob @@ -777,6 +846,8 @@ continue else if(!SA_attackable(L)) continue + else if(!special_target_check(L)) + continue else T = L break @@ -785,6 +856,8 @@ var/obj/mecha/M = A if(!SA_attackable(M)) continue + else if(!special_target_check(M)) + continue if((M.occupant.faction != src.faction) || attack_same) T = M break @@ -801,6 +874,10 @@ /mob/living/simple_animal/proc/Found(var/atom/A) return +// Used for somewhat special targeting, but not to the extent of using Found() +/mob/living/simple_animal/proc/special_target_check(var/atom/A) + return TRUE + //Requesting help from like-minded individuals /mob/living/simple_animal/proc/RequestHelp() if(!cooperative || ((world.time - last_helpask_time) < 10 SECONDS)) @@ -833,6 +910,12 @@ if(set_follow(F, 10 SECONDS)) handle_stance(STANCE_FOLLOW) +// Can be used to conditionally do a ranged or melee attack. +// Note that the SA must be able to do an attack at the specified range or else it may get trapped in a loop of switching +// between STANCE_ATTACK and STANCE_ATTACKING, due to being told by MoveToTarget() that they're in range but being told by AttackTarget() that they're not. +/mob/living/simple_animal/proc/ClosestDistance() + return ranged ? shoot_range - 1 : 1 // Shoot range -1 just because we don't want to constantly get kited + //Move to a target (or near if we're ranged) /mob/living/simple_animal/proc/MoveToTarget() if(incapacitated(INCAPACITATION_DISABLED)) @@ -857,9 +940,9 @@ ForgetPath() //Find out where we're getting to - var/get_to = ranged ? shoot_range-1 : 1 //Shoot range -1 just because we don't want to constantly get kited + var/get_to = ClosestDistance() var/distance = get_dist(src,target_mob) - ai_log("MoveToTarget() [src] [get_to] [distance]",2) + ai_log("MoveToTarget() [src] get_to: [get_to] distance: [distance]",2) //We're here! if(distance <= get_to) @@ -919,6 +1002,7 @@ if(incapacitated(INCAPACITATION_DISABLED)) ai_log("FollowTarget() Bailing because we're disabled",2) + LoseFollow() return if((get_dist(src,follow_mob) <= follow_dist)) @@ -972,7 +1056,7 @@ /mob/living/simple_animal/proc/GetPath(var/turf/target,var/get_to = 1,var/max_distance = world.view*6) ai_log("GetPath([target],[get_to],[max_distance])",2) ForgetPath() - var/list/new_path = AStar(get_turf(loc), target, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, min_target_dist = get_to, max_node_depth = max_distance, id = myid, exclude = obstacles) + var/list/new_path = AStar(get_turf(loc), target, astar_adjacent_proc, /turf/proc/Distance, min_target_dist = get_to, max_node_depth = max_distance, id = myid, exclude = obstacles) if(new_path && new_path.len) walk_list = new_path @@ -1082,6 +1166,10 @@ //Get into attack mode on a target /mob/living/simple_animal/proc/AttackTarget() stop_automated_movement = 1 + if(incapacitated(INCAPACITATION_DISABLED)) + ai_log("AttackTarget() Bailing because we're disabled",2) + LoseTarget() + return 0 if(!target_mob || !SA_attackable(target_mob)) LoseTarget() return 0 @@ -1111,6 +1199,7 @@ //They ran away! else ai_log("AttackTarget() out of range!",3) + sleep(1) // Unfortunately this is needed to protect from ClosestDistance() sometimes not updating fast enough to prevent an infinite loop. handle_stance(STANCE_ATTACK) return 0 @@ -1118,7 +1207,8 @@ /mob/living/simple_animal/proc/PunchTarget() if(!Adjacent(target_mob)) return - sleep(rand(8) + 8) + if(!client) + sleep(rand(8) + 8) if(isliving(target_mob)) var/mob/living/L = target_mob @@ -1129,39 +1219,51 @@ src.do_attack_animation(src) return L else - L.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext) + DoPunch(L) 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) + DoPunch(M) return M +// This is the actual act of 'punching'. Override for special behaviour. +/mob/living/simple_animal/proc/DoPunch(var/atom/A) + if(!Adjacent(target_mob)) // They could've moved in the meantime. + return + var/damage_to_do = rand(melee_damage_lower, melee_damage_upper) + + for(var/datum/modifier/M in modifiers) + if(!isnull(M.outgoing_melee_damage_percent)) + damage_to_do *= M.outgoing_melee_damage_percent + + A.attack_generic(src, damage_to_do, attacktext) + //The actual top-level ranged attack proc /mob/living/simple_animal/proc/ShootTarget() var/target = target_mob var/tturf = get_turf(target) - if(firing_lines && !CheckFiringLine(tturf)) + if((firing_lines && !client) && !CheckFiringLine(tturf)) step_rand(src) face_atom(tturf) return 0 - visible_message("[src] fires at [target]!", 1) + visible_message("[src] fires at [target]!") if(rapid) spawn(1) - Shoot(tturf, src.loc, src) + Shoot(target, src.loc, src) if(casingtype) new casingtype(get_turf(src)) spawn(4) - Shoot(tturf, src.loc, src) + Shoot(target, src.loc, src) if(casingtype) new casingtype(get_turf(src)) spawn(6) - Shoot(tturf, src.loc, src) + Shoot(target, src.loc, src) if(casingtype) new casingtype(get_turf(src)) else - Shoot(tturf, src.loc, src) + Shoot(target, src.loc, src) if(casingtype) new casingtype @@ -1201,9 +1303,9 @@ playsound(user, projectilesound, 100, 1) if(!A) return - if (!istype(target, /turf)) - qdel(A) - return +// if (!istype(target, /turf)) +// qdel(A) +// return A.launch(target) return @@ -1226,6 +1328,43 @@ handle_stance(STANCE_IDLE) GiveUpMoving() +// Makes the simple mob stop everything. Useful for when it get stunned. +/mob/living/simple_animal/proc/Disable() + ai_log("Disable() [target_mob]",2) + spawn(0) + LoseTarget() + LoseFollow() + +/mob/living/simple_animal/Stun(amount) + if(amount > 0) + Disable() + ..(amount) + +/mob/living/simple_animal/AdjustStunned(amount) + if(amount > 0) + Disable() + ..(amount) + +/mob/living/simple_animal/Weaken(amount) + if(amount > 0) + Disable() + ..(amount) + +/mob/living/simple_animal/AdjustWeakened(amount) + if(amount > 0) + Disable() + ..(amount) + +/mob/living/simple_animal/Paralyse(amount) + if(amount > 0) + Disable() + ..(amount) + +/mob/living/simple_animal/AdjustParalysis(amount) + if(amount > 0) + Disable() + ..(amount) + //Find me some targets /mob/living/simple_animal/proc/ListTargets(var/dist = view_range) var/list/L = hearers(src, dist) @@ -1244,22 +1383,32 @@ var/turf/problem_turf = get_step(src, direction) ai_log("DestroySurroundings([direction])",3) + var/damage_to_do = rand(melee_damage_lower, melee_damage_upper) + + for(var/datum/modifier/M in modifiers) + if(!isnull(M.outgoing_melee_damage_percent)) + damage_to_do *= M.outgoing_melee_damage_percent + for(var/obj/structure/window/obstacle in problem_turf) if(obstacle.dir == reverse_dir[dir]) // So that windows get smashed in the right order ai_log("DestroySurroundings() directional window hit",3) - obstacle.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext) + obstacle.attack_generic(src, damage_to_do, attacktext) + return + else if(obstacle.is_fulltile()) + ai_log("DestroySurroundings() full tile window hit",3) + obstacle.attack_generic(src, damage_to_do, attacktext) return var/obj/structure/obstacle = locate(/obj/structure, problem_turf) if(istype(obstacle, /obj/structure/window) || istype(obstacle, /obj/structure/closet) || istype(obstacle, /obj/structure/table) || istype(obstacle, /obj/structure/grille)) ai_log("DestroySurroundings() generic structure hit [obstacle]",3) - obstacle.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext) + obstacle.attack_generic(src, damage_to_do ,attacktext) return for(var/obj/machinery/door/baddoor in problem_turf) //Required since firelocks take up the same turf if(baddoor.density) ai_log("DestroySurroundings() door hit [baddoor]",3) - baddoor.attack_generic(src,rand(melee_damage_lower,melee_damage_upper),attacktext) + baddoor.attack_generic(src, damage_to_do ,attacktext) return //Check for shuttle bumrush diff --git a/code/modules/mob/living/simple_animal/slime/ai.dm b/code/modules/mob/living/simple_animal/slime/ai.dm new file mode 100644 index 0000000000..2a61f91e31 --- /dev/null +++ b/code/modules/mob/living/simple_animal/slime/ai.dm @@ -0,0 +1,58 @@ +/mob/living/simple_animal/slime/FindTarget() + if(victim) // Don't worry about finding another target if we're eatting someone. + return +// if(!will_hunt()) +// return + ..() + +/mob/living/simple_animal/slime/special_target_check(mob/living/L) + if(istype(L, /mob/living/simple_animal/slime)) + var/mob/living/simple_animal/slime/buddy = L + if(buddy.slime_color == src.slime_color || discipline || unity || buddy.unity) + return FALSE // Don't hurt same colored slimes. + + if(ishuman(L)) + var/mob/living/carbon/human/H = L + if(H.species && H.species.name == "Promethean") + return FALSE // Prometheans are always our friends. + else if(istype(H.species, /datum/species/monkey)) // istype() is so they'll eat the alien monkeys too. + return TRUE // Monkeys are always food. + if(discipline && !rabid) + return FALSE // We're a good slime. For now at least + + if(issilicon(L) || isbot(L) ) + if(discipline && !rabid) + return FALSE // We're a good slime. For now at least. + return ..() // Other colors and nonslimes are jerks however. + +/mob/living/simple_animal/slime/ClosestDistance() + if(target_mob.stat == DEAD) + return 1 // Melee (eat) the target if dead, don't shoot it. + return ..() + +/mob/living/simple_animal/slime/HelpRequested(var/mob/living/simple_animal/slime/buddy) + if(istype(buddy)) + if(buddy.slime_color != src.slime_color && (!unity || !buddy.unity)) // We only help slimes of the same color, if it's another slime calling for help. + ai_log("HelpRequested() by [buddy] but they are a [buddy.slime_color] while we are a [src.slime_color].",2) + return + if(buddy.target_mob) + if(!special_target_check(buddy.target_mob)) + ai_log("HelpRequested() by [buddy] but special_target_check() failed when passed [buddy.target_mob].",2) + return + ..() + + +/mob/living/simple_animal/slime/handle_resist() + if(buckled && victim && isliving(buckled) && victim == buckled) // If it's buckled to a living thing it's probably eating it. + return + else + ..() + +/* +/mob/living/simple_animal/slime/proc/will_hunt() // Check for being stopped from feeding and chasing + if(nutrition <= get_starve_nutrition() || rabid) + return TRUE + if(nutrition <= get_hunger_nutrition() || prob(25)) + return TRUE + return FALSE +*/ \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/slime/combat.dm b/code/modules/mob/living/simple_animal/slime/combat.dm new file mode 100644 index 0000000000..eb77f338c2 --- /dev/null +++ b/code/modules/mob/living/simple_animal/slime/combat.dm @@ -0,0 +1,276 @@ + + +/* +// Check target_mob if worthy of attack +/mob/living/simple_animal/slime/SA_attackable(target_mob) + ai_log("SA_attackable([target_mob])",3) + if(isliving(target_mob)) + var/mob/living/L = target_mob + if(L.stat == DEAD) + if(can_consume(L)) // If we can eat them, then it doesn't matter if they're dead. + return TRUE + ..() +*/ + +/mob/living/simple_animal/slime/PunchTarget() + if(victim) + return // Already eatting someone. + if(!client) // AI controlled. + if( (!target_mob.lying && prob(60 + (power_charge * 4) ) || (!target_mob.lying && optimal_combat) )) // "Smart" slimes always stun first. + a_intent = I_DISARM // Stun them first. + else if(can_consume(target_mob) && target_mob.lying) + a_intent = I_GRAB // Then eat them. + else + a_intent = I_HURT // Otherwise robust them. + ai_log("PunchTarget() will [a_intent] [target_mob]",2) + ..() + +/mob/living/simple_animal/slime/proc/can_consume(var/mob/living/L) + if(!L || !istype(L)) + to_chat(src, "This subject is incomparable...") + return FALSE + if(L.isSynthetic()) + to_chat(src, "This subject is not biological...") + return FALSE + if(L.getarmor(null, "bio") >= 80) + to_chat(src, "I cannot reach this subject's biological matter...") + return FALSE + if(istype(L, /mob/living/simple_animal/slime)) + to_chat(src, "I cannot feed on other slimes...") + return FALSE + if(!Adjacent(L)) + to_chat(src, "This subject is too far away...") + return FALSE + if(istype(L, /mob/living/carbon) && L.getCloneLoss() >= L.getMaxHealth() * 1.5 || istype(L, /mob/living/simple_animal) && L.stat == DEAD) + to_chat(src, "This subject does not have an edible life energy...") + return FALSE + if(L.buckled_mob) + if(istype(L.buckled_mob, /mob/living/simple_animal/slime)) + if(L.buckled_mob != src) + to_chat(src, "\The [L.buckled_mob] is already feeding on this subject...") + return FALSE + return TRUE + +/mob/living/simple_animal/slime/proc/start_consuming(var/mob/living/L) + if(!can_consume(L)) + return + if(!Adjacent(L)) + return + step_towards(src, L) // Get on top of them to feed. + if(loc != L.loc) + return + if(L.buckle_mob(src, forced = TRUE)) + victim = L + update_icon() + victim.visible_message("\The [src] latches onto [victim]!", + "\The [src] latches onto you!") + +/mob/living/simple_animal/slime/proc/stop_consumption() + if(!victim) + return + victim.unbuckle_mob() + victim.visible_message("\The [src] slides off of [victim]!", + "\The [src] slides off of you!") + victim = null + update_icon() + + +/mob/living/simple_animal/slime/proc/handle_consumption() + if(victim && can_consume(victim) && !stat) + + var/armor_modifier = abs((victim.getarmor(null, "bio") / 100) - 1) + if(istype(victim, /mob/living/carbon)) + victim.adjustCloneLoss(rand(5,6) * armor_modifier) + victim.adjustToxLoss(rand(1,2) * armor_modifier) + if(victim.health <= 0) + victim.adjustToxLoss(rand(2,4) * armor_modifier) + + else if(istype(victim, /mob/living/simple_animal)) + victim.adjustBruteLoss(is_adult ? rand(7, 15) : rand(4, 12)) + + else + to_chat(src, "[pick("This subject is incompatable", \ + "This subject does not have a life energy", "This subject is empty", "I am not satisified", \ + "I can not feed from this subject", "I do not feel nourished", "This subject is not food")]...") + stop_consumption() + + adjust_nutrition(50 * armor_modifier) + + adjustOxyLoss(-10 * armor_modifier) //Heal yourself + adjustBruteLoss(-10 * armor_modifier) + adjustFireLoss(-10 * armor_modifier) + adjustCloneLoss(-10 * armor_modifier) + updatehealth() + if(victim) + victim.updatehealth() + else + stop_consumption() + +/mob/living/simple_animal/slime/DoPunch(var/mob/living/L) + if(!Adjacent(L)) // Might've moved away in the meantime. + return + + if(istype(L)) + + if(ishuman(L)) + var/mob/living/carbon/human/H = L + // Slime attacks can be blocked with shields. + if(H.check_shields(damage = 0, damage_source = null, attacker = src, def_zone = null, attack_text = "the attack")) + return + + switch(a_intent) + if(I_HELP) + ai_log("DoPunch() against [L], helping.",2) + L.visible_message("[src] gently pokes [L]!", + "[src] gently pokes you!") + do_attack_animation(L) + post_attack(L, a_intent) + + if(I_DISARM) + ai_log("DoPunch() against [L], disarming.",2) + var/stun_power = between(0, power_charge + rand(0, 3), 10) + + if(ishuman(L)) + var/mob/living/carbon/human/H = L + stun_power *= max(H.species.siemens_coefficient,0) + + + if(prob(stun_power * 10)) + power_charge = max(0, power_charge - 3) + L.visible_message("[src] has shocked [L]!", "[src] has shocked you!") + playsound(src, 'sound/weapons/Egloves.ogg', 75, 1) + L.Weaken(4) + L.Stun(4) + do_attack_animation(L) + if(L.buckled) + L.buckled.unbuckle_mob() // To prevent an exploit where being buckled prevents slimes from jumping on you. + L.stuttering = max(L.stuttering, stun_power) + + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread + s.set_up(5, 1, L) + s.start() + + if(prob(stun_power * 10) && stun_power >= 8) + L.adjustFireLoss(power_charge * rand(1, 2)) + post_attack(L, a_intent) + + else if(prob(40)) + L.visible_message("[src] has pounced at [L]!", "[src] has pounced at you!") + playsound(src, 'sound/weapons/thudswoosh.ogg', 75, 1) + L.Weaken(2) + do_attack_animation(L) + if(L.buckled) + L.buckled.unbuckle_mob() // To prevent an exploit where being buckled prevents slimes from jumping on you. + post_attack(L, a_intent) + else + L.visible_message("[src] has tried to pounce at [L]!", "[src] has tried to pounce at you!") + playsound(src, 'sound/weapons/punchmiss.ogg', 75, 1) + do_attack_animation(L) + L.updatehealth() + return L + + if(I_GRAB) + ai_log("DoPunch() against [L], grabbing.",2) + start_consuming(L) + post_attack(L, a_intent) + + if(I_HURT) + ai_log("DoPunch() against [L], hurting.",2) + var/damage_to_do = rand(melee_damage_lower, melee_damage_upper) + var/armor_modifier = abs((L.getarmor(null, "bio") / 100) - 1) + + L.attack_generic(src, damage_to_do, attacktext) + playsound(src, 'sound/weapons/bite.ogg', 75, 1) + + // Give the slime some nutrition, if applicable. + if(!L.isSynthetic()) + if(ishuman(L)) + if(L.getCloneLoss() < L.getMaxHealth() * 1.5) + adjust_nutrition(damage_to_do * armor_modifier) + + else if(istype(L, /mob/living/simple_animal)) + if(!isslime(L)) + var/mob/living/simple_animal/SA = L + if(!SA.stat) + adjust_nutrition(damage_to_do) + + post_attack(L, a_intent) + + if(istype(L,/obj/mecha)) + var/obj/mecha/M = L + M.attack_generic(src, rand(melee_damage_lower, melee_damage_upper), attacktext) + +/mob/living/simple_animal/slime/proc/post_attack(var/mob/living/L, var/intent = I_HURT) + if(intent != I_HELP) + if(L.reagents && L.can_inject() && reagent_injected) + L.reagents.add_reagent(reagent_injected, injection_amount) + +/mob/living/simple_animal/slime/attackby(obj/item/W, mob/user) + if(istype(W, /obj/item/clothing/head)) // Handle hat simulator. + give_hat(W, user) + return + + // Otherwise they're probably fighting the slime. + if(prob(25)) + visible_message("\The [user]'s [W] passes right through [src]!") + user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) + return + ..() + +/mob/living/simple_animal/slime/hit_with_weapon(obj/item/O, mob/living/user, var/effective_force, var/hit_zone) + ..() + if(!stat) + if(O.force > 0 && discipline && !rabid) // wow, buddy, why am I getting attacked?? + adjust_discipline(1) + return + if(O.force >= 3) + if(victim || target_mob) // We've been a bad slime. + if(is_adult) + if(prob(5 + round(O.force / 2)) ) + if(prob(80) && !client) + adjust_discipline(2) + if(user) + step_away(src, user) + else + if(prob(10 + O.force * 2)) + if(prob(80) && !client) + adjust_discipline(2) + if(user) + step_away(src, user) + else + if(user in friends) // Friend attacking us for no reason. + if(prob(25)) + friends -= user + say("[user]... not friend...") + +/mob/living/simple_animal/slime/attack_hand(mob/living/carbon/human/M as mob) + if(victim) // Are we eating someone? + var/fail_odds = 30 + if(victim == M) // Harder to get the slime off if its eating you right now. + fail_odds = 60 + + if(prob(fail_odds)) + visible_message("[M] attempts to wrestle \the [name] off!") + playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1) + + else + visible_message(" [M] manages to wrestle \the [name] off!") + playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1) + + if(prob(40) && !client) + adjust_discipline(1) + stop_consumption() + step_away(src,M) + else + if(M.a_intent == I_HELP) + if(hat) + remove_hat(M) + else + ..() + else + ..() + +// Shocked grilles don't hurt slimes, and in fact give them charge. +/mob/living/simple_animal/slime/electrocute_act(var/shock_damage, var/obj/source, var/siemens_coeff = 1.0, var/def_zone = null) + power_charge = between(0, power_charge + round(shock_damage / 10), 10) + to_chat(src, "\The [source] shocks you, and it charges you.") diff --git a/code/modules/mob/living/simple_animal/slime/death.dm b/code/modules/mob/living/simple_animal/slime/death.dm new file mode 100644 index 0000000000..01500db42e --- /dev/null +++ b/code/modules/mob/living/simple_animal/slime/death.dm @@ -0,0 +1,24 @@ +/mob/living/simple_animal/slime/death(gibbed) + + if(stat == DEAD) + return + + if(!gibbed && is_adult) + var/mob/living/simple_animal/slime/S = make_new_slime() + S.rabid = TRUE + step_away(S, src) + is_adult = FALSE + maxHealth = initial(maxHealth) + revive() + if(!client) + rabid = TRUE + number = rand(1, 1000) + update_name() + return + + stop_consumption() + . = ..(gibbed, "stops moving and partially dissolves...") + + update_icon() + + return \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/slime/life.dm b/code/modules/mob/living/simple_animal/slime/life.dm new file mode 100644 index 0000000000..30c2dba554 --- /dev/null +++ b/code/modules/mob/living/simple_animal/slime/life.dm @@ -0,0 +1,174 @@ +/mob/living/simple_animal/slime/proc/adjust_nutrition(input) + nutrition = between(0, nutrition + input, get_max_nutrition()) + + if(input > 0) + if(prob(input * 2)) // Gain around one level per 50 nutrition + power_charge = min(power_charge++, 10) + if(power_charge == 10) + adjustToxLoss(-10) + + +/mob/living/simple_animal/slime/proc/get_max_nutrition() // Can't go above it + if(is_adult) + return 1200 + return 1000 + +/mob/living/simple_animal/slime/proc/get_grow_nutrition() // Above it we grow, below it we can eat + if(is_adult) + return 1000 + return 800 + +/mob/living/simple_animal/slime/proc/get_hunger_nutrition() // Below it we will always eat + if(is_adult) + return 600 + return 500 + +/mob/living/simple_animal/slime/proc/get_starve_nutrition() // Below it we will eat before everything else + if(is_adult) + return 300 + return 200 + +/mob/living/simple_animal/slime/proc/handle_nutrition() + if(docile) + return + if(prob(15)) + adjust_nutrition(-1 - is_adult) + + if(nutrition <= get_starve_nutrition()) + handle_starvation() + + else if(nutrition >= get_grow_nutrition() && amount_grown < 10) + adjust_nutrition(-20) + amount_grown = between(0, amount_grown + 1, 10) + +/mob/living/simple_animal/slime/proc/handle_starvation() + if(nutrition < get_starve_nutrition() && !client) // if a slime is starving, it starts losing its friends + if(friends.len && prob(1)) + var/mob/nofriend = pick(friends) + if(nofriend) + friends -= nofriend + say("[nofriend]... food now...") + + if(nutrition <= 0) + adjustToxLoss(rand(1,3)) + if(client && prob(5)) + to_chat(src, "You are starving!") + +/mob/living/simple_animal/slime/proc/handle_discipline() + if(discipline > 0) + update_mood() + // if(discipline >= 5 && rabid) + // if(prob(60)) + // rabid = 0 + // adjust_discipline(1) // So it stops trying to murder everyone. + + // Handle discipline decay. + if(!prob(75 + (obedience * 5))) + adjust_discipline(-1) + if(!discipline) + update_mood() + +/mob/living/simple_animal/slime/handle_regular_status_updates() + if(stat != DEAD) + handle_nutrition() + + handle_discipline() + + if(prob(30)) + adjustOxyLoss(-1) + adjustToxLoss(-1) + adjustFireLoss(-1) + adjustCloneLoss(-1) + adjustBruteLoss(-1) + + if(victim) + handle_consumption() + + if(amount_grown >= 10 && !target_mob && !client) + if(is_adult) + reproduce() + else + evolve() + + handle_stuttering() + + ..() + + +// This is to make slime responses feel a bit more natural and not instant. +/mob/living/simple_animal/slime/proc/delayed_say(var/message, var/mob/target) + sleep(rand(1 SECOND, 2 SECONDS)) + if(target) + face_atom(target) + say(message) + +//Commands, reactions, etc +/mob/living/simple_animal/slime/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/alt_name = "", var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol) + ..() + if((findtext(message, num2text(number)) || findtext(message, name) || findtext(message, "slimes"))) // Talking to us + + // Say hello back. + if(findtext(message, "hello") || findtext(message, "hi") || findtext(message, "greetings")) + delayed_say(pick("Hello...", "Hi..."), speaker) + + // Follow request. + if(findtext(message, "follow") || findtext(message, "come with me")) + if(!can_command(speaker)) + delayed_say(pick("No...", "I won't follow..."), speaker) + return + + delayed_say("Yes... I follow \the [speaker]...", speaker) + set_follow(speaker) + FollowTarget() + + // Stop request. + if(findtext(message, "stop") || findtext(message, "halt") || findtext(message, "cease")) + if(victim) // We're being asked to stop eatting someone. + if(!can_command(speaker)) + delayed_say("No...", speaker) + return + else + delayed_say("Fine...", speaker) + stop_consumption() + adjust_discipline(1, TRUE) + + if(target_mob) // We're being asked to stop chasing someone. + if(!can_command(speaker)) + delayed_say("No...", speaker) + return + else + delayed_say("Fine...", speaker) + LoseTarget() + adjust_discipline(1, TRUE) + + if(follow_mob) // We're being asked to stop following someone. + if(follow_mob == speaker) + delayed_say("Yes... I'll stop...", speaker) + LoseFollow() + else + delayed_say("No... I'll keep following \the [follow_mob]...", speaker) + + // Help request + if(findtext(message, "help")) + if(!can_command(speaker)) + delayed_say("No...", speaker) + return + else + delayed_say("I will protect \the [speaker].", speaker) + + // Murder request + if(findtext(message, "harm") || findtext(message, "kill") || findtext(message, "murder") || findtext(message, "eat") || findtext(message, "consume")) + if(!can_command(speaker)) + delayed_say("No...", speaker) + return + + //LoseFollow() + + /* + if(reacts && speaker && (message in reactions) && (!hostile || isliving(speaker)) && say_understands(speaker,language)) + var/mob/living/L = speaker + if(L.faction == faction) + spawn(10) + face_atom(speaker) + say(reactions[message]) + */ \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm new file mode 100644 index 0000000000..bc91e44884 --- /dev/null +++ b/code/modules/mob/living/simple_animal/slime/slime.dm @@ -0,0 +1,433 @@ +/mob/living/simple_animal/slime + name = "baby slime" + desc = "The most basic of slimes. The grey slime has no remarkable qualities, however it remains one of the most useful colors for scientists." + icon = 'icons/mob/slime2.dmi' + icon_state = "grey baby slime" + intelligence_level = SA_ANIMAL + pass_flags = PASSTABLE + var/shiny = FALSE // If true, will add a 'shiny' overlay. + var/glows = FALSE // If true, will glow in the same color as the color var. + var/icon_state_override = null // Used for special slime appearances like the rainbow slime. + pass_flags = PASSTABLE + + speak_emote = list("chirps") + + maxHealth = 150 + var/maxHealth_adult = 200 + melee_damage_lower = 5 + melee_damage_upper = 25 + melee_miss_chance = 0 + gender = NEUTER + + // Atmos stuff. + minbodytemp = T0C-30 + heat_damage_per_tick = 0 + cold_damage_per_tick = 40 + + min_oxy = 0 + max_oxy = 0 + min_tox = 0 + max_tox = 0 + min_co2 = 0 + max_co2 = 0 + min_n2 = 0 + max_n2 = 0 + unsuitable_atoms_damage = 0 + + + speak = list( + "Blorp...", + "Blop..." + + ) + emote_hear = list( + + ) + emote_see = list( + "bounces", + "jiggles", + "sways" + ) + + hostile = 1 + retaliate = 1 + attack_same = 1 + cooperative = 1 + faction = "slime" // Slimes will help other slimes, provided they share the same color. + + color = "#CACACA" + var/is_adult = FALSE + var/cores = 1 // How many cores you get when placed in a Processor. + var/power_charge = 0 // 0-10 controls how much electricity they are generating. High numbers encourage the slime to stun someone with electricity. + var/amount_grown = 0 // controls how long the slime has been overfed, if 10, grows or reproduces + var/number = 0 // This is used to make the slime semi-unique for indentification. + + var/mob/living/victim = null // the person the slime is currently feeding on + var/rabid = FALSE // If true, will attack anyone and everyone. + var/docile = FALSE // Basically the opposite of above. If true, will never harm anything and won't get hungry. + var/discipline = 0 // Beating slimes makes them less likely to lash out. In theory. + var/resentment = 0 // 'Unjustified' beatings make this go up, and makes it more likely for abused slimes to go berserk. + var/obedience = 0 // Conversely, 'justified' beatings make this go up, and makes discipline decay slowly, potentially making it not decay at all. + var/unity = FALSE // If true, slimes will consider other colors as their own. Other slimes will see this slime as the same color as well. A rainbow slime is required to get this. + var/optimal_combat = FALSE // Used to dumb down the combat AI somewhat. If true, the slime tends to be really dangerous to fight alone due to stunlocking. + var/mood = ":3" // Icon to use to display 'mood'. + var/obj/item/clothing/head/hat = null // The hat the slime may be wearing. + + var/slime_color = "grey" + var/mutation_chance = 25 // Odds of spawning as a new color when reproducing. Can be modified by certain xenobio products. Carried across generations of slimes. + var/coretype = /obj/item/slime_extract/grey + // List of potential slime color mutations. This must have exactly four types. + var/list/slime_mutation = list( + /mob/living/simple_animal/slime/orange, + /mob/living/simple_animal/slime/metal, + /mob/living/simple_animal/slime/blue, + /mob/living/simple_animal/slime/purple + ) + + var/reagent_injected = null // Some slimes inject reagents on attack. This tells the game what reagent to use. + var/injection_amount = 5 // This determines how much. + +/mob/living/simple_animal/slime/New(var/location, var/start_as_adult = FALSE) + verbs += /mob/living/proc/ventcrawl + if(start_as_adult) + make_adult() + health = maxHealth +// slime_mutation = mutation_table(slime_color) + update_icon() + number = rand(1, 1000) + update_name() + ..(location) + +/mob/living/simple_animal/slime/Destroy() + if(hat) + drop_hat() + return ..() + +/mob/living/simple_animal/slime/proc/make_adult() + if(is_adult) + return + + is_adult = TRUE + melee_damage_lower = 20 + melee_damage_upper = 40 + maxHealth = maxHealth_adult + amount_grown = 0 + update_icon() + update_name() + +/mob/living/simple_animal/slime/proc/update_name() + if(docile) // Docile slimes are generally named, so we shouldn't mess with it. + return + name = "[slime_color] [is_adult ? "adult" : "baby"] slime ([number])" + real_name = name + +/mob/living/simple_animal/slime/update_icon() + if(stat == DEAD) + icon_state = "[icon_state_override ? "[icon_state_override] slime" : "slime"] [is_adult ? "adult" : "baby"] dead" + set_light(0) + else + if(incapacitated(INCAPACITATION_DISABLED)) + icon_state = "[icon_state_override ? "[icon_state_override] slime" : "slime"] [is_adult ? "adult" : "baby"] dead" + else + icon_state = "[icon_state_override ? "[icon_state_override] slime" : "slime"] [is_adult ? "adult" : "baby"][victim ? " eating":""]" + + overlays.Cut() + if(stat != DEAD) + var/image/I = image(icon, src, "slime light") + I.appearance_flags = RESET_COLOR + overlays += I + + if(shiny) + I = image(icon, src, "slime shiny") + I.appearance_flags = RESET_COLOR + overlays += I + + I = image(icon, src, "aslime-[mood]") + I.appearance_flags = RESET_COLOR + overlays += I + + if(glows) + set_light(3, 2, color) + + if(hat) + var/hat_state = hat.item_state ? hat.item_state : hat.icon_state + var/image/I = image('icons/mob/head.dmi', src, hat_state) + I.pixel_y = -7 // Slimes are small. + I.appearance_flags = RESET_COLOR + overlays += I + + if(modifier_overlay) // Restore our modifier overlay. + overlays += modifier_overlay + +/mob/living/simple_animal/slime/proc/update_mood() + var/old_mood = mood + if(incapacitated(INCAPACITATION_DISABLED)) + mood = "sad" + else if(rabid) + mood = "angry" + else if(target_mob) + mood = "mischevous" + else if(discipline) + mood = "pout" + else if(docile) + mood = ":33" + else + mood = ":3" + if(old_mood != mood) + update_icon() + +// Makes the slime very angry and dangerous. +/mob/living/simple_animal/slime/proc/enrage() + if(docile) + return + rabid = TRUE + update_mood() + visible_message("\The [src] enrages!") + +// Makes the slime safe and harmless. +/mob/living/simple_animal/slime/proc/pacify() + rabid = FALSE + docile = TRUE + hostile = FALSE + retaliate = FALSE + cooperative = FALSE + + // If for whatever reason the mob AI decides to try to attack something anyways. + melee_damage_upper = 0 + melee_damage_lower = 0 + + update_mood() + +/mob/living/simple_animal/slime/proc/unify() + unity = TRUE + attack_same = FALSE + +/mob/living/simple_animal/slime/examine(mob/user) + ..() + if(hat) + to_chat(user, "It is wearing \a [hat].") + + if(stat == DEAD) + to_chat(user, "It appears to be dead.") + else if(incapacitated(INCAPACITATION_DISABLED)) + to_chat(user, "It appears to be incapacitated.") + else if(rabid) + to_chat(user, "It seems very, very angry and upset.") + else if(obedience >= 5) + to_chat(user, "It looks rather obedient.") + else if(discipline) + to_chat(user, "It has been subjugated by force, at least for now.") + else if(docile) + to_chat(user, "It appears to have been pacified.") + +/mob/living/simple_animal/slime/water_act(amount) // This is called if a slime enters a water tile. + adjustBruteLoss(40 * amount) + +/mob/living/simple_animal/slime/proc/adjust_discipline(amount, silent) + if(amount > 0) + if(!rabid) + var/justified = is_justified_to_discipline() + spawn(0) + stop_consumption() + LoseTarget() + if(!silent) + if(justified) + say(pick("Fine...", "Okay...", "Sorry...", "I yield...", "Mercy...")) + else + say(pick("Why...?", "I don't understand...?", "Cruel...", "Stop...", "Nooo...")) + if(justified) + obedience++ + else + if(prob(resentment * 20)) + enrage() // Pushed the slime too far. + say(pick("Evil...", "Kill...", "Tyrant...")) + resentment++ // Done after check so first time will never enrage. + + discipline = between(0, discipline + amount, 10) + +/mob/living/simple_animal/slime/movement_delay() + if(bodytemperature >= 330.23) // 135 F or 57.08 C + return -1 // slimes become supercharged at high temperatures + + . = ..() + + var/health_deficiency = (maxHealth - health) + if(health_deficiency >= 45) + . += (health_deficiency / 25) + + if(bodytemperature < 183.222) + . += (283.222 - bodytemperature) / 10 * 1.75 + + . += config.slime_delay + +/mob/living/simple_animal/slime/Process_Spacemove() + return 2 + +/mob/living/simple_animal/slime/verb/evolve() + set category = "Slime" + set desc = "This will let you evolve from baby to adult slime." + + if(stat) + to_chat(src, "I must be conscious to do this...") + return + + if(docile) + to_chat(src, "I have been pacified. I cannot evolve...") + return + + if(!is_adult) + if(amount_grown >= 10) + make_adult() + else + to_chat(src, "I am not ready to evolve yet...") + else + to_chat(src, "I have already evolved...") + +/mob/living/simple_animal/slime/verb/reproduce() + set category = "Slime" + set desc = "This will make you split into four Slimes." + + if(stat) + to_chat(src, "I must be conscious to do this...") + return + + if(docile) + to_chat(src, "I have been pacified. I cannot reproduce...") + return + + if(is_adult) + if(amount_grown >= 10) + + var/list/babies = list() + for(var/i = 1 to 4) + babies.Add(make_new_slime()) + + var/mob/living/simple_animal/slime/new_slime = pick(babies) + new_slime.universal_speak = universal_speak + if(src.mind) + src.mind.transfer_to(new_slime) + else + new_slime.key = src.key + qdel(src) + else + to_chat(src, "I am not ready to reproduce yet...") + else + to_chat(src, "I am not old enough to reproduce yet...") + +// Used for reproducing and dying. +/mob/living/simple_animal/slime/proc/make_new_slime() + var/t = src.type + if(prob(mutation_chance) && slime_mutation.len) + t = slime_mutation[rand(1, slime_mutation.len)] + var/mob/living/simple_animal/slime/baby = new t(loc) + + // Handle 'inheriting' from parent slime. + baby.mutation_chance = mutation_chance + baby.power_charge = round(power_charge / 4) + baby.resentment = max(resentment - 1, 0) + baby.discipline = max(discipline - 1, 0) + baby.obedience = max(obedience - 1, 0) + baby.unity = unity + baby.faction = faction + baby.friends = friends.Copy() + if(rabid) + baby.enrage() + + step_away(baby, src) + return baby + +/mob/living/simple_animal/slime/speech_bubble_appearance() + return "slime" + +// Called after they finish eatting someone. +/mob/living/simple_animal/slime/proc/befriend(var/mob/living/friend) + if(!(friend in friends)) + friends |= friend + say("[friend]... friend...") + +/mob/living/simple_animal/slime/proc/can_command(var/mob/living/commander) + if(rabid) + return FALSE + if(docile) + return TRUE + if(commander in friends) + return TRUE + if(faction == commander.faction) + return TRUE + if(discipline > resentment && obedience >= 5) + return TRUE + return FALSE + +/mob/living/simple_animal/slime/proc/give_hat(var/obj/item/clothing/head/new_hat, var/mob/living/user) + if(!istype(new_hat)) + to_chat(user, "\The [new_hat] isn't a hat.") + return + if(hat) + to_chat(user, "\The [src] is already wearing \a [hat].") + return + else + user.drop_item(new_hat) + hat = new_hat + new_hat.forceMove(src) + to_chat(user, "You place \a [new_hat] on \the [src]. How adorable!") + update_icon() + return + +/mob/living/simple_animal/slime/proc/remove_hat(var/mob/living/user) + if(!hat) + to_chat(user, "\The [src] doesn't have a hat to remove.") + else + hat.forceMove(get_turf(src)) + user.put_in_hands(hat) + to_chat(user, "You take away \the [src]'s [hat.name]. How mean.") + hat = null + update_icon() + +/mob/living/simple_animal/slime/proc/drop_hat() + if(!hat) + return + hat.forceMove(get_turf(src)) + hat = null + update_icon() + +// Checks if disciplining the slime would be 'justified' right now. +/mob/living/simple_animal/slime/proc/is_justified_to_discipline() + if(rabid) + return TRUE + if(target_mob) + if(ishuman(target_mob)) + var/mob/living/carbon/human/H = target_mob + if(istype(H.species, /datum/species/monkey)) + return FALSE + return TRUE + return FALSE + + +/mob/living/simple_animal/slime/get_description_interaction() + var/list/results = list() + + if(!stat) + results += "[desc_panel_image("slimebaton")]to stun the slime, if it's being bad." + + results += ..() + + return results + +/mob/living/simple_animal/slime/get_description_info() + var/list/lines = list() + var/intro_line = "Slimes are generally the test subjects of Xenobiology, with different colors having different properties. \ + They can be extremely dangerous if not handled properly." + lines.Add(intro_line) + lines.Add(null) // To pad the line breaks. + + var/list/rewards = list() + for(var/potential_color in slime_mutation) + var/mob/living/simple_animal/slime/S = potential_color + rewards.Add(initial(S.slime_color)) + var/reward_line = "This color of slime can mutate into [english_list(rewards)] colors, when it reproduces. It will do so when it has eatten enough." + lines.Add(reward_line) + lines.Add(null) + + lines.Add(description_info) + return lines.Join("\n") + diff --git a/code/modules/mob/living/simple_animal/slime/subtypes.dm b/code/modules/mob/living/simple_animal/slime/subtypes.dm new file mode 100644 index 0000000000..4f71f91d3f --- /dev/null +++ b/code/modules/mob/living/simple_animal/slime/subtypes.dm @@ -0,0 +1,697 @@ +// Tier 1 + +/mob/living/simple_animal/slime/purple + desc = "This slime is rather toxic to handle, as it is poisonous." + color = "#CC23FF" + slime_color = "purple" + coretype = /obj/item/slime_extract/purple + reagent_injected = "toxin" + + description_info = "This slime spreads a toxin when it attacks. A biosuit or other thick armor can protect from the toxic attack." + + slime_mutation = list( + /mob/living/simple_animal/slime/dark_purple, + /mob/living/simple_animal/slime/dark_blue, + /mob/living/simple_animal/slime/green, + /mob/living/simple_animal/slime + ) + + +/mob/living/simple_animal/slime/orange + desc = "This slime is known to be flammable and can ignite enemies." + color = "#FFA723" + slime_color = "orange" + coretype = /obj/item/slime_extract/orange + + description_info = "Attacks from this slime can ignite you. A firesuit can protect from the burning attacks of this slime." + + slime_mutation = list( + /mob/living/simple_animal/slime/dark_purple, + /mob/living/simple_animal/slime/yellow, + /mob/living/simple_animal/slime/red, + /mob/living/simple_animal/slime + ) + +/mob/living/simple_animal/slime/orange/post_attack(mob/living/L, intent) + if(intent != I_HELP) + L.adjust_fire_stacks(1) + if(prob(25)) + L.IgniteMob() + ..() + +/mob/living/simple_animal/slime/blue + desc = "This slime produces 'cryotoxin' and uses it against their foes. Very deadly to other slimes." + color = "#19FFFF" + slime_color = "blue" + coretype = /obj/item/slime_extract/blue + reagent_injected = "cryotoxin" + + description_info = "Attacks from this slime can chill you. A biosuit or other thick armor can protect from the chilling attack." + + slime_mutation = list( + /mob/living/simple_animal/slime/dark_blue, + /mob/living/simple_animal/slime/silver, + /mob/living/simple_animal/slime/pink, + /mob/living/simple_animal/slime + ) + + +/mob/living/simple_animal/slime/metal + desc = "This slime is a lot more resilient than the others, due to having a metamorphic metallic and sloped surface." + color = "#5F5F5F" + slime_color = "metal" + shiny = 1 + coretype = /obj/item/slime_extract/metal + + description_info = "This slime is a lot more durable and tough to damage than the others." + + resistance = 10 // Sloped armor is strong. + maxHealth = 250 + maxHealth_adult = 350 + + slime_mutation = list( + /mob/living/simple_animal/slime/silver, + /mob/living/simple_animal/slime/yellow, + /mob/living/simple_animal/slime/gold, + /mob/living/simple_animal/slime + ) + +// Tier 2 + +/mob/living/simple_animal/slime/yellow + desc = "This slime is very conductive, and is known to use electricity as a means of defense moreso than usual for slimes." + color = "#FFF423" + slime_color = "yellow" + coretype = /obj/item/slime_extract/yellow + + ranged = 1 + shoot_range = 3 + firing_lines = 1 + projectiletype = /obj/item/projectile/beam/lightning/slime + projectilesound = 'sound/weapons/gauss_shoot.ogg' // Closest thing to a 'thunderstrike' sound we have. + glows = TRUE + + description_info = "This slime will fire lightning attacks at enemies if they are at range, and generate electricity \ + for their stun attack faster than usual. Insulative or reflective armor can protect from the lightning." + + slime_mutation = list( + /mob/living/simple_animal/slime/bluespace, + /mob/living/simple_animal/slime/bluespace, + /mob/living/simple_animal/slime/metal, + /mob/living/simple_animal/slime/orange + ) + +/mob/living/simple_animal/slime/yellow/handle_regular_status_updates() + if(stat == CONSCIOUS) + if(prob(25)) + power_charge = between(0, power_charge + 1, 10) + ..() + +/obj/item/projectile/beam/lightning/slime + power = 15 + +/mob/living/simple_animal/slime/yellow/ClosestDistance() // Needed or else they won't eat monkeys outside of melee range. + if(target_mob && ishuman(target_mob)) + var/mob/living/carbon/human/H = target_mob + if(istype(H.species, /datum/species/monkey)) + return 1 + return ..() + + +/mob/living/simple_animal/slime/dark_purple + desc = "This slime produces ever-coveted phoron. Risky to handle but very much worth it." + color = "#CC23FF" + slime_color = "dark purple" + coretype = /obj/item/slime_extract/dark_purple + reagent_injected = "phoron" + + description_info = "This slime applies phoron to enemies it attacks. A biosuit or other thick armor can protect from the toxic attack. \ + If hit with a burning attack, it will erupt in flames." + + slime_mutation = list( + /mob/living/simple_animal/slime/purple, + /mob/living/simple_animal/slime/orange, + /mob/living/simple_animal/slime/ruby, + /mob/living/simple_animal/slime/ruby + ) + +/mob/living/simple_animal/slime/dark_purple/proc/ignite() + visible_message("\The [src] erupts in an inferno!") + for(var/turf/simulated/target_turf in view(2, src)) + target_turf.assume_gas("phoron", 30, 1500+T0C) + spawn(0) + target_turf.hotspot_expose(1500+T0C, 400) + qdel(src) + +/mob/living/simple_animal/slime/dark_purple/ex_act(severity) + log_and_message_admins("[src] ignited due to a chain reaction with an explosion.") + ignite() + +/mob/living/simple_animal/slime/dark_purple/fire_act(datum/gas_mixture/air, temperature, volume) + log_and_message_admins("[src] ignited due to exposure to fire.") + ignite() + +/mob/living/simple_animal/slime/dark_purple/bullet_act(var/obj/item/projectile/P, var/def_zone) + if(P.damage_type && P.damage_type == BURN && P.damage) // Most bullets won't trigger the explosion, as a mercy towards Security. + log_and_message_admins("[src] ignited due to bring hit by a burning projectile[P.firer ? " by [key_name(P.firer)]" : ""].") + ignite() + else + ..() + +/mob/living/simple_animal/slime/dark_purple/attackby(var/obj/item/weapon/W, var/mob/user) + if(istype(W) && W.force && W.damtype == BURN) + log_and_message_admins("[src] ignited due to being hit with a burning weapon ([W]) by [key_name(user)].") + ignite() + else + ..() + + + + +/mob/living/simple_animal/slime/dark_blue + desc = "This slime makes other entities near it feel much colder, and is more resilient to the cold. It tends to kill other slimes rather quickly." + color = "#2398FF" + glows = TRUE + slime_color = "dark blue" + coretype = /obj/item/slime_extract/dark_blue + + description_info = "This slime is immune to the cold, however water will still kill it. A winter coat or other cold-resistant clothing can protect from the chilling aura." + + slime_mutation = list( + /mob/living/simple_animal/slime/purple, + /mob/living/simple_animal/slime/blue, + /mob/living/simple_animal/slime/cerulean, + /mob/living/simple_animal/slime/cerulean + ) + + minbodytemp = 0 + cold_damage_per_tick = 0 + +/mob/living/simple_animal/slime/dark_blue/Life() + if(stat != DEAD) + cold_aura() + ..() + +/mob/living/simple_animal/slime/dark_blue/proc/cold_aura() + for(var/mob/living/L in view(2, src)) + var/protection = L.get_cold_protection() + + if(protection < 1) + var/cold_factor = abs(protection - 1) + var/delta = -20 + delta *= cold_factor + L.bodytemperature = max(50, delta) + var/turf/T = get_turf(src) + var/datum/gas_mixture/env = T.return_air() + if(env) + env.add_thermal_energy(-10 * 1000) + + +/mob/living/simple_animal/slime/silver + desc = "This slime is shiny, and can deflect lasers or other energy weapons directed at it." + color = "#AAAAAA" + slime_color = "silver" + coretype = /obj/item/slime_extract/silver + shiny = TRUE + + description_info = "Tasers, including the slime version, are ineffective against this slime. The slimebation still works." + + slime_mutation = list( + /mob/living/simple_animal/slime/metal, + /mob/living/simple_animal/slime/blue, + /mob/living/simple_animal/slime/amber, + /mob/living/simple_animal/slime/amber + ) + +/mob/living/simple_animal/slime/silver/bullet_act(var/obj/item/projectile/P, var/def_zone) + if(istype(P,/obj/item/projectile/beam) || istype(P, /obj/item/projectile/energy)) + visible_message("\The [src] reflects \the [P]!") + + // Find a turf near or on the original location to bounce to + var/new_x = P.starting.x + pick(0, 0, 0, -1, 1, -2, 2) + var/new_y = P.starting.y + pick(0, 0, 0, -1, 1, -2, 2) + var/turf/curloc = get_turf(src) + + // redirect the projectile + P.redirect(new_x, new_y, curloc, src) + return PROJECTILE_CONTINUE // complete projectile permutation + else + ..() + + +// Tier 3 + +/mob/living/simple_animal/slime/bluespace + desc = "Trapping this slime in a cell is generally futile, as it can teleport at will." + color = null + slime_color = "bluespace" + icon_state_override = "bluespace" + coretype = /obj/item/slime_extract/bluespace + + description_info = "This slime will teleport to attack something if it is within a range of seven tiles. The teleport has a cooldown of five seconds." + + slime_mutation = list( + /mob/living/simple_animal/slime/bluespace, + /mob/living/simple_animal/slime/bluespace, + /mob/living/simple_animal/slime/yellow, + /mob/living/simple_animal/slime/yellow + ) + + spattack_prob = 100 + spattack_min_range = 3 + spattack_max_range = 7 + var/last_tele = null // Uses world.time + var/tele_cooldown = 5 SECONDS + +/mob/living/simple_animal/slime/bluespace/ClosestDistance() // Needed or the SA AI won't ever try to teleport. + if(world.time > last_tele + tele_cooldown) + return spattack_max_range - 1 + return ..() + +/mob/living/simple_animal/slime/bluespace/SpecialAtkTarget() + // Teleport attack. + if(!target_mob) + to_chat(src, "There's nothing to teleport to.") + return FALSE + + if(world.time < last_tele + tele_cooldown) + to_chat(src, "You can't teleport right now, wait a few seconds.") + return FALSE + + var/list/nearby_things = range(1, target_mob) + var/list/valid_turfs = list() + + // All this work to just go to a non-dense tile. + for(var/turf/potential_turf in nearby_things) + var/valid_turf = TRUE + if(potential_turf.density) + continue + for(var/atom/movable/AM in potential_turf) + if(AM.density) + valid_turf = FALSE + if(valid_turf) + valid_turfs.Add(potential_turf) + + + + var/turf/T = get_turf(src) + var/turf/target_turf = pick(valid_turfs) + + if(!target_turf) + to_chat(src, "There wasn't an unoccupied spot to teleport to.") + return FALSE + + var/datum/effect/effect/system/spark_spread/s1 = new /datum/effect/effect/system/spark_spread + s1.set_up(5, 1, T) + var/datum/effect/effect/system/spark_spread/s2 = new /datum/effect/effect/system/spark_spread + s2.set_up(5, 1, target_turf) + + + T.visible_message("\The [src] vanishes!") + s1.start() + + forceMove(target_turf) + playsound(target_turf, 'sound/effects/phasein.ogg', 50, 1) + to_chat(src, "You teleport to \the [target_turf].") + + target_turf.visible_message("\The [src] appears!") + s2.start() + + last_tele = world.time + + if(Adjacent(target_mob)) + PunchTarget() + return TRUE + +/mob/living/simple_animal/slime/ruby + desc = "This slime has great physical strength." + color = "#FF3333" + slime_color = "ruby" + shiny = TRUE + glows = TRUE + coretype = /obj/item/slime_extract/ruby + + description_info = "This slime is unnaturally stronger, allowing it to hit much harder, take less damage, and be stunned for less time." + + slime_mutation = list( + /mob/living/simple_animal/slime/dark_purple, + /mob/living/simple_animal/slime/dark_purple, + /mob/living/simple_animal/slime/ruby, + /mob/living/simple_animal/slime/ruby + ) + +/mob/living/simple_animal/slime/ruby/New() + ..() + add_modifier(/datum/modifier/slime_strength, null, src) // Slime is always swole. + + +/mob/living/simple_animal/slime/amber + desc = "This slime seems to be an expert in the culinary arts, as they create their own food to share with others. \ + They would probably be very important to other slimes, if the other colors didn't try to kill them." + color = "#FFBB00" + slime_color = "amber" + shiny = TRUE + glows = TRUE + coretype = /obj/item/slime_extract/amber + + description_info = "This slime feeds nearby entities passively while it is alive. This can cause uncontrollable \ + slime growth and reproduction if not kept in check." + + slime_mutation = list( + /mob/living/simple_animal/slime/silver, + /mob/living/simple_animal/slime/silver, + /mob/living/simple_animal/slime/amber, + /mob/living/simple_animal/slime/amber + ) + +/mob/living/simple_animal/slime/amber/Life() + if(stat != DEAD) + feed_aura() + ..() + +/mob/living/simple_animal/slime/amber/proc/feed_aura() + for(var/mob/living/L in view(2, src)) + if(L == src) // Don't feed themselves, or it is impossible to stop infinite slimes without killing all of the ambers. + continue + if(isslime(L)) + var/mob/living/simple_animal/slime/S = L + S.adjust_nutrition(rand(15, 25)) + if(ishuman(L)) + var/mob/living/carbon/human/H = L + if(H.isSynthetic()) + continue + H.nutrition = between(0, H.nutrition + rand(15, 25), 600) + + + +/mob/living/simple_animal/slime/cerulean + desc = "This slime is generally superior in a wide range of attributes, compared to the common slime. The jack of all trades, but master of none." + color = "#4F7EAA" + slime_color = "cerulean" + coretype = /obj/item/slime_extract/cerulean + + // Less than the specialized slimes, but higher than the rest. + maxHealth = 200 + maxHealth_adult = 250 + + melee_damage_lower = 10 + melee_damage_upper = 30 + + move_to_delay = 3 + + + + slime_mutation = list( + /mob/living/simple_animal/slime/dark_blue, + /mob/living/simple_animal/slime/dark_blue, + /mob/living/simple_animal/slime/cerulean, + /mob/living/simple_animal/slime/cerulean + ) + +// Tier 4 + +/mob/living/simple_animal/slime/red + desc = "This slime is full of energy, and very aggressive. 'The red ones go faster.' seems to apply here." + color = "#FF3333" + slime_color = "red" + coretype = /obj/item/slime_extract/red + move_to_delay = 3 // The red ones go faster. + + description_info = "This slime is faster than the others. Attempting to discipline this slime will always cause it to go berserk." + + slime_mutation = list( + /mob/living/simple_animal/slime/red, + /mob/living/simple_animal/slime/oil, + /mob/living/simple_animal/slime/oil, + /mob/living/simple_animal/slime/orange + ) + + +/mob/living/simple_animal/slime/red/adjust_discipline(amount) + if(amount > 0) + if(!rabid) + enrage() // How dare you try to control the red slime. + say("Grrr...!") + + +/mob/living/simple_animal/slime/green + desc = "This slime is radioactive." + color = "#14FF20" + slime_color = "green" + coretype = /obj/item/slime_extract/green + glows = TRUE + reagent_injected = "radium" + var/rads = 25 + + description_info = "This slime will irradiate anything nearby passively, and will inject radium on attack. \ + A radsuit or other thick and radiation-hardened armor can protect from this. It will only radiate while alive." + + slime_mutation = list( + /mob/living/simple_animal/slime/purple, + /mob/living/simple_animal/slime/green, + /mob/living/simple_animal/slime/emerald, + /mob/living/simple_animal/slime/emerald + ) + +/mob/living/simple_animal/slime/green/Life() + if(stat != DEAD) + irradiate() + ..() + +/mob/living/simple_animal/slime/green/proc/irradiate() + radiation_repository.radiate(src, rads) + + +/mob/living/simple_animal/slime/pink + desc = "This slime has regenerative properties." + color = "#FF0080" + slime_color = "pink" + coretype = /obj/item/slime_extract/pink + glows = TRUE + + description_info = "This slime will passively heal nearby entities within two tiles, including itself. It will only do this while alive." + + slime_mutation = list( + /mob/living/simple_animal/slime/blue, + /mob/living/simple_animal/slime/light_pink, + /mob/living/simple_animal/slime/light_pink, + /mob/living/simple_animal/slime/pink + ) + +/mob/living/simple_animal/slime/pink/Life() + if(stat != DEAD) + heal_aura() + ..() + +/mob/living/simple_animal/slime/pink/proc/heal_aura() + for(var/mob/living/L in view(src, 2)) + if(L.stat == DEAD || L == target_mob) + continue + L.add_modifier(/datum/modifier/slime_heal, 5 SECONDS, src) + +/datum/modifier/slime_heal + name = "slime mending" + desc = "You feel somewhat gooy." + mob_overlay_state = "pink_sparkles" + + on_created_text = "Twinkling spores of goo surround you. It makes you feel healthier." + on_expired_text = "The spores of goo have faded, although you feel much healthier than before." + stacks = MODIFIER_STACK_EXTEND + +/datum/modifier/slime_heal/tick() + if(holder.stat == DEAD) // Required or else simple animals become immortal. + expire() + holder.adjustBruteLoss(-2) + holder.adjustFireLoss(-2) + holder.adjustToxLoss(-2) + holder.adjustOxyLoss(-2) + holder.adjustCloneLoss(-1) + + + +/mob/living/simple_animal/slime/gold + desc = "This slime absorbs energy, and cannot be stunned by normal means." + color = "#EEAA00" + shiny = TRUE + slime_color = "gold" + coretype = /obj/item/slime_extract/gold + description_info = "This slime is immune to the slimebaton and taser, and will actually charge the slime, however it will still discipline the slime." + + slime_mutation = list( + /mob/living/simple_animal/slime/metal, + /mob/living/simple_animal/slime/gold, + /mob/living/simple_animal/slime/sapphire, + /mob/living/simple_animal/slime/sapphire + ) + +/mob/living/simple_animal/slime/gold/Weaken(amount) + power_charge = between(0, power_charge + amount, 10) + return + +/mob/living/simple_animal/slime/gold/Stun(amount) + power_charge = between(0, power_charge + amount, 10) + return + +/mob/living/simple_animal/slime/gold/get_description_interaction() // So it doesn't say to use a baton on them. + return list() + + +// Tier 5 + +/mob/living/simple_animal/slime/oil + desc = "This slime is explosive and volatile. Smoking near it is probably a bad idea." + color = "#333333" + slime_color = "oil" + shiny = TRUE + coretype = /obj/item/slime_extract/oil + + description_info = "If this slime suffers damage from a fire or heat based source, or if it is caught inside \ + an explosion, it will explode. Rabid oil slimes will charge at enemies, then suicide-bomb themselves. \ + Bomb suits can protect from the explosion." + + slime_mutation = list( + /mob/living/simple_animal/slime/oil, + /mob/living/simple_animal/slime/oil, + /mob/living/simple_animal/slime/red, + /mob/living/simple_animal/slime/red + ) + +/mob/living/simple_animal/slime/oil/proc/explode() + if(stat != DEAD) + // explosion(src.loc, 1, 2, 4) + explosion(src.loc, 0, 2, 4) // A bit weaker since the suicide charger tended to gib the poor sod being targeted. + if(src) // Delete ourselves if the explosion didn't do it. + qdel(src) + +/mob/living/simple_animal/slime/oil/post_attack(var/mob/living/L, var/intent = I_HURT) + if(!rabid) + return ..() + if(intent == I_HURT || intent == I_GRAB) + say(pick("Sacrifice...!", "Sssss...", "Boom...!")) + sleep(2 SECOND) + log_and_message_admins("[src] has suicide-bombed themselves while trying to kill \the [L].") + explode() + +/mob/living/simple_animal/slime/oil/ex_act(severity) + log_and_message_admins("[src] exploded due to a chain reaction with another explosion.") + explode() + +/mob/living/simple_animal/slime/oil/fire_act(datum/gas_mixture/air, temperature, volume) + log_and_message_admins("[src] exploded due to exposure to fire.") + explode() + +/mob/living/simple_animal/slime/oil/bullet_act(var/obj/item/projectile/P, var/def_zone) + if(P.damage_type && P.damage_type == BURN && P.damage) // Most bullets won't trigger the explosion, as a mercy towards Security. + log_and_message_admins("[src] exploded due to bring hit by a burning projectile[P.firer ? " by [key_name(P.firer)]" : ""].") + explode() + else + ..() + +/mob/living/simple_animal/slime/oil/attackby(var/obj/item/weapon/W, var/mob/user) + if(istype(W) && W.force && W.damtype == BURN) + log_and_message_admins("[src] exploded due to being hit with a burning weapon ([W]) by [key_name(user)].") + explode() + else + ..() + + +/mob/living/simple_animal/slime/sapphire + desc = "This slime seems a bit brighter than the rest, both figuratively and literally." + color = "#2398FF" + slime_color = "sapphire" + shiny = TRUE + glows = TRUE + coretype = /obj/item/slime_extract/sapphire + + optimal_combat = TRUE // Lift combat AI restrictions to look smarter. + run_at_them = FALSE // Use fancy A* pathing. + astar_adjacent_proc = /turf/proc/TurfsWithAccess // Normal slimes don't care about cardinals (because BYOND) so smart slimes shouldn't as well. + move_to_delay = 3 // A* chasing is slightly slower in terms of movement speed than regular pathing so reducing this hopefully makes up for that. + + description_info = "This slime uses more robust tactics when fighting and won't hold back, so it is dangerous to be alone \ + with one if hostile, and especially dangerous if they outnumber you." + + slime_mutation = list( + /mob/living/simple_animal/slime/sapphire, + /mob/living/simple_animal/slime/sapphire, + /mob/living/simple_animal/slime/gold, + /mob/living/simple_animal/slime/gold + ) + +/mob/living/simple_animal/slime/emerald + desc = "This slime is faster than usual, even more so than the red slimes." + color = "#22FF22" + shiny = TRUE + glows = TRUE + slime_color = "emerald" + coretype = /obj/item/slime_extract/emerald + + description_info = "This slime will make everything around it, and itself, faster for a few seconds, if close by." + move_to_delay = 2 + + slime_mutation = list( + /mob/living/simple_animal/slime/green, + /mob/living/simple_animal/slime/green, + /mob/living/simple_animal/slime/emerald, + /mob/living/simple_animal/slime/emerald + ) + +/mob/living/simple_animal/slime/emerald/Life() + if(stat != DEAD) + zoom_aura() + ..() + +/mob/living/simple_animal/slime/emerald/proc/zoom_aura() + for(var/mob/living/L in view(src, 2)) + if(L.stat == DEAD || L == target_mob) + continue + L.add_modifier(/datum/modifier/technomancer/haste, 5 SECONDS, src) + +/mob/living/simple_animal/slime/light_pink + desc = "This slime seems a lot more peaceful than the others." + color = "#FF8888" + slime_color = "light_pink" + coretype = /obj/item/slime_extract/light_pink + + description_info = "This slime is effectively always disciplined initially." + obedience = 5 + discipline = 5 + + slime_mutation = list( + /mob/living/simple_animal/slime/green, + /mob/living/simple_animal/slime/green, + /mob/living/simple_animal/slime/emerald, + /mob/living/simple_animal/slime/emerald + ) + +// Special +/mob/living/simple_animal/slime/rainbow + desc = "This slime changes colors constantly." + color = null // Only slime subtype that uses a different icon_state. + slime_color = "rainbow" + coretype = /obj/item/slime_extract/rainbow + icon_state_override = "rainbow" + + description_info = "This slime is considered to be the same color as all other slime colors at the same time for the purposes of \ + other slimes being friendly to them, and therefore will never be harmed by another slime. \ + Attacking this slime will provoke the wrath of all slimes within range." + + slime_mutation = list( + /mob/living/simple_animal/slime/rainbow, + /mob/living/simple_animal/slime/rainbow, + /mob/living/simple_animal/slime/rainbow, + /mob/living/simple_animal/slime/rainbow + ) + +/mob/living/simple_animal/slime/rainbow/New() + unify() + ..() + +// The RD's pet slime. +/mob/living/simple_animal/slime/rainbow/kendrick + name = "Kendrick" + desc = "The Research Director's pet slime. It shifts colors constantly." + +/mob/living/simple_animal/slime/rainbow/kendrick/New() + pacify() + ..() \ No newline at end of file diff --git a/code/modules/mob/living/voice/voice.dm b/code/modules/mob/living/voice/voice.dm index dbace03e52..3bc7929eac 100644 --- a/code/modules/mob/living/voice/voice.dm +++ b/code/modules/mob/living/voice/voice.dm @@ -111,7 +111,8 @@ //Speech bubbles. if(comm) var/speech_bubble_test = say_test(message) - var/image/speech_bubble = image('icons/mob/talk.dmi',comm,"h[speech_bubble_test]") + var/speech_type = speech_bubble_appearance() + var/image/speech_bubble = image('icons/mob/talk.dmi',comm,"[speech_type][speech_bubble_test]") spawn(30) qdel(speech_bubble) @@ -121,6 +122,12 @@ ..(message, speaking, verb, alt_name, whispering) //mob/living/say() can do the actual talking. +// Proc: speech_bubble_appearance() +// Parameters: 0 +// Description: Gets the correct icon_state information for chat bubbles to work. +/mob/living/voice/speech_bubble_appearance() + return "comm" + /mob/living/voice/say_understands(var/other,var/datum/language/speaking = null) //These only pertain to common. Languages are handled by mob/say_understands() if (!speaking) diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index ba5b24dbe7..b01d346c23 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -536,13 +536,40 @@ proc/is_blind(A) return threatcount -/mob/living/simple_animal/hostile/assess_perp(var/obj/access_obj, var/check_access, var/auth_weapons, var/check_records, var/check_arrest) +/mob/living/simple_animal/assess_perp(var/obj/access_obj, var/check_access, var/auth_weapons, var/check_records, var/check_arrest) var/threatcount = ..() if(. == SAFE_PERP) return SAFE_PERP if(!istype(src, /mob/living/simple_animal/retaliate/goat)) + if(hostile) + if(faction != "neutral") // Otherwise Runtime gets killed. + threatcount += 4 + return threatcount + +// Beepsky will (try to) only beat 'bad' slimes. +/mob/living/simple_animal/slime/assess_perp(var/obj/access_obj, var/check_access, var/auth_weapons, var/check_records, var/check_arrest) + var/threatcount = 0 + + if(stat == DEAD) + return SAFE_PERP + + if(is_justified_to_discipline()) threatcount += 4 +/* + if(discipline && !rabid) + if(!target_mob || istype(target_mob, /mob/living/carbon/human/monkey)) + return SAFE_PERP + + if(target_mob) + threatcount += 4 + + if(victim) + threatcount += 4 +*/ + if(rabid) + threatcount = 10 + return threatcount #undef SAFE_PERP diff --git a/code/modules/mob/modifiers.dm b/code/modules/mob/modifiers.dm index 0b39c9e275..95d3db1e93 100644 --- a/code/modules/mob/modifiers.dm +++ b/code/modules/mob/modifiers.dm @@ -92,7 +92,7 @@ /mob/living/proc/add_modifier(var/modifier_type, var/expire_at = null, var/mob/living/origin = null) // First, check if the mob already has this modifier. for(var/datum/modifier/M in modifiers) - if(istype(modifier_type, M)) + if(ispath(modifier_type, M)) switch(M.stacks) if(MODIFIER_STACK_FORBID) return // Stop here. diff --git a/code/modules/mob/say.dm b/code/modules/mob/say.dm index f5445e0e5a..b5add4f23f 100644 --- a/code/modules/mob/say.dm +++ b/code/modules/mob/say.dm @@ -35,6 +35,9 @@ usr << "Speech is currently admin-disabled." return + if(!client) + return // Clientless mobs shouldn't be trying to talk in deadchat. + if(!src.client.holder) if(!config.dsay_allowed) src << "Deadchat is globally muted." diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index 085f601aef..03e4227f6e 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -161,40 +161,6 @@ qdel(src) return O -/mob/living/carbon/human/proc/slimeize(adult as num, reproduce as num) - if (transforming) - return - for(var/obj/item/W in src) - drop_from_inventory(W) - regenerate_icons() - transforming = 1 - canmove = 0 - icon = null - invisibility = 101 - for(var/t in organs) - qdel(t) - - var/mob/living/carbon/slime/new_slime - if(reproduce) - var/number = pick(14;2,3,4) //reproduce (has a small chance of producing 3 or 4 offspring) - var/list/babies = list() - for(var/i=1,i<=number,i++) - var/mob/living/carbon/slime/M = new/mob/living/carbon/slime(loc) - M.nutrition = round(nutrition/number) - step_away(M,src) - babies += M - new_slime = pick(babies) - else - new_slime = new /mob/living/carbon/slime(loc) - if(adult) - new_slime.is_adult = 1 - else - new_slime.key = key - - new_slime << "You are now a slime. Skreee!" - qdel(src) - return - /mob/living/carbon/human/proc/corgize() if (transforming) return diff --git a/code/modules/mob/typing_indicator.dm b/code/modules/mob/typing_indicator.dm index 8a8d92f2c7..0ce5f390c4 100644 --- a/code/modules/mob/typing_indicator.dm +++ b/code/modules/mob/typing_indicator.dm @@ -12,7 +12,7 @@ mob/var/obj/effect/decal/typing_indicator if(!typing_indicator) typing_indicator = new typing_indicator.icon = 'icons/mob/talk.dmi' - typing_indicator.icon_state = "typing" + typing_indicator.icon_state = "[speech_bubble_appearance()]_typing" if(client && !stat) typing_indicator.invisibility = invisibility diff --git a/code/modules/organs/robolimbs.dm b/code/modules/organs/robolimbs.dm index a93f37bd56..a055409531 100644 --- a/code/modules/organs/robolimbs.dm +++ b/code/modules/organs/robolimbs.dm @@ -44,6 +44,7 @@ var/const/standard_monitor_styles = "blank=ipc_blank;\ var/parts = BP_ALL //Defines what parts said brand can replace on a body. var/health_hud_intensity = 1 // Intensity modifier for the health GUI indicator. var/suggested_species = "Human" //If it should make the torso a species + var/speech_bubble_appearance = "synthetic" // What icon_state to use for speech bubbles when talking. Check talk.dmi for all the icons. /datum/robolimb/unbranded_monitor company = "Unbranded Monitor" @@ -135,6 +136,7 @@ var/const/standard_monitor_styles = "blank=ipc_blank;\ unavailable_to_build = 1 lifelike = 1 blood_color = "#CCCCCC" + speech_bubble_appearance = "normal" /datum/robolimb/wardtakahashi company = "Ward-Takahashi" diff --git a/code/modules/paperwork/paperbin.dm b/code/modules/paperwork/paperbin.dm index f6d192276f..4a81179c72 100644 --- a/code/modules/paperwork/paperbin.dm +++ b/code/modules/paperwork/paperbin.dm @@ -19,7 +19,7 @@ /obj/item/weapon/paper_bin/MouseDrop(mob/user as mob) if((user == usr && (!( usr.restrained() ) && (!( usr.stat ) && (usr.contents.Find(src) || in_range(src, usr)))))) - if(!istype(usr, /mob/living/carbon/slime) && !istype(usr, /mob/living/simple_animal)) + if(!istype(usr, /mob/living/simple_animal)) if( !usr.get_active_hand() ) //if active hand is empty var/mob/living/carbon/human/H = user var/obj/item/organ/external/temp = H.organs_by_name["r_hand"] diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm index c58bd2f166..d3cde87049 100644 --- a/code/modules/power/cell.dm +++ b/code/modules/power/cell.dm @@ -6,6 +6,19 @@ ..() charge = maxcharge update_icon() + if(self_recharge) + processing_objects |= src + +/obj/item/weapon/cell/Destroy() + if(self_recharge) + processing_objects -= src + return ..() + +/obj/item/weapon/cell/process() + if(self_recharge) + give(charge_amount / CELLRATE) + else + return PROCESS_KILL /obj/item/weapon/cell/drain_power(var/drain_check, var/surge, var/power = 0) diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm index bddc1fe490..0bdf518a2c 100644 --- a/code/modules/projectiles/guns/energy.dm +++ b/code/modules/projectiles/guns/energy.dm @@ -174,4 +174,17 @@ power_supply = new /obj/item/weapon/cell/device/weapon(src) self_recharge = 1 processing_objects.Add(src) - update_icon() \ No newline at end of file + update_icon() + +/obj/item/weapon/gun/energy/get_description_interaction() + var/list/results = list() + + if(!battery_lock && !self_recharge) + if(power_supply) + results += "[desc_panel_image("offhand")]to remove the weapon cell." + else + results += "[desc_panel_image("weapon cell")]to add a new weapon cell." + + results += ..() + + return results \ No newline at end of file diff --git a/code/modules/projectiles/guns/energy/temperature.dm b/code/modules/projectiles/guns/energy/temperature.dm index 64f708891b..5e24564292 100644 --- a/code/modules/projectiles/guns/energy/temperature.dm +++ b/code/modules/projectiles/guns/energy/temperature.dm @@ -2,78 +2,14 @@ name = "temperature gun" icon_state = "freezegun" fire_sound = 'sound/weapons/pulse3.ogg' - desc = "A gun that changes temperatures. It has a small label on the side, 'More extreme temperatures will cost more charge!'" - var/temperature = T20C - var/current_temperature = T20C - charge_cost = 24 + desc = "A gun that can add or remove heat from entities it hits. In other words, it can fire 'cold', and 'hot' beams." + charge_cost = 240 origin_tech = list(TECH_COMBAT = 3, TECH_MATERIAL = 4, TECH_POWER = 3, TECH_MAGNET = 2) slot_flags = SLOT_BELT|SLOT_BACK projectile_type = /obj/item/projectile/temp - cell_type = /obj/item/weapon/cell/high - -/obj/item/weapon/gun/energy/temperature/New() - ..() - processing_objects.Add(src) - - -/obj/item/weapon/gun/energy/temperature/Destroy() - processing_objects.Remove(src) - ..() - - -/obj/item/weapon/gun/energy/temperature/attack_self(mob/living/user as mob) - user.set_machine(src) - var/temp_text = "" - if(temperature > (T0C - 50)) - temp_text = "[temperature] ([round(temperature-T0C)]°C) ([round(temperature*1.8-459.67)]°F)" - else - temp_text = "[temperature] ([round(temperature-T0C)]°C) ([round(temperature*1.8-459.67)]°F)" - - var/dat = {"Freeze Gun Configuration:
- Current output temperature: [temp_text]
- Target output temperature: - - - [current_temperature] + + +
- "} - - user << browse(dat, "window=freezegun;size=450x300;can_resize=1;can_close=1;can_minimize=1") - onclose(user, "window=freezegun", src) - - -/obj/item/weapon/gun/energy/temperature/Topic(href, href_list) - if (..()) - return 1 - usr.set_machine(src) - src.add_fingerprint(usr) - - - - if(href_list["temp"]) - var/amount = text2num(href_list["temp"]) - if(amount > 0) - src.current_temperature = min(500, src.current_temperature+amount) - else - src.current_temperature = max(0, src.current_temperature+amount) - if (istype(src.loc, /mob)) - attack_self(src.loc) - src.add_fingerprint(usr) - return - - -/obj/item/weapon/gun/energy/temperature/process() - switch(temperature) - if(0 to 100) charge_cost = 1000 - if(100 to 250) charge_cost = 500 - if(251 to 300) charge_cost = 100 - if(301 to 400) charge_cost = 500 - if(401 to 500) charge_cost = 1000 - - if(current_temperature != temperature) - var/difference = abs(current_temperature - temperature) - if(difference >= 10) - if(current_temperature < temperature) - temperature -= 10 - else - temperature += 10 - else - temperature = current_temperature + firemodes = list( + list(mode_name="endothermic beam", projectile_type = /obj/item/projectile/temp, charge_cost = 240), + list(mode_name="exothermic beam", projectile_type = /obj/item/projectile/temp/hot, charge_cost = 240), + ) diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index f5a7460cc3..3144f9eb09 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -76,7 +76,7 @@ /obj/item/projectile/proc/on_hit(var/atom/target, var/blocked = 0, var/def_zone = null) if(blocked >= 100) return 0//Full block if(!isliving(target)) return 0 - if(isanimal(target)) return 0 +// if(isanimal(target)) return 0 var/mob/living/L = target L.apply_effects(stun, weaken, paralyze, irradiate, stutter, eyeblur, drowsy, agony, blocked) // add in AGONY! return 1 diff --git a/code/modules/projectiles/projectile/change.dm b/code/modules/projectiles/projectile/change.dm index b389d39153..6f19b29bbb 100644 --- a/code/modules/projectiles/projectile/change.dm +++ b/code/modules/projectiles/projectile/change.dm @@ -52,7 +52,7 @@ Robot.mmi = new /obj/item/device/mmi(new_mob) Robot.mmi.transfer_identity(M) //Does not transfer key/client. if("slime") - new_mob = new /mob/living/carbon/slime(M.loc) + new_mob = new /mob/living/simple_animal/slime(M.loc) new_mob.universal_speak = 1 else var/mob/living/carbon/human/H diff --git a/code/modules/projectiles/projectile/special.dm b/code/modules/projectiles/projectile/special.dm index c15e7cda4a..dd268f09b7 100644 --- a/code/modules/projectiles/projectile/special.dm +++ b/code/modules/projectiles/projectile/special.dm @@ -35,19 +35,45 @@ icon_state = "ice_2" damage = 0 damage_type = BURN + pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE nodamage = 1 - check_armour = "energy" - var/temperature = 300 + check_armour = "energy" // It actually checks heat/cold protection. + var/target_temperature = 50 light_range = 2 light_power = 0.5 light_color = "#55AAFF" +/obj/item/projectile/temp/on_hit(atom/target, blocked = FALSE) + ..() + if(isliving(target)) + var/mob/living/L = target - on_hit(var/atom/target, var/blocked = 0)//These two could likely check temp protection on the mob - if(istype(target, /mob/living)) - var/mob/M = target - M.bodytemperature = temperature - return 1 + var/protection = null + var/potential_temperature_delta = null + var/new_temperature = L.bodytemperature + + if(target_temperature >= T20C) // Make it cold. + protection = L.get_cold_protection(target_temperature) + potential_temperature_delta = 75 + new_temperature = max(new_temperature - potential_temperature_delta, target_temperature) + else // Make it hot. + protection = L.get_heat_protection(target_temperature) + potential_temperature_delta = 200 // Because spacemen temperature needs stupid numbers to actually hurt people. + new_temperature = min(new_temperature + potential_temperature_delta, target_temperature) + + var/temp_factor = abs(protection - 1) + + new_temperature = round(new_temperature * temp_factor) + L.bodytemperature = new_temperature + +// L.bodytemperature = between(target_temperature,(L.bodytemperature - ((L.bodytemperature + potential_temperature_delta) * temp_factor) ), L.bodytemperature) + world << "Temperature of [L] is now [L.bodytemperature]." + + return 1 + +/obj/item/projectile/temp/hot + name = "heat beam" + target_temperature = 1000 /obj/item/projectile/meteor name = "meteor" diff --git a/code/modules/reagents/Chemistry-Holder.dm b/code/modules/reagents/Chemistry-Holder.dm index d634711379..ab83fbe8a0 100644 --- a/code/modules/reagents/Chemistry-Holder.dm +++ b/code/modules/reagents/Chemistry-Holder.dm @@ -381,10 +381,6 @@ 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-Machinery.dm b/code/modules/reagents/Chemistry-Machinery.dm index ccf7c62ac1..3c71a0b089 100644 --- a/code/modules/reagents/Chemistry-Machinery.dm +++ b/code/modules/reagents/Chemistry-Machinery.dm @@ -2,7 +2,7 @@ #define LIQUID 2 #define GAS 3 -#define REAGENTS_PER_SHEET 20 + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -294,6 +294,7 @@ /obj/item/stack/material/phoron = "phoron", /obj/item/stack/material/gold = "gold", /obj/item/stack/material/silver = "silver", + /obj/item/stack/material/platinum = "platinum", /obj/item/stack/material/mhydrogen = "hydrogen" ) @@ -500,5 +501,3 @@ qdel(O) if (beaker.reagents.total_volume >= beaker.reagents.maximum_volume) break - -#undef REAGENTS_PER_SHEET diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Core.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Core.dm index f6208f59ff..6fb44ad814 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Core.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Core.dm @@ -133,23 +133,19 @@ /datum/reagent/water/touch_mob(var/mob/living/L, var/amount) if(istype(L)) + // First, kill slimes. + if(istype(L, /mob/living/simple_animal/slime)) + var/mob/living/simple_animal/slime/S = L + S.adjustToxLoss(15 * amount) + S.visible_message("[S]'s flesh sizzles where the water touches it!", "Your flesh burns in the water!") + + // Then extinguish people on fire. var/needed = L.fire_stacks * 5 if(amount > needed) L.ExtinguishMob() L.adjust_fire_stacks(-(amount / 5)) remove_self(needed) -/datum/reagent/water/affect_touch(var/mob/living/carbon/M, var/alien, var/removed) - if(istype(M, /mob/living/carbon/slime)) - var/mob/living/carbon/slime/S = M - S.adjustToxLoss(15 * removed) // Babies have 150 health, adults have 200; So, 10 units and 13.5 - if(!S.client) - if(S.Target) // Like cats - S.Target = null - ++S.Discipline - if(dose == removed) - S.visible_message("[S]'s flesh sizzles where the water touches it!", "Your flesh burns in the water!") - /datum/reagent/fuel name = "Welding fuel" id = "fuel" diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm index 6732f4c192..8cfb1b5e93 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Food-Drinks.dm @@ -287,7 +287,7 @@ M.bodytemperature = max(M.bodytemperature - 10 * TEMPERATURE_DAMAGE_COEFFICIENT, 0) if(prob(1)) M.emote("shiver") - if(istype(M, /mob/living/carbon/slime)) + if(istype(M, /mob/living/simple_animal/slime)) M.bodytemperature = max(M.bodytemperature - rand(10,20), 0) holder.remove_reagent("capsaicin", 5) @@ -319,7 +319,7 @@ M.apply_effect(2, AGONY, 0) if(prob(5)) M.visible_message("[M] [pick("dry heaves!","coughs!","splutters!")]", "You feel like your insides are burning!") - if(istype(M, /mob/living/carbon/slime)) + if(istype(M, /mob/living/simple_animal/slime)) M.bodytemperature += rand(10, 25) holder.remove_reagent("frostoil", 5) @@ -404,7 +404,7 @@ M.apply_effect(4, AGONY, 0) if(prob(5)) M.visible_message("[M] [pick("dry heaves!","coughs!","splutters!")]", "You feel like your insides are burning!") - if(istype(M, /mob/living/carbon/slime)) + if(istype(M, /mob/living/simple_animal/slime)) M.bodytemperature += rand(15, 30) holder.remove_reagent("frostoil", 5) diff --git a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Other.dm b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Other.dm index 0a7c78f952..c554959435 100644 --- a/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Other.dm +++ b/code/modules/reagents/Chemistry-Reagents/Chemistry-Reagents-Other.dm @@ -169,6 +169,14 @@ reagent_state = SOLID color = "#B8B8C0" +/datum/reagent/platinum + name = "Platinum" + id = "platinum" + description = "Platinum is a dense, malleable, ductile, highly unreactive, precious, gray-white transition metal. It is very resistant to corrosion." + taste_description = "metal" + reagent_state = SOLID + color = "#777777" + /datum/reagent/uranium/affect_touch(var/mob/living/carbon/M, var/alien, var/removed) affect_ingest(M, alien, removed) @@ -298,7 +306,7 @@ S.dirt = 0 T.clean_blood() - for(var/mob/living/carbon/slime/M in T) + for(var/mob/living/simple_animal/slime/M in T) M.adjustToxLoss(rand(5, 10)) /datum/reagent/space_cleaner/affect_touch(var/mob/living/carbon/M, var/alien, var/removed) diff --git a/code/modules/reagents/Chemistry-Recipes.dm b/code/modules/reagents/Chemistry-Recipes.dm index 8df309b1b8..5e38218ac0 100644 --- a/code/modules/reagents/Chemistry-Recipes.dm +++ b/code/modules/reagents/Chemistry-Recipes.dm @@ -604,16 +604,75 @@ /* Solidification */ -/datum/chemical_reaction/phoronsolidification +/datum/chemical_reaction/solidification + name = "Solid Iron" + id = "solidiron" + result = null + required_reagents = list("frostoil" = 5, "iron" = REAGENTS_PER_SHEET) + result_amount = 1 + var/sheet_to_give = /obj/item/stack/material/iron + +/datum/chemical_reaction/solidification/on_reaction(var/datum/reagents/holder, var/created_volume) + new sheet_to_give(get_turf(holder.my_atom), created_volume) + return + + +/datum/chemical_reaction/solidification/phoron name = "Solid Phoron" id = "solidphoron" - result = null - required_reagents = list("iron" = 5, "frostoil" = 5, "phoron" = 20) - result_amount = 1 + required_reagents = list("frostoil" = 5, "phoron" = REAGENTS_PER_SHEET) + sheet_to_give = /obj/item/stack/material/phoron + + +/datum/chemical_reaction/solidification/silver + name = "Solid Silver" + id = "solidsilver" + required_reagents = list("frostoil" = 5, "silver" = REAGENTS_PER_SHEET) + sheet_to_give = /obj/item/stack/material/silver + + +/datum/chemical_reaction/solidification/gold + name = "Solid Gold" + id = "solidgold" + required_reagents = list("frostoil" = 5, "gold" = REAGENTS_PER_SHEET) + sheet_to_give = /obj/item/stack/material/gold + + +/datum/chemical_reaction/solidification/platinum + name = "Solid Platinum" + id = "solidplatinum" + required_reagents = list("frostoil" = 5, "platinum" = REAGENTS_PER_SHEET) + sheet_to_give = /obj/item/stack/material/platinum + + +/datum/chemical_reaction/solidification/uranium + name = "Solid Uranium" + id = "soliduranium" + required_reagents = list("frostoil" = 5, "uranium" = REAGENTS_PER_SHEET) + sheet_to_give = /obj/item/stack/material/uranium + + +/datum/chemical_reaction/solidification/hydrogen + name = "Solid Hydrogen" + id = "solidhydrogen" + required_reagents = list("frostoil" = 100, "hydrogen" = REAGENTS_PER_SHEET) + sheet_to_give = /obj/item/stack/material/mhydrogen + + +// These are from Xenobio. +/datum/chemical_reaction/solidification/steel + name = "Solid Steel" + id = "solidsteel" + required_reagents = list("frostoil" = 5, "steel" = REAGENTS_PER_SHEET) + sheet_to_give = /obj/item/stack/material/steel + + +/datum/chemical_reaction/solidification/plasteel + name = "Solid Plasteel" + id = "solidplasteel" + required_reagents = list("frostoil" = 10, "plasteel" = REAGENTS_PER_SHEET) + sheet_to_give = /obj/item/stack/material/plasteel -/datum/chemical_reaction/phoronsolidification/on_reaction(var/datum/reagents/holder, var/created_volume) - new /obj/item/stack/material/phoron(get_turf(holder.my_atom), created_volume) - return /datum/chemical_reaction/plastication name = "Plastic" @@ -1038,30 +1097,6 @@ /datum/chemical_reaction/aluminum_paint/send_data() return "#F0F8FF" -/* Slime cores */ - -/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)) - return ..() - return 0 - -/datum/chemical_reaction/slime/golem - name = "Prometheans" - id = "m_promethean" - result = null - required_reagents = list("mutationtoxin" = 1) - result_amount = 1 - required = /obj/item/weapon/reagent_containers/food/snacks/monkeycube - -/datum/chemical_reaction/slime/golem/on_reaction(var/datum/reagents/holder) - var/location = get_turf(holder.my_atom) - new /obj/item/slime_cube(location) - qdel(holder.my_atom) - /* Food */ /datum/chemical_reaction/food/tofu diff --git a/code/modules/reagents/reagent_containers/food/snacks.dm b/code/modules/reagents/reagent_containers/food/snacks.dm index f28b8c6b62..908c7d6332 100644 --- a/code/modules/reagents/reagent_containers/food/snacks.dm +++ b/code/modules/reagents/reagent_containers/food/snacks.dm @@ -90,8 +90,6 @@ user << "\The [blocked] is in the way!" return - if(!istype(M, /mob/living/carbon/slime)) //If you're feeding it to someone else. - if (fullness <= (550 * (1 + M.overeatduration / 1000))) user.visible_message("[user] attempts to feed [M] [src].") else diff --git a/code/modules/reagents/reagent_containers/glass.dm b/code/modules/reagents/reagent_containers/glass.dm index bd670cc8bc..ba1df21038 100644 --- a/code/modules/reagents/reagent_containers/glass.dm +++ b/code/modules/reagents/reagent_containers/glass.dm @@ -42,8 +42,7 @@ /obj/machinery/smartfridge/, /obj/machinery/biogenerator, /obj/structure/frame, - /obj/machinery/radiocarbon_spectrometer, - /obj/machinery/xenobio2/manualinjector + /obj/machinery/radiocarbon_spectrometer ) /obj/item/weapon/reagent_containers/glass/New() diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm index fea929006e..536a069474 100644 --- a/code/modules/reagents/reagent_containers/syringes.dm +++ b/code/modules/reagents/reagent_containers/syringes.dm @@ -79,9 +79,6 @@ user << "There is already a blood sample in this syringe." return if(istype(target, /mob/living/carbon)) - if(istype(target, /mob/living/carbon/slime)) - user << "You are unable to locate any blood." - return var/amount = reagents.get_free_space() var/mob/living/carbon/T = target if(!T.dna) diff --git a/code/modules/recycling/disposal.dm b/code/modules/recycling/disposal.dm index 28b2e0575b..228d4296ed 100644 --- a/code/modules/recycling/disposal.dm +++ b/code/modules/recycling/disposal.dm @@ -471,6 +471,8 @@ qdel(H) /obj/machinery/disposal/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if(istype(mover, /obj/item/projectile)) + return 1 if (istype(mover,/obj/item) && mover.throwing) var/obj/item/I = mover if(istype(I, /obj/item/projectile)) diff --git a/code/modules/research/designs.dm b/code/modules/research/designs.dm index fd75b22eaf..55981fd672 100644 --- a/code/modules/research/designs.dm +++ b/code/modules/research/designs.dm @@ -592,6 +592,20 @@ other types of metals and chemistry for reagents). build_path = /obj/item/weapon/gun/energy/floragun sort_string = "TBAAA" +/datum/design/item/weapon/slimebation + id = "slimebation" + req_tech = list(TECH_MATERIAL = 2, TECH_BIO = 3, TECH_POWER = 3, TECH_COMBAT = 3) + materials = list(DEFAULT_WALL_MATERIAL = 5000) + build_path = /obj/item/weapon/melee/baton/slime + sort_string = "TBAAB" + +/datum/design/item/weapon/slimetaser + id = "slimetaser" + req_tech = list(TECH_MATERIAL = 3, TECH_BIO = 4, TECH_POWER = 4, TECH_COMBAT = 4) + materials = list(DEFAULT_WALL_MATERIAL = 5000) + build_path = /obj/item/weapon/gun/energy/taser/xeno + sort_string = "TBAAC" + /datum/design/item/stock_part/subspace_ansible id = "s-ansible" req_tech = list(TECH_DATA = 3, TECH_MAGNET = 4, TECH_MATERIAL = 4, TECH_BLUESPACE = 2) diff --git a/code/modules/surgery/slimes.dm b/code/modules/surgery/slimes.dm index 038dc7f6d4..256f4d377f 100644 --- a/code/modules/surgery/slimes.dm +++ b/code/modules/surgery/slimes.dm @@ -3,10 +3,10 @@ ////////////////////////////////////////////////////////////////// /datum/surgery_step/slime - is_valid_target(mob/living/carbon/slime/target) - return istype(target, /mob/living/carbon/slime/) + is_valid_target(mob/living/simple_animal/slime/target) + return istype(target, /mob/living/simple_animal/slime/) - can_use(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) + can_use(mob/living/user, mob/living/simple_animal/slime/target, target_zone, obj/item/tool) return target.stat == 2 /datum/surgery_step/slime/cut_flesh @@ -19,19 +19,19 @@ min_duration = 30 max_duration = 50 - can_use(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) + can_use(mob/living/user, mob/living/simple_animal/slime/target, target_zone, obj/item/tool) return ..() && istype(target) && target.core_removal_stage == 0 - begin_step(mob/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) + begin_step(mob/user, mob/living/simple_animal/slime/target, target_zone, obj/item/tool) user.visible_message("[user] starts cutting through [target]'s flesh with \the [tool].", \ "You start cutting through [target]'s flesh with \the [tool].") - end_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) + end_step(mob/living/user, mob/living/simple_animal/slime/target, target_zone, obj/item/tool) user.visible_message("[user] cuts through [target]'s flesh with \the [tool].", \ "You cut through [target]'s flesh with \the [tool], revealing its silky innards.") target.core_removal_stage = 1 - fail_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) + fail_step(mob/living/user, mob/living/simple_animal/slime/target, target_zone, obj/item/tool) user.visible_message("[user]'s hand slips, tearing [target]'s flesh with \the [tool]!", \ "Your hand slips, tearing [target]'s flesh with \the [tool]!") @@ -45,19 +45,19 @@ min_duration = 30 max_duration = 50 - can_use(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) + can_use(mob/living/user, mob/living/simple_animal/slime/target, target_zone, obj/item/tool) return ..() && istype(target) && target.core_removal_stage == 1 - begin_step(mob/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) + begin_step(mob/user, mob/living/simple_animal/slime/target, target_zone, obj/item/tool) user.visible_message("[user] starts cutting [target]'s silky innards apart with \the [tool].", \ "You start cutting [target]'s silky innards apart with \the [tool].") - end_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) + end_step(mob/living/user, mob/living/simple_animal/slime/target, target_zone, obj/item/tool) user.visible_message("[user] cuts [target]'s innards apart with \the [tool], exposing the cores.", \ "You cut [target]'s innards apart with \the [tool], exposing the cores.") target.core_removal_stage = 2 - fail_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) + fail_step(mob/living/user, mob/living/simple_animal/slime/target, target_zone, obj/item/tool) user.visible_message("[user]'s hand slips, tearing [target]'s innards with \the [tool]!", \ "Your hand slips, tearing [target]'s innards with \the [tool]!") @@ -70,14 +70,14 @@ min_duration = 50 max_duration = 70 - can_use(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) + can_use(mob/living/user, mob/living/simple_animal/slime/target, target_zone, obj/item/tool) return ..() && (istype(target) && target.core_removal_stage == 2 && target.cores > 0) //This is being passed a human as target, unsure why. - begin_step(mob/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) + begin_step(mob/user, mob/living/simple_animal/slime/target, target_zone, obj/item/tool) user.visible_message("[user] starts cutting out one of [target]'s cores with \the [tool].", \ "You start cutting out one of [target]'s cores with \the [tool].") - end_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) + end_step(mob/living/user, mob/living/simple_animal/slime/target, target_zone, obj/item/tool) target.cores-- user.visible_message("[user] cuts out one of [target]'s cores with \the [tool].",, \ "You cut out one of [target]'s cores with \the [tool]. [target.cores] cores left.") @@ -85,9 +85,9 @@ if(target.cores >= 0) new target.coretype(target.loc) if(target.cores <= 0) - target.icon_state = "[target.colour] baby slime dead-nocore" + target.icon_state = "slime extracted" - fail_step(mob/living/user, mob/living/carbon/slime/target, target_zone, obj/item/tool) + fail_step(mob/living/user, mob/living/simple_animal/slime/target, target_zone, obj/item/tool) user.visible_message("[user]'s hand slips, causing \him to miss the core!", \ "Your hand slips, causing you to miss the core!") \ No newline at end of file diff --git a/code/modules/ventcrawl/ventcrawl.dm b/code/modules/ventcrawl/ventcrawl.dm index 1ece024833..8978305ec2 100644 --- a/code/modules/ventcrawl/ventcrawl.dm +++ b/code/modules/ventcrawl/ventcrawl.dm @@ -35,8 +35,8 @@ var/list/ventcrawl_machinery = list( remove_ventcrawl() add_ventcrawl(loc) -/mob/living/carbon/slime/can_ventcrawl() - if(Victim) +/mob/living/simple_animal/slime/can_ventcrawl() + if(victim) to_chat(src, "You cannot ventcrawl while feeding.") return FALSE . = ..() diff --git a/code/modules/xenobio/items/extracts.dm b/code/modules/xenobio/items/extracts.dm new file mode 100644 index 0000000000..cf3e96c52a --- /dev/null +++ b/code/modules/xenobio/items/extracts.dm @@ -0,0 +1,973 @@ +// Base +/obj/item/slime_extract + name = "slime extract" + desc = "Goo extracted from a slime, which can do different things depending on its color and what it is injected with." + icon = 'icons/mob/slimes.dmi' + icon_state = "grey slime extract" + force = 1 + w_class = ITEMSIZE_TINY + throwforce = 0 + throw_speed = 3 + throw_range = 6 + origin_tech = list(TECH_BIO = 4) + var/uses = 1 // uses before it goes inert + var/enhanced = FALSE + flags = OPENCONTAINER + + +/obj/item/slime_extract/New() + ..() + create_reagents(60) + +/obj/item/slime_extract/attackby(obj/item/O, mob/user) + if(istype(O, /obj/item/slimepotion/enhancer)) + if(enhanced) + to_chat(user, "You cannot enhance this extract further!") + return ..() + to_chat(user, "You apply the enhancer to the slime extract. It may now be reused one more time.") + playsound(src, 'sound/effects/bubbles.ogg', 50, 1) + uses += 2 + enhanced = TRUE + name = initial(name) // To remove the 'inert' part of the name. + qdel(O) + ..() + +/obj/item/slime_extract/examine(mob/user) + ..() + if(uses) + to_chat(user, "This extract has [uses] more use\s.") + else + to_chat(user, "This extract is inert.") + +/datum/chemical_reaction/slime + var/required = null + +/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 FALSE + +/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] goes inert.") + T.name = "inert [initial(T.name)]" + + +// *************** +// * Grey slimes * +// *************** + + +/obj/item/slime_extract/grey + name = "grey slime extract" + icon_state = "grey slime extract" + description_info = "This extract will create a new grey baby slime if injected with phoron, or some new monkey cubes if injected with blood." + +/datum/chemical_reaction/slime/grey_new_slime + name = "Slime Spawn" + id = "m_spawn" + result = null + required_reagents = list("phoron" = 5) + result_amount = 1 + required = /obj/item/slime_extract/grey + +/datum/chemical_reaction/slime/grey_new_slime/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!") + new /mob/living/simple_animal/slime(get_turf(holder.my_atom)) + ..() + +/datum/chemical_reaction/slime/grey_monkey + name = "Slime Monkey" + id = "m_monkey" + result = null + required_reagents = list("blood" = 5) + result_amount = 1 + required = /obj/item/slime_extract/grey + +/datum/chemical_reaction/slime/grey_monkey/on_reaction(var/datum/reagents/holder) + for(var/i = 1 to 4) + new /obj/item/weapon/reagent_containers/food/snacks/monkeycube(get_turf(holder.my_atom)) + ..() + + +// **************** +// * Metal slimes * +// **************** + + +/obj/item/slime_extract/metal + name = "metal slime extract" + icon_state = "metal slime extract" + description_info = "This extract will create a metamorphic liquid which will transform into metallic liquid it comes into contact with, when injected with phoron. \ + It can also create a metallic binding liquid which will force metallic liquids to mix to form alloys when solified, when injected with water." + +// 'Duplicates' liquid metals, consuming itself in the process. +/datum/reagent/toxin/metamorphic_metal + name = "Metamorphic Metal" + id = "metamorphic" + description = "A strange metallic liquid which can rearrange itself to take the form of other metals it touches." + taste_description = "metallic" + taste_mult = 1.1 + reagent_state = LIQUID + color = "#666666" + strength = 20 + +/datum/chemical_reaction/slime/metal_metamorphic + name = "Slime Metal" + id = "m_metal" + required_reagents = list("phoron" = 5) + result = "metamorphic" + result_amount = REAGENTS_PER_SHEET // Makes enough to make one sheet of any metal. + required = /obj/item/slime_extract/metal + + +/datum/chemical_reaction/metamorphic + result_amount = REAGENTS_PER_SHEET * 2 + + +/obj/item/weapon/reagent_containers/glass/bottle/metamorphic + name = "Metamorphic Metal Bottle" + desc = "A small bottle. Contains some really weird liquid metal." + icon = 'icons/obj/chemical.dmi' + icon_state = "bottle-4" + +/obj/item/weapon/reagent_containers/glass/bottle/metamorphic/New() + ..() + reagents.add_reagent("metamorphic", 60) + update_icon() + + +// This is kind of a waste since iron is in the chem dispenser but it would be inconsistent if this wasn't here. +/datum/chemical_reaction/metamorphic/iron + name = "Morph into Iron" + id = "morph_iron" + required_reagents = list("metamorphic" = REAGENTS_PER_SHEET, "iron" = REAGENTS_PER_SHEET) + result = "iron" + + +/datum/chemical_reaction/metamorphic/silver + name = "Morph into Silver" + id = "morph_silver" + required_reagents = list("metamorphic" = REAGENTS_PER_SHEET, "silver" = REAGENTS_PER_SHEET) + result = "silver" + + +/datum/chemical_reaction/metamorphic/gold + name = "Morph into Gold" + id = "morph_gold" + required_reagents = list("metamorphic" = REAGENTS_PER_SHEET, "gold" = REAGENTS_PER_SHEET) + result = "gold" + + +/datum/chemical_reaction/metamorphic/platinum + name = "Morph into Platinum" + id = "morph_platinum" + required_reagents = list("metamorphic" = REAGENTS_PER_SHEET, "platinum" = REAGENTS_PER_SHEET) + result = "platinum" + + +/datum/chemical_reaction/metamorphic/uranium + name = "Morph into Uranium" + id = "morph_uranium" + required_reagents = list("metamorphic" = REAGENTS_PER_SHEET, "uranium" = REAGENTS_PER_SHEET) + result = "uranium" + + +/datum/chemical_reaction/metamorphic/phoron + name = "Morph into Phoron" + id = "morph_phoron" + required_reagents = list("metamorphic" = REAGENTS_PER_SHEET, "phoron" = REAGENTS_PER_SHEET) + result = "phoron" + + +// Creates 'alloys' which can be finalized with frost oil. +/datum/chemical_reaction/slime/metal_binding + name = "Slime Binding" + id = "m_binding" + required_reagents = list("water" = 5) + result = "binding" + result_amount = REAGENTS_PER_SHEET // Makes enough to make one sheet of any metal. + required = /obj/item/slime_extract/metal + + +/datum/reagent/toxin/binding_metal + name = "Binding Metal" + id = "binding" + description = "A strange metallic liquid which can bind other metals together that would otherwise require intense heat to alloy." + taste_description = "metallic" + taste_mult = 1.1 + reagent_state = LIQUID + color = "#666666" + strength = 20 + +/obj/item/weapon/reagent_containers/glass/bottle/binding + name = "Binding Metal Bottle" + desc = "A small bottle. Contains some really weird liquid metal." + icon = 'icons/obj/chemical.dmi' + icon_state = "bottle-4" + +/obj/item/weapon/reagent_containers/glass/bottle/binding/New() + ..() + reagents.add_reagent("binding", 60) + update_icon() + + +/datum/chemical_reaction/binding + name = "Bind into Steel" + id = "bind_steel" + result = "steel" + required_reagents = list("binding" = REAGENTS_PER_SHEET, "iron" = REAGENTS_PER_SHEET, "carbon" = REAGENTS_PER_SHEET) + result_amount = REAGENTS_PER_SHEET + +/datum/reagent/steel + name = "Liquid Steel" + id = "steel" + description = "An 'alloy' of iron and carbon, forced to bind together by another strange metallic liquid." + taste_description = "metallic" + reagent_state = LIQUID + color = "#888888" + + +/datum/chemical_reaction/binding/plasteel // Two parts 'steel', one part platnium matches the smelter alloy recipe. + name = "Bind into Plasteel" + id = "bind_plasteel" + required_reagents = list("binding" = REAGENTS_PER_SHEET, "steel" = REAGENTS_PER_SHEET * 2, "platinum" = REAGENTS_PER_SHEET) + result = "plasteel" + +/datum/reagent/plasteel + name = "Liquid Plasteel" + id = "plasteel" + description = "An 'alloy' of iron, carbon, and platinum, forced to bind together by another strange metallic liquid." + taste_description = "metallic" + reagent_state = LIQUID + color = "#AAAAAA" + + +// *************** +// * Blue slimes * +// *************** + + +/obj/item/slime_extract/blue + name = "blue slime extract" + icon_state = "blue slime extract" + description_info = "This extract will create frost oil when injected with phoron, which can be used to solidify liquid metals. \ + The extract can also create a slime stability agent when injected with blood, which reduces the odds of newly created slimes mutating into \ + a different color when a slime reproduces." + +/datum/chemical_reaction/slime/blue_frostoil + name = "Slime Frost Oil" + id = "m_frostoil" + result = "frostoil" + required_reagents = list("phoron" = 5) + result_amount = 20 + required = /obj/item/slime_extract/blue + + +/datum/chemical_reaction/slime/blue_stability + name = "Slime Stability" + id = "m_stability" + required_reagents = list("blood" = 5) + result_amount = 1 + required = /obj/item/slime_extract/blue + +/datum/chemical_reaction/slime/blue_frostoil/on_reaction(var/datum/reagents/holder) + new /obj/item/slimepotion/stabilizer(get_turf(holder.my_atom)) + ..() + + +// ***************** +// * Purple slimes * +// ***************** + + +/obj/item/slime_extract/purple + name = "purple slime extract" + icon_state = "purple slime extract" + description_info = "This extract can create a slime steroid agent when injected with phoron, which increases the amount of slime extracts the processor \ + can extract from a slime specimen." + + +/datum/chemical_reaction/slime/purple_steroid + name = "Slime Steroid" + id = "m_steroid" + required_reagents = list("phoron" = 5) + result_amount = 1 + required = /obj/item/slime_extract/purple + +/datum/chemical_reaction/slime/purple_steroid/on_reaction(var/datum/reagents/holder) + new /obj/item/slimepotion/steroid(get_turf(holder.my_atom)) + ..() + + +// ***************** +// * Orange slimes * +// ***************** + + +/obj/item/slime_extract/orange + name = "orange slime extract" + icon_state = "orange slime extract" + description_info = "This extract creates a fire when injected with phoron, after a five second delay." + +/datum/chemical_reaction/slime/orange_fire + name = "Slime Fire" + id = "m_fire" + required_reagents = list("phoron" = 5) + result_amount = 1 + required = /obj/item/slime_extract/orange + +/datum/chemical_reaction/slime/orange_fire/on_reaction(var/datum/reagents/holder) + log_and_message_admins("Orange extract reaction (fire) has been activated in [get_area(holder.my_atom)]. Last fingerprints: [holder.my_atom.fingerprintslast]") + holder.my_atom.visible_message("\The [src] begins to vibrate violently!") + playsound(get_turf(holder.my_atom), 'sound/effects/phasein.ogg', 75, 1) + spawn(5 SECONDS) + if(holder && holder.my_atom) + var/turf/simulated/T = get_turf(holder.my_atom) + if(!istype(T)) + return + + for(var/turf/simulated/target_turf in view(2, T)) + target_turf.assume_gas("volatile_fuel", 33, 1500+T0C) + target_turf.assume_gas("oxygen", 66, 1500+T0C) + spawn(0) + target_turf.hotspot_expose(1500+T0C, 400) + + playsound(T, 'sound/effects/phasein.ogg', 75, 1) + ..() + + +// ***************** +// * Yellow slimes * +// ***************** + +/obj/item/slime_extract/yellow + name = "yellow slime extract" + icon_state = "yellow slime extract" + description_info = "This extract will create a special 10k capacity power cell that self recharges slowly over time, when injected with phoron. \ + When injected with blood, it will create a glob of slime which glows brightly. If injected with water, it will emit a strong EMP, after a five second delay." + +/datum/chemical_reaction/slime/yellow_emp + name = "Slime EMP" + id = "m_emp" + required_reagents = list("water" = 5) + result_amount = 1 + required = /obj/item/slime_extract/yellow + +/datum/chemical_reaction/slime/yellow_emp/on_reaction(var/datum/reagents/holder) + log_and_message_admins("Yellow extract reaction (emp) has been activated in [get_area(holder.my_atom)]. Last fingerprints: [holder.my_atom.fingerprintslast]") + holder.my_atom.visible_message("\The [src] begins to vibrate violently!") + playsound(get_turf(holder.my_atom), 'sound/effects/phasein.ogg', 75, 1) + spawn(5 SECONDS) + if(holder && holder.my_atom) + empulse(get_turf(holder.my_atom), 2, 4, 7, 10) // As strong as a normal EMP grenade. + playsound(get_turf(holder.my_atom), 'sound/effects/phasein.ogg', 75, 1) + ..() + + +/datum/chemical_reaction/slime/yellow_battery + name = "Slime Cell" + id = "m_cell" + required_reagents = list("phoron" = 5) + result_amount = 1 + required = /obj/item/slime_extract/yellow + +/datum/chemical_reaction/slime/yellow_battery/on_reaction(var/datum/reagents/holder) + new /obj/item/weapon/cell/slime(get_turf(holder.my_atom)) + ..() + + +/datum/chemical_reaction/slime/yellow_flashlight + name = "Slime Flashlight" + id = "m_flashlight" + required_reagents = list("blood" = 5) + result_amount = 1 + required = /obj/item/slime_extract/yellow + +/datum/chemical_reaction/slime/yellow_flashlight/on_reaction(var/datum/reagents/holder) + new /obj/item/device/flashlight/slime(get_turf(holder.my_atom)) + ..() + +// *************** +// * Gold slimes * +// *************** + +/obj/item/slime_extract/gold + name = "gold slime extract" + icon_state = "gold slime extract" + description_info = "This extract will create 5u liquid gold when injected with phoron." + + +/datum/chemical_reaction/slime/gold_gold + name = "Slime Gold" + id = "m_gold" + result = "gold" + required_reagents = list("phoron" = 5) + result_amount = 5 + required = /obj/item/slime_extract/gold + + +// ***************** +// * Silver slimes * +// ***************** + +/obj/item/slime_extract/silver + name = "silver slime extract" + icon_state = "silver slime extract" + description_info = "This extract will create 5u liquid silver when injected with phoron." + + +/datum/chemical_reaction/slime/silver_silver + name = "Slime Silver" + id = "m_silver" + result = "silver" + required_reagents = list("phoron" = 5) + result_amount = 5 + required = /obj/item/slime_extract/silver + + +// ********************** +// * Dark Purple slimes * +// ********************** + + +/obj/item/slime_extract/dark_purple + name = "dark purple slime extract" + icon_state = "dark purple slime extract" + description_info = "This extract will create 40u liquid phoron when injected with water." + + +/datum/chemical_reaction/slime/dark_purple_phoron + name = "Slime Phoron" + id = "m_phoron_harvest" + result = "phoron" + required_reagents = list("water" = 5) + result_amount = REAGENTS_PER_SHEET * 2 + required = /obj/item/slime_extract/dark_purple + + +// ******************** +// * Dark Blue slimes * +// ******************** + + +/obj/item/slime_extract/dark_blue + name = "dark blue slime extract" + icon_state = "dark blue slime extract" + description_info = "This extract will massively lower the temperature of the surrounding atmosphere when injected with phoron. \ + Slimes will suffer massive harm from the cold snap and most colors will die instantly. Other entities are also chilled, however \ + cold-resistant armor like winter coats can protect from this. Note that the user is not immune to the extract's effects." + + +/datum/chemical_reaction/slime/dark_blue_cold_snap + name = "Slime Cold Snap" + id = "m_cold_snap" + required_reagents = list("phoron" = 5) + result_amount = 1 + required = /obj/item/slime_extract/dark_blue + +// This iterates over a ZAS zone's contents, so that things seperated in other zones aren't subjected to the temperature drop. +/datum/chemical_reaction/slime/dark_blue_cold_snap/on_reaction(var/datum/reagents/holder) + var/turf/simulated/T = get_turf(holder.my_atom) + if(!T) // Nullspace lacks zones. + return + + if(!istype(T)) + return + + var/zone/Z = T.zone + if(!Z) // Paranoid. + return + + log_and_message_admins("Dark Blue extract reaction (cold snap) has been activated in [get_area(holder.my_atom)]. Last fingerprints: [holder.my_atom.fingerprintslast]") + + var/list/nearby_things = view(T) + + // Hurt mobs. + for(var/mob/living/L in nearby_things) + var/turf/simulated/their_turf = get_turf(L) + if(!istype(their_turf)) // Not simulated. + continue + + if(!(their_turf in Z.contents)) // Not in the same zone. + continue + + if(istype(L, /mob/living/simple_animal/slime)) + var/mob/living/simple_animal/slime/S = L + if(S.cold_damage_per_tick <= 0) // Immune to cold. + to_chat(S, "A chill is felt around you, however it cannot harm you.") + continue + if(S.client) // Don't instantly kill player slimes. + to_chat(S, "You feel your body crystalize as an intense chill overwhelms you!") + S.adjustToxLoss(S.cold_damage_per_tick * 2) + else + S.adjustToxLoss(S.cold_damage_per_tick * 5) // Metal slimes can survive this 'slime nuke'. + continue + + if(ishuman(L)) + var/mob/living/carbon/human/H = L + var/protection = H.get_cold_protection() + + if(protection < 1) + var/cold_factor = abs(protection - 1) + H.bodytemperature = between(50, (H.bodytemperature - ((H.bodytemperature - 50) * cold_factor) ), H.bodytemperature) + + if(protection < 0.7) + to_chat(L, "A chilling wave of cold overwhelms you!") + else + to_chat(L, "A chilling wave of cold passes by you, as your armor protects you from it.") + continue + + // Now make it very cold. + var/datum/gas_mixture/env = T.return_air() + if(env) + // This is most likely physically impossible but when has that stopped slimes before? + env.add_thermal_energy(-10 * 1000 * 1000) // For a moderately sized room this doesn't actually lower it that much. + + playsound(T, 'sound/effects/phasein.ogg', 75, 1) + + ..() + + +// ************** +// * Red slimes * +// ************** + +/obj/item/slime_extract/red + name = "red slime extract" + icon_state = "red slime extract" + description_info = "This extract will create a slime mutator agent when injected with phoron, which increases a slime's odds of mutating \ + into a different color when reproducing by 12%. Injecting with blood causes all slimes that can see the user to enrage, becoming very violent and \ + out of control." + + +/datum/chemical_reaction/slime/red_enrage + name = "Slime Enrage" + id = "m_enrage" + required_reagents = list("blood" = 5) + result_amount = 1 + required = /obj/item/slime_extract/red + +/datum/chemical_reaction/slime/red_enrage/on_reaction(var/datum/reagents/holder) + for(var/mob/living/simple_animal/slime/S in view(get_turf(holder.my_atom))) + if(S.stat || S.docile || S.rabid) + continue + + if(S.client) // Player slimes always have free will. + to_chat(S, "An intense wave of rage almost overcomes you, but you remain in control of yourself.") + continue + + S.enrage() + + log_and_message_admins("Red extract reaction (enrage) has been activated in [get_area(holder.my_atom)]. Last fingerprints: [holder.my_atom.fingerprintslast]") + + playsound(get_turf(holder.my_atom), 'sound/effects/phasein.ogg', 75, 1) + ..() + + + +/datum/chemical_reaction/slime/red_mutation + name = "Slime Mutation" + id = "m_mutation" + required_reagents = list("phoron" = 5) + result_amount = 1 + required = /obj/item/slime_extract/red + +/datum/chemical_reaction/slime/red_mutation/on_reaction(var/datum/reagents/holder) + new /obj/item/slimepotion/mutator(get_turf(holder.my_atom)) + ..() + +// *************** +// * Green slime * +// *************** + +/obj/item/slime_extract/green + name = "green slime extract" + icon_state = "green slime extract" + description_info = "This extract will create 5u of liquid uranium when injected with phoron." + +/datum/chemical_reaction/slime/green_uranium + name = "Slime Uranium" + id = "m_uranium" + result = "uranium" + required_reagents = list("phoron" = 5) + result_amount = 5 + required = /obj/item/slime_extract/green + + +// *************** +// * Pink slimes * +// *************** + +/obj/item/slime_extract/pink + name = "pink slime extract" + icon_state = "pink slime extract" + description_info = "This extract will create 20u of blood clotting agent if injected with blood. It can also create 20u of bone binding agent if injected \ + with phoron. When injected with water, it will create an organ-mending agent. The slime medications have a very low threshold for overdosage, however." + + +/datum/chemical_reaction/slime/pink_clotting + name = "Slime Clotting Med" + id = "m_clotting" + result = "slime_bleed_fixer" + required_reagents = list("blood" = 5) + result_amount = 30 + required = /obj/item/slime_extract/pink + + +/datum/chemical_reaction/slime/pink_bone_fix + name = "Slime Bone Med" + id = "m_bone_fixer" + result = "slime_bone_fixer" + required_reagents = list("phoron" = 5) + result_amount = 30 + required = /obj/item/slime_extract/pink + + +/datum/chemical_reaction/slime/pink_organ_fix + name = "Slime Organ Med" + id = "m_organ_fixer" + result = "slime_organ_fixer" + required_reagents = list("water" = 5) + result_amount = 30 + required = /obj/item/slime_extract/pink + + +/datum/reagent/myelamine/slime + name = "Agent A" + id = "slime_bleed_fixer" + description = "A slimy liquid which appears to rapidly clot internal hemorrhages by increasing the effectiveness of platelets at low quantities. Toxic in high quantities." + taste_description = "slime" + overdose = 5 + +/datum/reagent/osteodaxon/slime + name = "Agent B" + id = "slime_bone_fixer" + description = "A slimy liquid which can be used to heal bone fractures at low quantities. Toxic in high quantities." + taste_description = "slime" + overdose = 5 + +/datum/reagent/peridaxon/slime + name = "Agent C" + id = "slime_organ_fixer" + description = "A slimy liquid which is used to encourage recovery of internal organs and nervous systems in low quantities. Toxic in high quantities." + taste_description = "slime" + overdose = 5 + + +// ************** +// * Oil slimes * +// ************** + +/obj/item/slime_extract/oil + name = "oil slime extract" + icon_state = "oil slime extract" + description_info = "This extract cause a moderately sized delayed explosion if injected with phoron. The delay is five seconds. Extract enhancers will \ + increase the power of the explosion instead of allowing for multiple explosions." + + +/datum/chemical_reaction/slime/oil_griff + name = "Slime Explosion" + id = "m_boom" + required_reagents = list("blood" = 5) + result_amount = 1 + required = /obj/item/slime_extract/oil + + +/datum/chemical_reaction/slime/oil_griff/on_reaction(var/datum/reagents/holder) + ..() + var/obj/item/slime_extract/E = holder.my_atom + var/power = 1 + if(E.enhanced) + power++ + E.uses = 0 + + playsound(get_turf(holder.my_atom), 'sound/effects/phasein.ogg', 75, 1) + holder.my_atom.visible_message("\The [holder.my_atom] begins to vibrate violently!") + log_and_message_admins("Oil extract reaction (explosion) has been activated in [get_area(holder.my_atom)]. Last fingerprints: [holder.my_atom.fingerprintslast]") + + spawn(5 SECONDS) + if(holder && holder.my_atom) + explosion(get_turf(holder.my_atom), 1 * power, 3 * power, 6 * power) + + if(holder && holder.my_atom) // Explosion may or may not have deleted the extract. + qdel(holder.my_atom) + +// ******************** +// * Bluespace slimes * +// ******************** + +/obj/item/slime_extract/bluespace + name = "bluespace slime extract" + icon_state = "bluespace slime extract" + description_info = "This extract creates slime crystals. When injected with water, it creates five 'lesser' slime crystals, which allow for limited \ + short ranged, random teleporting. When injected with phoron, it creates one 'greater' slime crystal, which allows for a one time precise teleport to \ + a specific area." + +/datum/chemical_reaction/slime/bluespace_lesser + name = "Slime Lesser Tele" + id = "m_tele_lesser" + required_reagents = list("water" = 5) + result_amount = 1 + required = /obj/item/slime_extract/bluespace + +/datum/chemical_reaction/slime/bluespace_lesser/on_reaction(var/datum/reagents/holder) + for(var/i = 1 to 5) + new /obj/item/slime_crystal(get_turf(holder.my_atom)) + ..() + +/datum/chemical_reaction/slime/bluespace_greater + name = "Slime Greater Tele" + id = "m_tele_lesser" + required_reagents = list("phoron" = 5) + result_amount = 1 + required = /obj/item/slime_extract/bluespace + +/datum/chemical_reaction/slime/bluespace_greater/on_reaction(var/datum/reagents/holder) + new /obj/item/weapon/disposable_teleporter/slime(get_turf(holder.my_atom)) + ..() + +// ******************* +// * Cerulean slimes * +// ******************* + +/obj/item/slime_extract/cerulean + name = "cerulean slime extract" + icon_state = "cerulean slime extract" + description_info = "This extract creates a slime extract enhancer agent, when injected with phoron. The agent allows an extract to have more \ + 'charges' before it goes inert." + + +/datum/chemical_reaction/slime/cerulean_enhancer + name = "Slime Enhancer" + id = "m_enhancer" + required_reagents = list("phoron" = 5) + result_amount = 1 + required = /obj/item/slime_extract/cerulean + +/datum/chemical_reaction/slime/cerulean_enhance/on_reaction(var/datum/reagents/holder) + new /obj/item/slimepotion/enhancer(get_turf(holder.my_atom)) + ..() + +// **************** +// * Amber slimes * +// **************** + +/obj/item/slime_extract/amber + name = "amber slime extract" + icon_state = "amber slime extract" + description_info = "This extract creates a slime feeding agent when injected with phoron, which will instantly feed the slime and make it reproduce. When \ + injected with water, it will create a very delicious and filling product." + + +/datum/chemical_reaction/slime/amber_slimefood + name = "Slime Feeding" + id = "m_slime_food" + required_reagents = list("phoron" = 5) + result_amount = 1 + required = /obj/item/slime_extract/amber + +/datum/chemical_reaction/slime/amber_slimefood/on_reaction(var/datum/reagents/holder) + new /obj/item/slimepotion/feeding(get_turf(holder.my_atom)) + ..() + + +/datum/chemical_reaction/slime/amber_peoplefood + name = "Slime Food" + id = "m_people_food" + required_reagents = list("water" = 5) + result_amount = 1 + required = /obj/item/slime_extract/amber + +/datum/chemical_reaction/slime/amber_peoplefood/on_reaction(var/datum/reagents/holder) + new /obj/item/weapon/reagent_containers/food/snacks/slime(get_turf(holder.my_atom)) + ..() + + +// ******************* +// * Sapphire slimes * +// ******************* +// Renamed from adamantine. + +/obj/item/slime_extract/sapphire + name = "sapphire slime extract" + icon_state = "sapphire slime extract" + description_info = "This extract will create one 'slime cube' when injected with phoron. The slime cube is needed to create a Promethean." + + +/datum/chemical_reaction/slime/sapphire_promethean + name = "Slime Promethean" + id = "m_promethean" + required_reagents = list("phoron" = 5) + result_amount = 1 + required = /obj/item/slime_extract/sapphire + +/datum/chemical_reaction/slime/sapphire_promethean/on_reaction(var/datum/reagents/holder) + new /obj/item/slime_cube(get_turf(holder.my_atom)) + ..() + +// *************** +// * Ruby slimes * +// *************** + +/obj/item/slime_extract/ruby + name = "ruby slime extract" + icon_state = "ruby slime extract" + description_info = "This extract will cause all entities close to the extract to become stronger for ten minutes, when injected with phoron. \ + When injected with blood, makes a slime loyalty agent which will make the slime fight other dangerous entities but not station crew." + +/datum/chemical_reaction/slime/ruby_swole + name = "Slime Strength" + id = "m_strength" + required_reagents = list("phoron" = 5) + result_amount = 1 + required = /obj/item/slime_extract/ruby + +/datum/chemical_reaction/slime/ruby_swole/on_reaction(var/datum/reagents/holder) + for(var/mob/living/L in range(1, holder.my_atom)) + L.add_modifier(/datum/modifier/slime_strength, 10 MINUTES, src) + ..() + + +/datum/modifier/slime_strength + name = "slime strength" + desc = "You feel much stronger than usual." + mob_overlay_state = "pink_sparkles" + + on_created_text = "Twinkling spores of goo surround you. It makes you feel stronger and more robust." + on_expired_text = "The spores of goo have faded, and you feel your strength returning to what it was before." + stacks = MODIFIER_STACK_EXTEND + + max_health_flat = 50 + outgoing_melee_damage_percent = 2 + disable_duration_percent = 0.5 + incoming_damage_percent = 0.75 + + +/datum/chemical_reaction/slime/ruby_loyalty + name = "Slime Loyalty" + id = "m_strength" + required_reagents = list("blood" = 5) + result_amount = 1 + required = /obj/item/slime_extract/ruby + +/datum/chemical_reaction/slime/ruby_loyalty/on_reaction(var/datum/reagents/holder) + new /obj/item/slimepotion/loyalty(get_turf(holder.my_atom)) + ..() + + +// ***************** +// * Emerald slime * +// ***************** + +/obj/item/slime_extract/emerald + name = "emerald slime extract" + icon_state = "emerald slime extract" + description_info = "This extract will cause all entities close to the extract to become more agile for ten minutes, when injected with phoron." + +/datum/chemical_reaction/slime/emerald_fast + name = "Slime Agility" + id = "m_agility" + required_reagents = list("phoron" = 5) + result_amount = 1 + required = /obj/item/slime_extract/emerald + +/datum/chemical_reaction/slime/emerald_fast/on_reaction(var/datum/reagents/holder) + for(var/mob/living/L in range(1, holder.my_atom)) + L.add_modifier(/datum/modifier/slime_agility, 10 MINUTES, src) + ..() + +/datum/modifier/slime_agility + name = "slime agility" + desc = "You feel much faster than usual." + mob_overlay_state = "green_sparkles" + + on_created_text = "Twinkling spores of goo surround you. It makes you feel fast and more agile." + on_expired_text = "The spores of goo have faded, and you feel your agility returning to what it was before." + stacks = MODIFIER_STACK_EXTEND + + evasion = 2 + slowdown = -1 + + +// ********************* +// * Light Pink slimes * +// ********************* + +/obj/item/slime_extract/light_pink + name = "light pink slime extract" + icon_state = "light pink slime extract" + description_info = "This extract creates a slime docility agent when injected with water, which will make the slime be harmless forever. \ + When injected with phoron, it instead creates a slime friendship agent, which makes the slime consider the user their ally. The agent \ + might be useful on other specimens as well." + +/datum/chemical_reaction/slime/light_pink_docility + name = "Slime Docility" + id = "m_docile" + required_reagents = list("water" = 5) + result_amount = 1 + required = /obj/item/slime_extract/light_pink + +/datum/chemical_reaction/slime/light_pink_docility/on_reaction(var/datum/reagents/holder) + new /obj/item/slimepotion/docility(get_turf(holder.my_atom)) + ..() + + +/datum/chemical_reaction/slime/light_pink_friendship + name = "Slime Friendship" + id = "m_friendship" + required_reagents = list("phoron" = 5) + result_amount = 1 + required = /obj/item/slime_extract/light_pink + +/datum/chemical_reaction/slime/light_pink_friendship/on_reaction(var/datum/reagents/holder) + new /obj/item/slimepotion/friendship(get_turf(holder.my_atom)) + ..() + + +// ****************** +// * Rainbow slimes * +// ****************** + + +/obj/item/slime_extract/rainbow + name = "rainbow slime extract" + icon_state = "rainbow slime extract" + description_info = "This extract will create a baby slime of a random color when injected with phoron, or a slime unification agent if injected with water, \ + which makes slimes stop attacking other slime colors." + + +/datum/chemical_reaction/slime/rainbow_random_slime + name = "Slime Random Slime" + id = "m_rng_slime" + required_reagents = list("phoron" = 5) + result_amount = 1 + required = /obj/item/slime_extract/rainbow + +/datum/chemical_reaction/slime/rainbow_random_slime/on_reaction(var/datum/reagents/holder) + var/list/forbidden_types = list( + /mob/living/simple_animal/slime/rainbow/kendrick + ) + var/list/potential_types = typesof(/mob/living/simple_animal/slime) - forbidden_types + var/slime_type = pick(potential_types) + new slime_type(get_turf(holder.my_atom)) + ..() + + +/datum/chemical_reaction/slime/rainbow_unity + name = "Slime Unity" + id = "m_unity" + required_reagents = list("water" = 5) + result_amount = 1 + required = /obj/item/slime_extract/rainbow + +/datum/chemical_reaction/slime/rainbow_unity/on_reaction(var/datum/reagents/holder) + new /obj/item/slimepotion/unity(get_turf(holder.my_atom)) + ..() + + + diff --git a/code/modules/xenobio/items/slime_objects.dm b/code/modules/xenobio/items/slime_objects.dm new file mode 100644 index 0000000000..03b048a49b --- /dev/null +++ b/code/modules/xenobio/items/slime_objects.dm @@ -0,0 +1,128 @@ +// Slime cube lives here. Makes Prometheans. +/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" + description_info = "Use in your hand to attempt to create a Promethean. It functions similarly to a positronic brain, in that a ghost is needed to become the Promethean." + 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(60 SECONDS) + reset_search() + +// Sometime down the road it would be great to make all of these 'ask ghosts if they want to be X' procs into a generic datum. +/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 + to_chat(S, "You are a promethean, brought into existence on [station_name()].") + S.mind.assigned_role = "Promethean" + S.set_species("Promethean") + S.shapeshifter_set_colour("#2398FF") + visible_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) + + + +// More or less functionally identical to the telecrystal tele. +/obj/item/slime_crystal + name = "lesser slime cystal" + desc = "A small, gooy crystal." + description_info = "This will teleport you to a mostly 'safe' tile when used in-hand, consuming the slime crystal. \ + It can also teleport someone else, by throwing it at them or attacking them with it." + icon = 'icons/obj/objects.dmi' + icon_state = "slime_crystal_small" + w_class = ITEMSIZE_TINY + origin_tech = list(TECH_MAGNETS = 6, TECH_BLUESPACE = 3) + force = 1 //Needs a token force to ensure you can attack because for some reason you can't attack with 0 force things + +/obj/item/slime_crystal/apply_hit_effect(mob/living/target, mob/living/user, var/hit_zone) + target.visible_message("\The [target] has been teleported with \the [src] by \the [user]!") + safe_blink(target, 14) + qdel(src) + +/obj/item/slime_crystal/attack_self(mob/user) + user.visible_message("\The [user] teleports themselves with \the [src]!") + safe_blink(user, 14) + qdel(src) + +/obj/item/slime_crystal/throw_impact(atom/movable/AM) + if(!istype(AM)) + return + + if(AM.anchored) + return + + AM.visible_message("\The [AM] has been teleported with \the [src]!") + safe_blink(AM, 14) + qdel(src) + +/obj/item/weapon/disposable_teleporter/slime + name = "greater slime crystal" + desc = "A larger, gooier crystal." + description_info = "This will teleport you to a specific area once, when used in-hand." + icon = 'icons/obj/objects.dmi' + icon_state = "slime_crystal_large" + uses = 1 + w_class = ITEMSIZE_SMALL + origin_tech = list(TECH_MAGNETS = 5, TECH_BLUESPACE = 4) + + + +// Very filling food. +/obj/item/weapon/reagent_containers/food/snacks/slime + name = "slimy clump" + desc = "A glob of slime that is thick as honey. For the brave Xenobiologist." + icon_state = "honeycomb" + filling_color = "#FFBB00" + center_of_mass = list("x"=17, "y"=10) + nutriment_amt = 25 // Very filling. + nutriment_desc = list("slime" = 10, "sweetness" = 10, "bliss" = 5) + +/obj/item/weapon/reagent_containers/food/snacks/slime/New() + ..() + bitesize = 5 \ No newline at end of file diff --git a/code/modules/xenobio/items/slimepotions.dm b/code/modules/xenobio/items/slimepotions.dm new file mode 100644 index 0000000000..df03fdab6f --- /dev/null +++ b/code/modules/xenobio/items/slimepotions.dm @@ -0,0 +1,255 @@ +// These things get applied to slimes to do things. + +/obj/item/slimepotion + name = "slime agent" + desc = "A flask containing strange, mysterious substances excreted by a slime." + icon = 'icons/obj/chemical.dmi' + w_class = ITEMSIZE_TINY + origin_tech = list(TECH_BIO = 4) + +// This is actually applied to an extract, so no attack() overriding needed. +/obj/item/slimepotion/enhancer + name = "extract enhancer agent" + desc = "A potent chemical mix that will give a slime extract an additional two uses." + icon_state = "potpurple" + description_info = "This will even work on inert slime extracts, if it wasn't enhanced before. Extracts enhanced cannot be enhanced again." + +// Makes slimes less likely to mutate. +/obj/item/slimepotion/stabilizer + name = "slime stabilizer agent" + desc = "A potent chemical mix that will reduce the chance of a slime mutating." + icon_state = "potcyan" + description_info = "The slime needs to be alive for this to work. It will reduce the chances of mutation by 15%." + +/obj/item/slimepotion/stabilizer/attack(mob/living/simple_animal/slime/M, mob/user) + if(!istype(M)) + to_chat(user, "The stabilizer only works on slimes!") + return ..() + if(M.stat == DEAD) + to_chat(user, "The slime is dead!") + return ..() + if(M.mutation_chance == 0) + to_chat(user, "The slime already has no chance of mutating!") + return ..() + + to_chat(user, "You feed the slime the stabilizer. It is now less likely to mutate.") + M.mutation_chance = between(0, M.mutation_chance - 15, 100) + playsound(src, 'sound/effects/bubbles.ogg', 50, 1) + qdel(src) + + +// The opposite, makes the slime more likely to mutate. +/obj/item/slimepotion/mutator + name = "slime mutator agent" + desc = "A potent chemical mix that will increase the chance of a slime mutating." + description_info = "The slime needs to be alive for this to work. It will increase the chances of mutation by 12%." + icon_state = "potred" + +/obj/item/slimepotion/mutator/attack(mob/living/simple_animal/slime/M, mob/user) + if(!istype(M)) + to_chat(user, "The mutator only works on slimes!") + return ..() + if(M.stat == DEAD) + to_chat(user, "The slime is dead!") + return ..() + if(M.mutation_chance == 100) + to_chat(user, "The slime is already guaranteed to mutate!") + return ..() + + to_chat(user, "You feed the slime the mutator. It is now more likely to mutate.") + M.mutation_chance = between(0, M.mutation_chance + 12, 100) + playsound(src, 'sound/effects/bubbles.ogg', 50, 1) + qdel(src) + + +// Makes the slime friendly forever. +/obj/item/slimepotion/docility + name = "docility agent" + desc = "A potent chemical mix that nullifies a slime's hunger, causing it to become docile and tame. It might also work on other creatures?" + icon_state = "potlightpink" + description_info = "The target needs to be alive, not already passive, and have animal-like intelligence." + +/obj/item/slimepotion/docility/attack(mob/living/simple_animal/M, mob/user) + if(!istype(M)) + to_chat(user, "The agent only works on creatures!") + return ..() + if(M.stat == DEAD) + to_chat(user, "\The [M] is dead!") + return ..() + + // Slimes. + if(istype(M, /mob/living/simple_animal/slime)) + var/mob/living/simple_animal/slime/S = M + if(S.docile) + to_chat(user, "The slime is already docile!") + return ..() + + S.pacify() + S.nutrition = 700 + to_chat(M, "You absorb the agent and feel your intense desire to feed melt away.") + to_chat(user, "You feed the slime the agent, removing its hunger and calming it.") + + // Simple Animals. + else if(istype(M, /mob/living/simple_animal)) + var/mob/living/simple_animal/SA = M + if(SA.intelligence_level > SA_ANIMAL) // So you can't use this on Russians/syndies/hivebots/etc. + to_chat(user, "\The [SA] is too intellient for this to affect them.") + return ..() + if(!SA.hostile) + to_chat(user, "\The [SA] is already passive!") + return ..() + + SA.hostile = FALSE + to_chat(M, "You consume the agent and feel a serene sense of peace.") + to_chat(user, "You feed \the [SA] the agent, calming it.") + + playsound(src, 'sound/effects/bubbles.ogg', 50, 1) + M.LoseTarget() // So hostile things stop attacking people even if not hostile anymore. + var/newname = copytext(sanitize(input(user, "Would you like to give \the [M] a name?", "Name your new pet", M.name) as null|text),1,MAX_NAME_LEN) + + if(newname) + M.name = newname + M.real_name = newname + qdel(src) + + +// Makes slimes make more extracts. +/obj/item/slimepotion/steroid + name = "slime steroid agent" + desc = "A potent chemical mix that will increase the amount of extracts obtained from harvesting a slime." + description_info = "The slime needs to be alive and not an adult for this to work. It will increase the amount of extracts gained by one, up to a max of five per slime. \ + Extra extracts are not passed down to offspring when reproducing." + icon_state = "potpurple" + +/obj/item/slimepotion/steroid/attack(mob/living/simple_animal/slime/M, mob/user) + if(!istype(M)) + to_chat(user, "The steroid only works on slimes!") + return ..() + if(M.stat == DEAD) + to_chat(user, "The slime is dead!") + return ..() + if(M.is_adult) //Can't steroidify adults + to_chat(user, "Only baby slimes can use the steroid!") + return ..() + if(M.cores >= 5) + to_chat(user, "The slime already has the maximum amount of extract!") + return ..() + + to_chat(user, "You feed the slime the steroid. It will now produce one more extract.") + M.cores++ + playsound(src, 'sound/effects/bubbles.ogg', 50, 1) + qdel(src) + + +// Makes slimes not try to murder other slime colors. +/obj/item/slimepotion/unity + name = "slime unity agent" + desc = "A potent chemical mix that makes the slime feel and be seen as all the colors at once, and as a result not be considered an enemy to any other color." + description_info = "The slime needs to be alive for this to work. Slimes unified will not attack or be attacked by other colored slimes, and this will \ + carry over to offspring when reproducing." + icon_state = "potpink" + +/obj/item/slimepotion/unity/attack(mob/living/simple_animal/slime/M, mob/user) + if(!istype(M)) + to_chat(user, "The agent only works on slimes!") + return ..() + if(M.stat == DEAD) + to_chat(user, "The slime is dead!") + return ..() + if(M.unity == TRUE) + to_chat(user, "The slime is already unified!") + return ..() + + to_chat(user, "You feed the slime the agent. It will now be friendly to all other slimes.") + to_chat(M, "\The [user] feeds you \the [src], and you suspect that all the other slimes will be \ + your friends, at least if you don't attack them first.") + M.unify() + playsound(src, 'sound/effects/bubbles.ogg', 50, 1) + qdel(src) + +// Makes slimes not kill (most) humanoids but still fight spiders/carp/bears/etc. +/obj/item/slimepotion/loyalty + name = "slime loyalty agent" + desc = "A potent chemical mix that makes an animal deeply loyal to the species of whoever applies this, and will attack threats to them." + description_info = "The slime or other animal needs to be alive for this to work. The slime this is applied to will have their 'faction' change to \ + the user's faction, which means the slime will attack things that are hostile to the user's faction, such as carp, spiders, and other slimes." + icon_state = "potred" + +/obj/item/slimepotion/loyalty/attack(mob/living/simple_animal/M, mob/user) + if(!istype(M)) + to_chat(user, "The agent only works on animals!") + return ..() + if(M.intelligence_level > SA_ANIMAL) // So you can't use this on Russians/syndies/hivebots/etc. + to_chat(user, "\The [M] is too intellient for this to affect them.") + return ..() + if(M.stat == DEAD) + to_chat(user, "The animal is dead!") + return ..() + if(M.faction == user.faction) + to_chat(user, "\The [M] is already loyal to your species!") + return ..() + + to_chat(user, "You feed \the [M] the agent. It will now try to murder things that want to murder you instead.") + to_chat(M, "\The [user] feeds you \the [src], and feel that the others will regard you as an outsider now.") + M.faction = user.faction + M.attack_same = FALSE + M.LoseTarget() // So hostile things stop attacking people even if not hostile anymore. + playsound(src, 'sound/effects/bubbles.ogg', 50, 1) + qdel(src) + + +// User befriends the slime with this. +/obj/item/slimepotion/friendship + name = "slime friendship agent" + desc = "A potent chemical mix that makes an animal deeply loyal to the the specific entity which feeds them this agent." + description_info = "The slime or other animal needs to be alive for this to work. The slime this is applied to will consider the user \ + their 'friend', and will never attack them. This might also work on other things besides slimes." + icon_state = "potlightpink" + +/obj/item/slimepotion/friendship/attack(mob/living/simple_animal/M, mob/user) + if(!istype(M)) + to_chat(user, "The agent only works on animals!") + return ..() + if(M.intelligence_level > SA_ANIMAL) // So you can't use this on Russians/syndies/hivebots/etc. + to_chat(user, "\The [M] is too intellient for this to affect them.") + return ..() + if(M.stat == DEAD) + to_chat(user, "The animal is dead!") + return ..() + if(user in M.friends) + to_chat(user, "\The [M] is already loyal to you!") + return ..() + + to_chat(user, "You feed \the [M] the agent. It will now be your best friend.") + to_chat(M, "\The [user] feeds you \the [src], and feel that \the [user] wants to be best friends with you.") + if(isslime(M)) + var/mob/living/simple_animal/slime/S = M + S.befriend(user) + else + M.friends.Add(user) + M.LoseTarget() // So hostile things stop attacking people even if not hostile anymore. + playsound(src, 'sound/effects/bubbles.ogg', 50, 1) + qdel(src) + + +// Feeds the slime instantly. +/obj/item/slimepotion/feeding + name = "slime feeding agent" + desc = "A potent chemical mix that will instantly sediate the slime." + description_info = "The slime needs to be alive for this to work. It will instantly grow the slime enough to reproduce." + icon_state = "potyellow" + +/obj/item/slimepotion/feeding/attack(mob/living/simple_animal/slime/M, mob/user) + if(!istype(M)) + to_chat(user, "The mutator only works on slimes!") + return ..() + if(M.stat == DEAD) + to_chat(user, "The slime is dead!") + return ..() + + to_chat(user, "You feed the slime the feeding agent. It will now instantly reproduce.") + M.make_adult() + M.amount_grown = 10 + M.reproduce() + playsound(src, 'sound/effects/bubbles.ogg', 50, 1) + qdel(src) diff --git a/code/modules/xenobio/items/weapons.dm b/code/modules/xenobio/items/weapons.dm new file mode 100644 index 0000000000..3fdc758f84 --- /dev/null +++ b/code/modules/xenobio/items/weapons.dm @@ -0,0 +1,105 @@ +/obj/item/weapon/melee/baton/slime + name = "slimebaton" + desc = "A modified stun baton designed to stun slimes and other lesser xeno lifeforms 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. + hitcost = 48 //Less zap for less cost + description_info = "This baton will stun a slime or other lesser lifeform for about five seconds, if hit with it while on." + +/obj/item/weapon/melee/baton/slime/attack(mob/M, mob/user, hit_zone) + // Simple Animals. + if(istype(M, /mob/living/simple_animal/slime) && status) + var/mob/living/simple_animal/SA = M + if(SA.intelligence_level <= SA_ANIMAL) // So it doesn't stun hivebots or syndies. + SA.Weaken(5) + if(isslime(SA)) + var/mob/living/simple_animal/slime/S = SA + S.adjust_discipline(3) + + // Prometheans. + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(H.species && H.species.name == "Promethean" && status) + var/agony_to_apply = 60 - agonyforce + H.apply_damage(agony_to_apply, HALLOSS) + ..() + +/obj/item/weapon/melee/baton/slime/loaded/New() + ..() + bcell = new/obj/item/weapon/cell/device(src) + update_icon() + return + + +// Research borg's version +/obj/item/weapon/melee/baton/slime/robot + hitcost = 200 + +/obj/item/weapon/melee/baton/slime/robot/attack_self(mob/user) + //try to find our power cell + var/mob/living/silicon/robot/R = loc + if (istype(R)) + bcell = R.cell + return ..() + +/obj/item/weapon/melee/baton/slime/robot/attackby(obj/item/weapon/W, mob/user) + 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." + desc = "An easy to use weapon designed by NanoTrasen, for NanoTrasen. This weapon is designed to subdue lesser \ + xeno lifeforms at a distance. It is ineffective at stunning larger lifeforms such as humanoids." + icon_state = "taserold" + fire_sound = 'sound/weapons/taser2.ogg' + charge_cost = 120 // Twice as many shots. + projectile_type = /obj/item/projectile/beam/stun/xeno + accuracy = 2 // Make it a bit easier to hit the slimes. + description_info = "This gun will stun a slime or other lesser lifeform for about two seconds, if hit with the projectile it fires." + +/obj/item/weapon/gun/energy/taser/xeno/robot // Borg version + self_recharge = 1 + use_external_power = 1 + recharge_time = 3 + + +/obj/item/projectile/beam/stun/xeno + icon_state = "omni" + agony = 4 + nodamage = TRUE + // For whatever reason the projectile qdels itself early if this is on, meaning on_hit() won't be called on prometheans. + // Probably for the best so that it doesn't harm the slime. + taser_effect = FALSE + + 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)) + var/mob/living/L = target + + // Simple Animals. + if(istype(L, /mob/living/simple_animal/slime)) + var/mob/living/simple_animal/SA = L + if(SA.intelligence_level <= SA_ANIMAL) // So it doesn't stun hivebots or syndies. + SA.Weaken(2) // Less powerful since its ranged, and therefore safer. + if(isslime(SA)) + var/mob/living/simple_animal/slime/S = SA + S.adjust_discipline(2) + + // Prometheans. + if(ishuman(L)) + var/mob/living/carbon/human/H = L + if(H.species && H.species.name == "Promethean") + var/agony_to_apply = 60 - agony + H.apply_damage(agony_to_apply, HALLOSS) + ..() \ No newline at end of file diff --git a/code/modules/xenobio/machinery/processor.dm b/code/modules/xenobio/machinery/processor.dm new file mode 100644 index 0000000000..56b7cee3bf --- /dev/null +++ b/code/modules/xenobio/machinery/processor.dm @@ -0,0 +1,118 @@ +// This is specifically for slimes since we don't have a 'normal' processor now. +// Feel free to rename it if that ever changes. + +/obj/machinery/processor + name = "slime processor" + desc = "An industrial grinder used to automate the process of slime core extraction. It can also recycle biomatter." + icon = 'icons/obj/kitchen.dmi' + icon_state = "processor1" + density = TRUE + anchored = TRUE + var/processing = FALSE // So I heard you like processing. + var/list/to_be_processed = list() + var/monkeys_recycled = 0 + description_info = "Clickdrag dead slimes or monkeys to it to insert them. It will make a new monkey cube for every four monkeys it processes." + +/obj/item/weapon/circuitboard/processor + name = T_BOARD("slime processor") + build_path = /obj/machinery/processor + origin_tech = list(TECH_DATA = 2, TECH_BIO = 2) + +/obj/machinery/processor/attack_hand(mob/living/user) + if(processing) + to_chat(user, "The processor is in the process of processing!") + return + if(to_be_processed.len) + spawn(1) + begin_processing() + else + to_chat(user, "The processor is empty.") + playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 1) + return + +// Verb to remove everything. +/obj/machinery/processor/verb/eject() + set category = "Object" + set name = "Eject Processor" + set src in oview(1) + + if(usr.stat || !usr.canmove || usr.restrained()) + return + empty() + add_fingerprint(usr) + return + +// Ejects all the things out of the machine. +/obj/machinery/processor/proc/empty() + for(var/atom/movable/AM in to_be_processed) + to_be_processed.Remove(AM) + AM.forceMove(get_turf(src)) + +// Ejects all the things out of the machine. +/obj/machinery/processor/proc/insert(var/atom/movable/AM, var/mob/living/user) + if(!Adjacent(AM)) + return + if(!can_insert(AM)) + to_chat(user, "\The [src] cannot process \the [AM] at this time.") + playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 1) + return + to_be_processed.Add(AM) + AM.forceMove(src) + visible_message("\the [user] places [AM] inside \the [src].") + +/obj/machinery/processor/proc/begin_processing() + if(processing) + return // Already doing it. + processing = TRUE + playsound(src.loc, 'sound/machines/juicer.ogg', 50, 1) + for(var/atom/movable/AM in to_be_processed) + extract(AM) + sleep(1 SECONDS) + + while(monkeys_recycled >= 4) + new /obj/item/weapon/reagent_containers/food/snacks/monkeycube(get_turf(src)) + playsound(src.loc, 'sound/effects/splat.ogg', 50, 1) + monkeys_recycled -= 4 + sleep(1 SECOND) + + processing = FALSE + playsound(src.loc, 'sound/machines/ding.ogg', 50, 1) + +/obj/machinery/processor/proc/extract(var/atom/movable/AM) + if(istype(AM, /mob/living/simple_animal/slime)) + var/mob/living/simple_animal/slime/S = AM + while(S.cores) + new S.coretype(get_turf(src)) + playsound(src.loc, 'sound/effects/splat.ogg', 50, 1) + S.cores-- + sleep(1 SECOND) + to_be_processed.Remove(S) + qdel(S) + + if(istype(AM, /mob/living/carbon/human)) + var/mob/living/carbon/human/M = AM + playsound(src.loc, 'sound/effects/splat.ogg', 50, 1) + to_be_processed.Remove(M) + qdel(M) + monkeys_recycled++ + sleep(1 SECOND) + +/obj/machinery/processor/proc/can_insert(var/atom/movable/AM) + if(istype(AM, /mob/living/simple_animal/slime)) + var/mob/living/simple_animal/slime/S = AM + if(S.stat != DEAD) + return FALSE + return TRUE + if(istype(AM, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = AM + if(!istype(H.species, /datum/species/monkey)) + return FALSE + if(H.stat != DEAD) + return FALSE + return TRUE + return FALSE + +/obj/machinery/processor/MouseDrop_T(var/atom/movable/AM, var/mob/living/user) + if(user.stat || user.incapacitated(INCAPACITATION_DISABLED) || !istype(user)) + return + insert(AM, user) \ 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 index 050a97bc41..e69de29bb2 100644 --- a/code/modules/xenobio2/tools/slime_handling_tools.dm +++ b/code/modules/xenobio2/tools/slime_handling_tools.dm @@ -1,70 +0,0 @@ -/* 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. - hitcost = 48 //Less zap for less cost - -/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/device(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' - 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)) - world << "is xeno" - var/mob/living/simple_animal/xeno/X = target - world << "[target.name]" - if(istype(X, /mob/living/simple_animal/xeno/slime)) - world << "is slime" - X.stasis += stasisforce - else - world << "is not slime" - X.stasis += (stasisforce / 8) - else - world << "is not xeno" - ..() -*/ \ No newline at end of file diff --git a/code/world.dm b/code/world.dm index 9a031dda0f..9ef6abf8aa 100644 --- a/code/world.dm +++ b/code/world.dm @@ -76,9 +76,6 @@ 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/icons/mob/modifier_effects.dmi b/icons/mob/modifier_effects.dmi index e0fe0b1697..eca5286d9b 100644 Binary files a/icons/mob/modifier_effects.dmi and b/icons/mob/modifier_effects.dmi differ diff --git a/icons/mob/screen1_stats.dmi b/icons/mob/screen1_stats.dmi index 381f6a3660..701d7f1702 100644 Binary files a/icons/mob/screen1_stats.dmi and b/icons/mob/screen1_stats.dmi differ diff --git a/icons/mob/slime2.dmi b/icons/mob/slime2.dmi index 33ef237cba..a0b6051665 100644 Binary files a/icons/mob/slime2.dmi and b/icons/mob/slime2.dmi differ diff --git a/icons/mob/slimes.dmi b/icons/mob/slimes.dmi index f2da09ad8f..b452a1526d 100644 Binary files a/icons/mob/slimes.dmi and b/icons/mob/slimes.dmi differ diff --git a/icons/mob/talk.dmi b/icons/mob/talk.dmi index 14d1d54ab9..acd94a74c3 100644 Binary files a/icons/mob/talk.dmi and b/icons/mob/talk.dmi differ diff --git a/icons/obj/aibots.dmi b/icons/obj/aibots.dmi index f58a356c34..abcf7c1cf9 100644 Binary files a/icons/obj/aibots.dmi and b/icons/obj/aibots.dmi differ diff --git a/icons/obj/chemical.dmi b/icons/obj/chemical.dmi index 2fa64c7ade..a8ae36b5e8 100644 Binary files a/icons/obj/chemical.dmi and b/icons/obj/chemical.dmi differ diff --git a/icons/obj/objects.dmi b/icons/obj/objects.dmi index 83e20f0af3..32827b2b81 100644 Binary files a/icons/obj/objects.dmi and b/icons/obj/objects.dmi differ diff --git a/icons/obj/structures.dmi b/icons/obj/structures.dmi index 214428603e..8cc8557888 100644 Binary files a/icons/obj/structures.dmi and b/icons/obj/structures.dmi differ diff --git a/maps/example/example.dm b/maps/example/example.dm index a103a32625..46ee489d5a 100644 --- a/maps/example/example.dm +++ b/maps/example/example.dm @@ -1,11 +1,13 @@ #if !defined(USING_MAP_DATUM) - #include "example-1.dmm" - #include "example-2.dmm" +// #include "example-1.dmm" +// #include "example-2.dmm" + #include "xenobio_test.dmm" #include "example_defines.dm" - #include "example_elevator.dm" - #include "example_areas.dm" +// #include "example_elevator.dm" +// #include "example_areas.dm" + #define USING_MAP_DATUM /datum/map/example diff --git a/maps/northern_star/polaris-1.dmm b/maps/northern_star/polaris-1.dmm index 9bc000a95d..ae027eeab8 100644 --- a/maps/northern_star/polaris-1.dmm +++ b/maps/northern_star/polaris-1.dmm @@ -4887,7 +4887,7 @@ "bPY" = (/obj/machinery/computer/aifixer,/obj/effect/floor_decal/corner/purple/full,/obj/machinery/status_display{layer = 4; pixel_x = 0; pixel_y = -32},/turf/simulated/floor/tiled/white,/area/rnd/rdoffice) "bPZ" = (/obj/machinery/computer/robotics,/obj/effect/floor_decal/corner/purple{dir = 10},/turf/simulated/floor/tiled/white,/area/rnd/rdoffice) "bQa" = (/obj/machinery/computer/mecha,/obj/effect/floor_decal/corner/purple{dir = 10},/obj/machinery/ai_status_display{pixel_y = -32},/obj/machinery/camera/network/research{c_tag = "SCI - RD's Office"; dir = 1},/turf/simulated/floor/tiled/white,/area/rnd/rdoffice) -"bQb" = (/obj/effect/floor_decal/corner/purple/full{dir = 4},/obj/machinery/alarm{dir = 1; pixel_y = -22},/mob/living/simple_animal/slime/science,/turf/simulated/floor/tiled/white,/area/rnd/rdoffice) +"bQb" = (/obj/effect/floor_decal/corner/purple/full{dir = 4},/obj/machinery/alarm{dir = 1; pixel_y = -22},/mob/living/simple_animal/slime/rainbow/kendrick,/turf/simulated/floor/tiled/white,/area/rnd/rdoffice) "bQc" = (/obj/structure/table/rack,/obj/item/weapon/rig/hazmat/equipped,/obj/structure/extinguisher_cabinet{pixel_x = 25; pixel_y = 0},/obj/machinery/firealarm{dir = 1; pixel_y = -24},/turf/simulated/floor/tiled/dark,/area/rnd/rdoffice) "bQd" = (/obj/structure/table/standard,/obj/item/device/mmi,/obj/item/device/mmi,/obj/item/device/mmi,/obj/structure/extinguisher_cabinet{pixel_x = -27},/turf/simulated/floor/tiled,/area/assembly/robotics) "bQe" = (/obj/structure/table/standard,/obj/machinery/cell_charger,/obj/item/device/radio/intercom{dir = 4; name = "Station Intercom (General)"; pixel_x = 21},/obj/effect/floor_decal/corner/pink{dir = 4},/turf/simulated/floor/tiled,/area/assembly/robotics) @@ -9879,7 +9879,7 @@ "dHZ" = (/turf/space,/area/skipjack_station/southeast_solars) "dIa" = (/turf/space,/area/syndicate_station/south) "dIb" = (/obj/machinery/power/tracker,/obj/structure/cable/yellow,/turf/simulated/floor/airless,/area/solar/starboard) - + (1,1,1) = {" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa diff --git a/maps/northern_star/polaris-5.dmm b/maps/northern_star/polaris-5.dmm index bb133806a4..28d2dc5f94 100644 --- a/maps/northern_star/polaris-5.dmm +++ b/maps/northern_star/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,/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" = (/obj/machinery/xenobio2/manualinjector,/turf/simulated/floor/reinforced,/area/outpost/research/xenobiology) +"fp" = (/obj,/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) @@ -299,17 +299,17 @@ "fM" = (/obj/effect/floor_decal/industrial/hatch/yellow,/obj/machinery/door/blast/regular{density = 0; icon_state = "pdoor0"; id = "xenobio2"; 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) "fN" = (/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 = "xenobio2"; name = "Containment Blast Doors"; opacity = 0},/obj/structure/disposalpipe/segment,/obj/structure/cable/blue{d2 = 2; icon_state = "0-2"},/turf/simulated/floor/plating,/area/outpost/research/xenobiology) "fO" = (/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) -"fP" = (/obj/machinery/xenobio/editor,/turf/simulated/floor/reinforced,/area/outpost/research/xenobiology) +"fP" = (/obj,/turf/simulated/floor/reinforced,/area/outpost/research/xenobiology) "fQ" = (/obj/structure/sign/securearea,/turf/simulated/wall/r_wall,/area/outpost/research/hallway/toxins_hallway) "fR" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/door/airlock/research{autoclose = 0; frequency = 1379; icon_state = "door_locked"; id_tag = "toxins_airlock_exterior"; locked = 1; name = "Toxins External Airlock"; req_access = list(7)},/obj/structure/cable/blue{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/access_button{command = "cycle_exterior"; frequency = 1379; master_tag = "toxins_airlock_control"; name = "Toxins Access Button"; pixel_x = 26; pixel_y = 0; req_access = list(7)},/turf/simulated/floor/tiled/white,/area/outpost/research/hallway/toxins_hallway) "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},/obj/machinery/computer/xenobio2,/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,/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/effect/floor_decal/industrial/warning,/obj/machinery/computer/xenobio2,/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) +"fZ" = (/obj/effect/floor_decal/industrial/warning,/obj,/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) @@ -321,8 +321,8 @@ "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,/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) +"gl" = (/obj,/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) +"gm" = (/obj,/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) @@ -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/machinery/slime/replicator,/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) +"hi" = (/obj,/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) @@ -445,7 +445,7 @@ "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/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,/obj/item/device/analyzer/xeno_analyzer,/turf/simulated/floor/tiled/dark,/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,/obj,/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) @@ -458,10 +458,10 @@ "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/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) +"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,/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/table/steel,/obj/item/clothing/glasses/science,/obj/item/device/analyzer/xeno_analyzer,/turf/simulated/floor/tiled/dark,/area/outpost/research/xenobiology) +"iV" = (/obj/structure/table/steel,/obj/item/clothing/glasses/science,/obj,/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,9 +469,9 @@ "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/standard,/obj/item/weapon/storage/box/xenobiodisk,/obj/item/weapon/melee/baton/slime/loaded,/obj/item/device/analyzer/xeno_analyzer,/turf/simulated/floor/tiled/white,/area/outpost/research/xenobiology) +"jd" = (/obj/structure/table/standard,/obj,/obj/item/weapon/melee/baton/slime/loaded,/obj,/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,/obj/item/device/analyzer/xeno_analyzer,/turf/simulated/floor/tiled/dark,/area/outpost/research/xenobiology) +"jf" = (/obj/structure/closet,/obj/item/toy/figure/scientist,/obj/item/clothing/accessory/armband/science,/obj,/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) "jh" = (/obj/machinery/light/small{dir = 8},/obj/structure/disposalpipe/segment,/turf/simulated/floor/reinforced,/area/outpost/research/xenobiology) "ji" = (/obj/structure/disposaloutlet{dir = 4},/obj/structure/disposalpipe/trunk{dir = 1},/turf/simulated/floor/reinforced,/area/outpost/research/xenobiology) @@ -1587,7 +1587,7 @@ "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) +"ED" = (/obj,/turf/simulated/floor/tiled/dark,/area/outpost/research/xenobiology) "EE" = (/obj/structure/bed/chair/office/light{dir = 1},/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) "EF" = (/obj/machinery/recharger/wallcharger{pixel_x = 32},/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) "EG" = (/obj/machinery/light{dir = 1},/obj/machinery/vending/hydronutrients,/turf/simulated/floor/tiled,/area/outpost/research/xenobiology) @@ -1910,7 +1910,7 @@ "KL" = (/obj/structure/lattice,/obj/structure/grille,/turf/space,/area/space) "KM" = (/obj/machinery/power/tracker,/obj/structure/cable/yellow,/turf/simulated/floor/airless{icon_state = "asteroidplating2"},/area/outpost/engineering/solarsoutside/aft) "KN" = (/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -20},/turf/simulated/floor/tiled,/area/outpost/mining_main/south_hall) - + (1,1,1) = {" aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa diff --git a/polaris.dme b/polaris.dme index 94ce131288..959eb6c298 100644 --- a/polaris.dme +++ b/polaris.dme @@ -1662,18 +1662,6 @@ #include "code\modules\mob\living\carbon\human\species\station\prometheans.dm" #include "code\modules\mob\living\carbon\human\species\station\seromi.dm" #include "code\modules\mob\living\carbon\human\species\station\station.dm" -#include "code\modules\mob\living\carbon\metroid\death.dm" -#include "code\modules\mob\living\carbon\metroid\emote.dm" -#include "code\modules\mob\living\carbon\metroid\examine.dm" -#include "code\modules\mob\living\carbon\metroid\hud.dm" -#include "code\modules\mob\living\carbon\metroid\items.dm" -#include "code\modules\mob\living\carbon\metroid\life.dm" -#include "code\modules\mob\living\carbon\metroid\login.dm" -#include "code\modules\mob\living\carbon\metroid\metroid.dm" -#include "code\modules\mob\living\carbon\metroid\powers.dm" -#include "code\modules\mob\living\carbon\metroid\say.dm" -#include "code\modules\mob\living\carbon\metroid\subtypes.dm" -#include "code\modules\mob\living\carbon\metroid\update_icons.dm" #include "code\modules\mob\living\silicon\death.dm" #include "code\modules\mob\living\silicon\laws.dm" #include "code\modules\mob\living\silicon\login.dm" @@ -1751,7 +1739,6 @@ #include "code\modules\mob\living\simple_animal\animals\mouse.dm" #include "code\modules\mob\living\simple_animal\animals\parrot.dm" #include "code\modules\mob\living\simple_animal\animals\penguin.dm" -#include "code\modules\mob\living\simple_animal\animals\slime.dm" #include "code\modules\mob\living\simple_animal\animals\spiderbot.dm" #include "code\modules\mob\living\simple_animal\animals\tomato.dm" #include "code\modules\mob\living\simple_animal\animals\tree.dm" @@ -1769,6 +1756,12 @@ #include "code\modules\mob\living\simple_animal\humanoids\pirate.dm" #include "code\modules\mob\living\simple_animal\humanoids\russian.dm" #include "code\modules\mob\living\simple_animal\humanoids\syndicate.dm" +#include "code\modules\mob\living\simple_animal\slime\ai.dm" +#include "code\modules\mob\living\simple_animal\slime\combat.dm" +#include "code\modules\mob\living\simple_animal\slime\death.dm" +#include "code\modules\mob\living\simple_animal\slime\life.dm" +#include "code\modules\mob\living\simple_animal\slime\slime.dm" +#include "code\modules\mob\living\simple_animal\slime\subtypes.dm" #include "code\modules\mob\living\voice\voice.dm" #include "code\modules\mob\new_player\login.dm" #include "code\modules\mob\new_player\logout.dm" @@ -2125,7 +2118,6 @@ #include "code\modules\surgery\organs_internal.dm" #include "code\modules\surgery\other.dm" #include "code\modules\surgery\robotics.dm" -#include "code\modules\surgery\slimes.dm" #include "code\modules\surgery\surgery.dm" #include "code\modules\surgery\~defines.dm" #include "code\modules\tables\bench.dm" @@ -2216,23 +2208,11 @@ #include "code\modules\xenoarcheaology\tools\suspension_generator.dm" #include "code\modules\xenoarcheaology\tools\tools.dm" #include "code\modules\xenoarcheaology\tools\tools_pickaxe.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\xenobio2\tools\xeno_trait_scanner.dm" +#include "code\modules\xenobio\items\extracts.dm" +#include "code\modules\xenobio\items\slime_objects.dm" +#include "code\modules\xenobio\items\slimepotions.dm" +#include "code\modules\xenobio\items\weapons.dm" +#include "code\modules\xenobio\machinery\processor.dm" #include "code\modules\xgm\xgm_gas_data.dm" #include "code\modules\xgm\xgm_gas_mixture.dm" #include "code\unit_tests\loadout_tests.dm" @@ -2262,6 +2242,7 @@ #include "code\ZAS\Zone.dm" #include "interface\interface.dm" #include "interface\skin.dmf" -#include "maps\northern_star\northern_star.dm" +#include "maps\example\example.dm" +#include "maps\example\xenobio_test.dmm" #include "maps\~map_system\maps.dm" // END_INCLUDE