mirror of
https://github.com/PolarisSS13/Polaris.git
synced 2025-12-30 12:03:11 +00:00
Merge pull request #3767 from Neerti/8/10/2017_make_xenobio_old_again
Make Xenobiology Old(ish) Again
This commit is contained in:
@@ -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()
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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].")
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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]"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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,
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"),
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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 ..()
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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')
|
||||
|
||||
|
||||
@@ -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."
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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,
|
||||
|
||||
)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
icon_gib = "syndicate_gib"
|
||||
|
||||
faction = "xeno"
|
||||
intelligence_level = SA_HUMANOID
|
||||
cooperative = 1
|
||||
run_at_them = 0
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
icon_dead = "otherthing-dead"
|
||||
|
||||
faction = "creature"
|
||||
intelligence_level = SA_ANIMAL
|
||||
maxHealth = 40
|
||||
health = 40
|
||||
speed = 8
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
icon_dead = "drone_dead"
|
||||
|
||||
faction = "malf_drone"
|
||||
intelligence_level = SA_ROBOTIC
|
||||
maxHealth = 300
|
||||
health = 300
|
||||
speed = 8
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
icon_dead = "basic"
|
||||
|
||||
faction = "hivebot"
|
||||
intelligence_level = SA_ROBOTIC
|
||||
maxHealth = 15
|
||||
health = 15
|
||||
speed = 4
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
icon_living = "crate"
|
||||
|
||||
faction = "mimic"
|
||||
intelligence_level = SA_ANIMAL
|
||||
|
||||
maxHealth = 250
|
||||
health = 250
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
icon_dead = "shade_dead"
|
||||
|
||||
faction = "cult"
|
||||
intelligence_level = SA_HUMANOID
|
||||
|
||||
maxHealth = 50
|
||||
health = 50
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
icon_gib = "bat_dead"
|
||||
|
||||
faction = "scarybat"
|
||||
intelligence_level = SA_ANIMAL
|
||||
|
||||
maxHealth = 20
|
||||
health = 20
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
icon_gib = "bear_gib"
|
||||
|
||||
faction = "russian"
|
||||
intelligence_level = SA_ANIMAL
|
||||
cooperative = 1
|
||||
|
||||
maxHealth = 60
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
icon_gib = "carp_gib"
|
||||
|
||||
faction = "carp"
|
||||
intelligence_level = SA_ANIMAL
|
||||
maxHealth = 25
|
||||
health = 25
|
||||
speed = 4
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
icon_state = "crab"
|
||||
icon_living = "crab"
|
||||
icon_dead = "crab_dead"
|
||||
intelligence_level = SA_ANIMAL
|
||||
|
||||
wander = 0
|
||||
stop_automated_movement = 1
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
icon_dead = "guard_dead"
|
||||
|
||||
faction = "spiders"
|
||||
intelligence_level = SA_ANIMAL
|
||||
maxHealth = 200
|
||||
health = 200
|
||||
pass_flags = PASSTABLE
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
icon_gib = "generic_gib"
|
||||
|
||||
faction = "geese"
|
||||
intelligence_level = SA_ANIMAL
|
||||
|
||||
maxHealth = 15
|
||||
health = 15
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
icon_state = "lizard"
|
||||
icon_living = "lizard"
|
||||
icon_dead = "lizard-dead"
|
||||
intelligence_level = SA_ANIMAL
|
||||
|
||||
health = 5
|
||||
maxHealth = 5
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
icon_living = "penguin"
|
||||
icon_dead = "penguin_dead"
|
||||
icon_gib = "generic_gib"
|
||||
intelligence_level = SA_ANIMAL
|
||||
|
||||
maxHealth = 20
|
||||
health = 20
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
icon_state = "tomato"
|
||||
icon_living = "tomato"
|
||||
icon_dead = "tomato_dead"
|
||||
intelligence_level = SA_PLANT
|
||||
|
||||
faction = "plants"
|
||||
maxHealth = 15
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
icon_state = "spaceworm"
|
||||
icon_living = "spaceworm"
|
||||
icon_dead = "spacewormdead"
|
||||
intelligence_level = SA_ANIMAL
|
||||
|
||||
|
||||
maxHealth = 30
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
icon_living = "clown"
|
||||
icon_dead = "clown_dead"
|
||||
icon_gib = "clown_gib"
|
||||
intelligence_level = SA_HUMANOID
|
||||
|
||||
faction = "clown"
|
||||
maxHealth = 75
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
icon_state = "crab"
|
||||
icon_living = "crab"
|
||||
icon_dead = "crab_dead"
|
||||
intelligence_level = SA_ANIMAL
|
||||
|
||||
wander = 0
|
||||
stop_automated_movement = 1
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
icon_state = "piratemelee"
|
||||
icon_living = "piratemelee"
|
||||
icon_dead = "piratemelee_dead"
|
||||
intelligence_level = SA_HUMANOID
|
||||
|
||||
faction = "pirate"
|
||||
maxHealth = 100
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
icon_living = "russianmelee"
|
||||
icon_dead = "russianmelee_dead"
|
||||
icon_gib = "syndicate_gib"
|
||||
intelligence_level = SA_HUMANOID
|
||||
|
||||
faction = "russian"
|
||||
maxHealth = 100
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
58
code/modules/mob/living/simple_animal/slime/ai.dm
Normal file
58
code/modules/mob/living/simple_animal/slime/ai.dm
Normal 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
|
||||
*/
|
||||
276
code/modules/mob/living/simple_animal/slime/combat.dm
Normal file
276
code/modules/mob/living/simple_animal/slime/combat.dm
Normal 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>")
|
||||
24
code/modules/mob/living/simple_animal/slime/death.dm
Normal file
24
code/modules/mob/living/simple_animal/slime/death.dm
Normal 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
|
||||
174
code/modules/mob/living/simple_animal/slime/life.dm
Normal file
174
code/modules/mob/living/simple_animal/slime/life.dm
Normal 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])
|
||||
*/
|
||||
436
code/modules/mob/living/simple_animal/slime/slime.dm
Normal file
436
code/modules/mob/living/simple_animal/slime/slime.dm
Normal 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")
|
||||
|
||||
709
code/modules/mob/living/simple_animal/slime/subtypes.dm
Normal file
709
code/modules/mob/living/simple_animal/slime/subtypes.dm
Normal 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()
|
||||
..()
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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>"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user