Merge pull request #3767 from Neerti/8/10/2017_make_xenobio_old_again

Make Xenobiology Old(ish) Again
This commit is contained in:
Anewbe
2017-09-10 17:12:38 -04:00
committed by GitHub
140 changed files with 6307 additions and 2782 deletions

View File

@@ -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()

View File

@@ -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.

View File

@@ -212,4 +212,10 @@
#define FBP_NONE ""
#define FBP_CYBORG "Cyborg"
#define FBP_POSI "Positronic"
#define FBP_DRONE "Drone"
#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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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("<span class='notice'>[src] gently pokes [M]!</span>", "<span class='notice'>[src] gently pokes you!</span>")
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("<span class='danger'>[src] has shocked [M]!</span>", "<span class='danger'>[src] has shocked you!</span>")
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("<span class='danger'>[src] has pounced at [M]!</span>", "<span class='danger'>[src] has pounced at you!</span>")
M.Weaken(power)
else
M.visible_message("<span class='danger'>[src] has tried to pounce at [M]!</span>", "<span class='danger'>[src] has tried to pounce at you!</span>")
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

View File

@@ -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")

View File

@@ -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"

View File

@@ -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))

View File

@@ -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 << "<span class='notice'>You are teleported to \the [A].</span>"
uses--
if(uses <= 0)
user << "<span class='danger'>\The [src] has ran out of uses, and disintegrates from your hands, to prevent \
reverse engineering by outsiders.</span>"
qdel(src)
user << "<span class='danger'>\The [src] has ran out of uses, and disintegrates from your hands.</span>"
qdel(src)

View File

@@ -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,

View File

@@ -46,8 +46,8 @@
if(occupant)
user << "<span class='notice'>The scanner is already occupied!</span>"
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 << "<span class='danger'>[H.affecting.name] has a fucking slime attached to them, deal with that first.</span>"
return
var/mob/M = H.affecting
@@ -83,8 +83,8 @@
if(O.abiotic())
user << "<span class='notice'>Subject cannot have abiotic items on.</span>"
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 << "<span class='danger'>[O] has a fucking slime attached to them, deal with that first.</span>"
return 0

View File

@@ -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)

View File

@@ -546,8 +546,8 @@
usr << "<span class='notice'><B>\The [src] is in use.</B></span>"
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

View File

@@ -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, "<span class='notice'>You begin repairing [src]...</span>")
playsound(src, WT.usesound, 50, 1)
if(do_after(user, 40 * WT.toolspeed, target = src))
health = maxhealth
update_icon()
to_chat(user, "<span class='notice'>You repair [src].</span>")
else
to_chat(user, "<span class='warning'>[src] is already in good condition!</span>")
return
//Emags and ninja swords? You may pass.
if (istype(I, /obj/item/weapon/melee/energy/blade))
if(emag_act(10, user))

View File

@@ -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

View File

@@ -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].")

View File

@@ -1154,8 +1154,8 @@
usr << "<span class='danger'>Kinda hard to climb in while handcuffed don't you think?</span>"
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 << "<span class='danger'>You're too busy getting your life sucked out of you.</span>"
return

View File

@@ -1015,8 +1015,8 @@
usr << "<span class='warning'>Access denied</span>"
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]"

View File

@@ -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)
@@ -19,18 +22,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 << "<span class='notice'>\The [src] already has someone buckled to it.</span>"
@@ -46,7 +51,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
@@ -57,19 +62,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 << "<span class='warning'>You can't buckle anyone in before the game starts.</span>"
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 << "<span class='warning'>The [M] is too squishy to buckle in.</span>"
return
add_fingerprint(user)
unbuckle_mob()
@@ -78,20 +80,21 @@
if(M.loc != src.loc)
step_towards(M, src)
. = buckle_mob(M)
. = buckle_mob(M, forced)
if(.)
if(M == user)
M.visible_message(\
"<span class='notice'>[M.name] buckles themselves to [src].</span>",\
"<span class='notice'>You buckle yourself to [src].</span>",\
"<span class='notice'>You hear metal clanking.</span>")
else
M.visible_message(\
"<span class='danger'>[M.name] is buckled to [src] by [user.name]!</span>",\
"<span class='danger'>You are buckled to [src] by [user.name]!</span>",\
"<span class='notice'>You hear metal clanking.</span>")
if(!silent)
if(M == user)
M.visible_message(\
"<span class='notice'>[M.name] buckles themselves to [src].</span>",\
"<span class='notice'>You buckle yourself to [src].</span>",\
"<span class='notice'>You hear metal clanking.</span>")
else
M.visible_message(\
"<span class='danger'>[M.name] is buckled to [src] by [user.name]!</span>",\
"<span class='danger'>You are buckled to [src] by [user.name]!</span>",\
"<span class='notice'>You hear metal clanking.</span>")
/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)
@@ -107,3 +110,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

View File

@@ -449,10 +449,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.

View File

@@ -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 << "<B>This device can only scan slimes!</B>"
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("<span class='alert'>Warning: slime is starving!</span>")
else if (T.nutrition < T.get_hunger_nutrition())
user.show_message("<span class='warning'>Warning: slime is hungry</span>")
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("<span class='alert'>Warning: Subject is starving!</span>")
else if (S.nutrition < S.get_hunger_nutrition())
user.show_message("<span class='warning'>Warning: Subject is hungry.</span>")
user.show_message("Electric change strength: [S.power_charge]")
if(S.resentment)
user.show_message("<span class='warning'>Warning: Subject is harboring resentment.</span>")
if(S.docile)
user.show_message("Subject has been pacified.")
if(S.rabid)
user.show_message("<span class='danger'>Subject is enraged and extremely dangerous!</span>")
if(S.unity)
user.show_message("Subject is friendly to other slime colors.")
user.show_message("Growth progress: [S.amount_grown]/10")

View File

@@ -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()

View File

@@ -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

View File

@@ -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 << "<span class='notice'>[src] already has a cell.</span>"
else
user << "<span class='notice'>This cell is not fitted for [src].</span>"
user << "<span class='notice'>This cell is not fitted for [src].</span>"
/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

View File

@@ -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,

View File

@@ -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"

View File

@@ -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"

View File

@@ -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("<span class='danger'>[user] smashes into [src]!</span>")
if(reinf)
damage = damage / 2
take_damage(damage)
else
visible_message("<span class='notice'>\The [user] bonks \the [src] harmlessly.</span>")
@@ -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, "<span class='notice'>You begin repairing [src]...</span>")
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, "<span class='notice'>You repair [src].</span>")
else
to_chat(user, "<span class='warning'>[src] is already in good condition!</span>")
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))
@@ -410,6 +433,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)
@@ -439,6 +471,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."
@@ -451,6 +487,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"
@@ -472,9 +511,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"

View File

@@ -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
)

View File

@@ -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()

View File

@@ -114,8 +114,7 @@ proc/admin_notice(var/message, var/rights)
else if(ishuman(M))
body += {"<A href='?src=\ref[src];makeai=\ref[M]'>Make AI</A> |
<A href='?src=\ref[src];makerobot=\ref[M]'>Make Robot</A> |
<A href='?src=\ref[src];makealien=\ref[M]'>Make Alien</A> |
<A href='?src=\ref[src];makeslime=\ref[M]'>Make slime</A>
<A href='?src=\ref[src];makealien=\ref[M]'>Make Alien</A>
"}
//Simple Animals

View File

@@ -191,7 +191,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,

View File

@@ -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 )
@@ -1156,16 +1156,6 @@
usr.client.cmd_admin_alienize(H)
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

View File

@@ -117,24 +117,6 @@
else
alert("Invalid mob")
/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("<font color='blue'>[key_name_admin(usr)] made [key_name(M)] into a slime.</font>", 1)
else
alert("Invalid mob")
/*
/client/proc/cmd_admin_monkeyize(var/mob/M in world)
set category = "Fun"

View File

@@ -69,7 +69,6 @@
<option value='?_src_=vars;makerobot=\ref[src]'>Make cyborg</option>
<option value='?_src_=vars;makemonkey=\ref[src]'>Make monkey</option>
<option value='?_src_=vars;makealien=\ref[src]'>Make alien</option>
<option value='?_src_=vars;makeslime=\ref[src]'>Make slime</option>
"}
/obj/get_view_variables_options()

View File

@@ -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

View File

@@ -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

View File

@@ -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"),
)

View File

@@ -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)

View File

@@ -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 <b>[target_name(target)]</b> in <b>[get_area(src)]</b>.", 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"] <b>[target_name(target)]</b> in <b>[get_area(src)]</b>.", 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("<span class='warning'>\The [C] was prodded by \the [src] with a stun baton!</span>")
insult(C)
else
playsound(loc, 'sound/weapons/handcuffs.ogg', 30, 1, -2)
visible_message("<span class='warning'>\The [src] is trying to put handcuffs on \the [C]!</span>")
@@ -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("<span class='warning'>\The [M] was beaten by \the [src] with a stun baton!</span>")
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)

View File

@@ -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 ..()

View File

@@ -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

View File

@@ -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()

View File

@@ -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'

View File

@@ -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')

View File

@@ -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 << "<span class='warning'> This extract has already been enhanced!</span>"
return ..()
if(Uses == 0)
user << "<span class='warning'> You can't enhance a used extract!</span>"
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 << "<span class='warning'> This extract has already been enhanced!</span>"
return ..()
if(Uses == 0)
user << "<span class='warning'> You can't enhance a used extract!</span>"
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 << "<span class='warning'> The potion only works on baby slimes!</span>"
return ..()
if(M.is_adult) //Can't tame adults
user << "<span class='warning'> Only baby slimes can be tamed!</span>"
return..()
if(M.stat)
user << "<span class='warning'> The slime is dead!</span>"
return..()
if(M.mind)
user << "<span class='warning'> The slime resists!</span>"
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 << "<span class='warning'> The potion only works on slimes!</span>"
return ..()
// if(M.is_adult) //Can't tame adults
// user << "<span class='warning'> Only baby slimes can be tamed!</span>"
// return..()
if(M.stat)
user << "<span class='warning'> The slime is dead!</span>"
return..()
if(M.mind)
user << "<span class='warning'> The slime resists!</span>"
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, "<span class='warning'>The stabilizer only works on slimes!</span>")
return ..()
if(M.stat)
to_chat(user, "<span class='warning'>The slime is dead!</span>")
return ..()
if(M.mutation_chance == 0)
to_chat(user, "<span class='warning'>The slime already has no chance of mutating!</span>")
return ..()
to_chat(user, "<span class='notice'>You feed the slime the stabilizer. It is now less likely to mutate.</span>")
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."

View File

@@ -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,12 @@ default behaviour is:
return
/mob/living/Move(a, b, flag)
if (buckled)
return
if (buckled && buckled.loc != a) //not updating position
if (!buckled.anchored)
return buckled.Move(a, b)
else
return 0
if (restrained())
stop_pulling()
@@ -724,10 +726,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

View File

@@ -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"

View File

@@ -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,
)

View File

@@ -719,6 +719,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)

View File

@@ -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")

View File

@@ -8,6 +8,7 @@
icon_gib = "syndicate_gib"
faction = "xeno"
intelligence_level = SA_HUMANOID
cooperative = 1
run_at_them = 0

View File

@@ -7,6 +7,7 @@
icon_dead = "otherthing-dead"
faction = "creature"
intelligence_level = SA_ANIMAL
maxHealth = 40
health = 40
speed = 8

View File

@@ -8,6 +8,7 @@
icon_dead = "drone_dead"
faction = "malf_drone"
intelligence_level = SA_ROBOTIC
maxHealth = 300
health = 300
speed = 8

View File

@@ -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

View File

@@ -7,6 +7,7 @@
icon_dead = "basic"
faction = "hivebot"
intelligence_level = SA_ROBOTIC
maxHealth = 15
health = 15
speed = 4

View File

@@ -10,6 +10,7 @@
icon_living = "crate"
faction = "mimic"
intelligence_level = SA_ANIMAL
maxHealth = 250
health = 250

View File

@@ -8,6 +8,7 @@
icon_dead = "shade_dead"
faction = "cult"
intelligence_level = SA_HUMANOID
maxHealth = 50
health = 50

View File

@@ -8,6 +8,7 @@
icon_gib = "bat_dead"
faction = "scarybat"
intelligence_level = SA_ANIMAL
maxHealth = 20
health = 20

View File

@@ -8,6 +8,7 @@
icon_gib = "bear_gib"
faction = "russian"
intelligence_level = SA_ANIMAL
cooperative = 1
maxHealth = 60

View File

@@ -7,6 +7,7 @@
icon_gib = "carp_gib"
faction = "carp"
intelligence_level = SA_ANIMAL
maxHealth = 25
health = 25
speed = 4

View File

@@ -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"

View File

@@ -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"

View File

@@ -5,6 +5,7 @@
icon_state = "crab"
icon_living = "crab"
icon_dead = "crab_dead"
intelligence_level = SA_ANIMAL
wander = 0
stop_automated_movement = 1

View File

@@ -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

View File

@@ -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(

View File

@@ -13,6 +13,7 @@
icon_dead = "guard_dead"
faction = "spiders"
intelligence_level = SA_ANIMAL
maxHealth = 200
health = 200
pass_flags = PASSTABLE

View File

@@ -7,6 +7,7 @@
icon_gib = "generic_gib"
faction = "geese"
intelligence_level = SA_ANIMAL
maxHealth = 15
health = 15

View File

@@ -5,6 +5,7 @@
icon_state = "lizard"
icon_living = "lizard"
icon_dead = "lizard-dead"
intelligence_level = SA_ANIMAL
health = 5
maxHealth = 5

View File

@@ -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

View File

@@ -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

View File

@@ -5,6 +5,7 @@
icon_living = "penguin"
icon_dead = "penguin_dead"
icon_gib = "generic_gib"
intelligence_level = SA_ANIMAL
maxHealth = 20
health = 20

View File

@@ -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

View File

@@ -4,6 +4,7 @@
icon_state = "tomato"
icon_living = "tomato"
icon_dead = "tomato_dead"
intelligence_level = SA_PLANT
faction = "plants"
maxHealth = 15

View File

@@ -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

View File

@@ -5,6 +5,7 @@
icon_state = "spaceworm"
icon_living = "spaceworm"
icon_dead = "spacewormdead"
intelligence_level = SA_ANIMAL
maxHealth = 30

View File

@@ -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"

View File

@@ -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

View File

@@ -5,6 +5,7 @@
icon_living = "clown"
icon_dead = "clown_dead"
icon_gib = "clown_gib"
intelligence_level = SA_HUMANOID
faction = "clown"
maxHealth = 75

View File

@@ -5,6 +5,7 @@
icon_state = "crab"
icon_living = "crab"
icon_dead = "crab_dead"
intelligence_level = SA_ANIMAL
wander = 0
stop_automated_movement = 1

View File

@@ -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

View File

@@ -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

View File

@@ -4,6 +4,7 @@
icon_state = "piratemelee"
icon_living = "piratemelee"
icon_dead = "piratemelee_dead"
intelligence_level = SA_HUMANOID
faction = "pirate"
maxHealth = 100

View File

@@ -5,6 +5,7 @@
icon_living = "russianmelee"
icon_dead = "russianmelee_dead"
icon_gib = "syndicate_gib"
intelligence_level = SA_HUMANOID
faction = "russian"
maxHealth = 100

View File

@@ -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

View File

@@ -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 << "<span class='notice'>Mob AI disabled while you are controlling the mob.</span>"
..()
@@ -241,7 +245,7 @@
/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
//Dead
@@ -249,13 +253,33 @@
icon_state = icon_dead
//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
//Backup
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("<span class='notice'>[user] gently taps [src] with \the [O].</span>")
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("<span class='danger'><b>[src]</b> fires at [target]!</span>", 1)
visible_message("<span class='danger'><b>[src]</b> fires at [target]!</span>")
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

View File

@@ -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
*/

View File

@@ -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") >= 75)
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("<span class='danger'>\The [src] latches onto [victim]!</span>",
"<span class='danger'>\The [src] latches onto you!</span>")
/mob/living/simple_animal/slime/proc/stop_consumption()
if(!victim)
return
victim.unbuckle_mob()
victim.visible_message("<span class='notice'>\The [src] slides off of [victim]!</span>",
"<span class='notice'>\The [src] slides off of you!</span>")
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, "<span class='warning'>[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")]...</span>")
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("<span class='notice'>[src] gently pokes [L]!</span>",
"<span class='notice'>[src] gently pokes you!</span>")
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("<span class='danger'>[src] has shocked [L]!</span>", "<span class='danger'>[src] has shocked you!</span>")
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("<span class='danger'>[src] has pounced at [L]!</span>", "<span class='danger'>[src] has pounced at you!</span>")
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("<span class='danger'>[src] has tried to pounce at [L]!</span>", "<span class='danger'>[src] has tried to pounce at you!</span>")
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("<span class='danger'>\The [user]'s [W] passes right through [src]!</span>")
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("<span class='warning'>[M] attempts to wrestle \the [name] off!</span>")
playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
else
visible_message("<span class='warning'> [M] manages to wrestle \the [name] off!</span>")
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, "<span class='notice'>\The [source] shocks you, and it charges you.</span>")

View File

@@ -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

View File

@@ -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, "<span class='danger'>You are starving!</span>")
/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])
*/

View File

@@ -0,0 +1,436 @@
/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("<span class='danger'>\The [src] enrages!</span>")
// 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, "<span class='notice'>I must be conscious to do this...</span>")
return
if(docile)
to_chat(src, "<span class='notice'>I have been pacified. I cannot evolve...</span>")
return
if(!is_adult)
if(amount_grown >= 10)
make_adult()
else
to_chat(src, "<span class='notice'>I am not ready to evolve yet...</span>")
else
to_chat(src, "<span class='notice'>I have already evolved...</span>")
/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, "<span class='notice'>I must be conscious to do this...</span>")
return
if(docile)
to_chat(src, "<span class='notice'>I have been pacified. I cannot reproduce...</span>")
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, "<span class='notice'>I am not ready to reproduce yet...</span>")
else
to_chat(src, "<span class='notice'>I am not old enough to reproduce yet...</span>")
// Used for reproducing and dying.
/mob/living/simple_animal/slime/proc/make_new_slime()
var/t = src.type
if(prob(mutation_chance / 10))
t = /mob/living/simple_animal/slime/rainbow
else 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, "<span class='warning'>\The [new_hat] isn't a hat.</span>")
return
if(hat)
to_chat(user, "<span class='warning'>\The [src] is already wearing \a [hat].</span>")
return
else
user.drop_item(new_hat)
hat = new_hat
new_hat.forceMove(src)
to_chat(user, "<span class='notice'>You place \a [new_hat] on \the [src]. How adorable!</span>")
update_icon()
return
/mob/living/simple_animal/slime/proc/remove_hat(var/mob/living/user)
if(!hat)
to_chat(user, "<span class='warning'>\The [src] doesn't have a hat to remove.</span>")
else
hat.forceMove(get_turf(src))
user.put_in_hands(hat)
to_chat(user, "<span class='warning'>You take away \the [src]'s [hat.name]. How mean.</span>")
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")

View File

@@ -0,0 +1,709 @@
// 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("<span class='danger'>\The [src] erupts in an inferno!</span>")
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("<span class='danger'>\The [src] reflects \the [P]!</span>")
// 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, "<span class='warning'>There's nothing to teleport to.</span>")
return FALSE
if(world.time < last_tele + tele_cooldown)
to_chat(src, "<span class='warning'>You can't teleport right now, wait a few seconds.</span>")
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, "<span class='warning'>There wasn't an unoccupied spot to teleport to.</span>")
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("<span class='notice'>\The [src] vanishes!</span>")
s1.start()
forceMove(target_turf)
playsound(target_turf, 'sound/effects/phasein.ogg', 50, 1)
to_chat(src, "<span class='notice'>You teleport to \the [target_turf].</span>")
target_turf.visible_message("<span class='warning'>\The [src] appears!</span>")
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. \
Their glomp attacks also send the victim flying."
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/ruby/DoPunch(var/mob/living/L)
..() // Do regular attacks.
if(istype(L))
if(a_intent == I_HURT)
visible_message("<span class='danger'>\The [src] sends \the [L] flying with the impact!</span>")
playsound(src, "punch", 50, 1)
L.Weaken(1)
var/throwdir = get_dir(src, L)
L.throw_at(get_edge_target_turf(L, throwdir), 3, 1, src)
/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. The amber slime cannot feed itself, but can be fed by other amber slimes."
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 = "<span class='warning'>Twinkling spores of goo surround you. It makes you feel healthier.</span>"
on_expired_text = "<span class='notice'>The spores of goo have faded, although you feel much healthier than before.</span>"
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/pink,
/mob/living/simple_animal/slime/pink,
/mob/living/simple_animal/slime/light_pink,
/mob/living/simple_animal/slime/light_pink
)
// 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()
..()

View File

@@ -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)

View File

@@ -542,13 +542,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

View File

@@ -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.

View File

@@ -35,6 +35,9 @@
usr << "<span class='danger'>Speech is currently admin-disabled.</span>"
return
if(!client)
return // Clientless mobs shouldn't be trying to talk in deadchat.
if(!src.client.holder)
if(!config.dsay_allowed)
src << "<span class='danger'>Deadchat is globally muted.</span>"

View File

@@ -185,39 +185,6 @@
qdel(src)
return
/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 << "<B>You are now a slime. Skreee!</B>"
qdel(src)
return
/mob/living/carbon/human/proc/corgize()
if (transforming)

View File

@@ -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

View File

@@ -46,6 +46,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"
@@ -166,6 +167,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"

Some files were not shown because too many files have changed in this diff Show More