Animal Tweaks: Second attempt (#849)

* Merge branch 'AnimalTweaks_Fix4' into AnimalTweaks_Fix5

# Conflicts:
#	code/modules/mob/living/living.dm

* REMOVED VENT THINGS FROM CHANGELOG

* switch statement for helper
This commit is contained in:
NanakoAC
2016-09-12 07:06:40 +01:00
committed by GitHub
parent 0a2df816c6
commit a5478a5360
20 changed files with 472 additions and 232 deletions
+79 -79
View File
@@ -20,94 +20,94 @@
if(holder)
holder.update_icon()
proc/triggered(mob/target as mob, var/type = "feet")
if(!armed)
/obj/item/device/assembly/mousetrap/proc/triggered(mob/target as mob, var/type = "feet")
if(!armed)
return
var/obj/item/organ/external/affecting = null
if(ishuman(target))
var/mob/living/carbon/human/H = target
switch(type)
if("feet")
if(!H.shoes)
affecting = H.get_organ(pick("l_leg", "r_leg"))
H.Weaken(3)
if("l_hand", "r_hand")
if(!H.gloves)
affecting = H.get_organ(type)
H.Stun(3)
if(affecting)
if(affecting.take_damage(rand(7,12), 0))
H.UpdateDamageIcon()
H.updatehealth()
else if(ismouse(target))
var/mob/living/simple_animal/mouse/M = target
visible_message("\red <b>SPLAT!</b>")
M.splat()
playsound(target.loc, 'sound/effects/snap.ogg', 50, 1)
layer = MOB_LAYER - 0.2
armed = 0
update_icon()
pulse(0)
/obj/item/device/assembly/mousetrap/attack_self(mob/living/user as mob)
if(!armed)
user << "<span class='notice'>You arm [src].</span>"
else
if(((user.getBrainLoss() >= 60 || (CLUMSY in user.mutations)) && prob(50)))
var/which_hand = "l_hand"
if(!user.hand)
which_hand = "r_hand"
triggered(user, which_hand)
user.visible_message("<span class='warning'>[user] accidentally sets off [src], breaking their fingers.</span>", \
"<span class='warning'>You accidentally trigger [src]!</span>")
return
var/obj/item/organ/external/affecting = null
if(ishuman(target))
var/mob/living/carbon/human/H = target
switch(type)
if("feet")
if(!H.shoes)
affecting = H.get_organ(pick("l_leg", "r_leg"))
H.Weaken(3)
if("l_hand", "r_hand")
if(!H.gloves)
affecting = H.get_organ(type)
H.Stun(3)
if(affecting)
if(affecting.take_damage(1, 0))
H.UpdateDamageIcon()
H.updatehealth()
else if(ismouse(target))
var/mob/living/simple_animal/mouse/M = target
visible_message("\red <b>SPLAT!</b>")
M.splat()
playsound(target.loc, 'sound/effects/snap.ogg', 50, 1)
layer = MOB_LAYER - 0.2
armed = 0
update_icon()
pulse(0)
user << "<span class='notice'>You disarm [src].</span>"
armed = !armed
update_icon()
playsound(user.loc, 'sound/weapons/handcuffs.ogg', 30, 1, -3)
attack_self(mob/living/user as mob)
if(!armed)
user << "<span class='notice'>You arm [src].</span>"
else
if(((user.getBrainLoss() >= 60 || (CLUMSY in user.mutations)) && prob(50)))
var/which_hand = "l_hand"
if(!user.hand)
which_hand = "r_hand"
triggered(user, which_hand)
user.visible_message("<span class='warning'>[user] accidentally sets off [src], breaking their fingers.</span>", \
"<span class='warning'>You accidentally trigger [src]!</span>")
return
user << "<span class='notice'>You disarm [src].</span>"
armed = !armed
update_icon()
playsound(user.loc, 'sound/weapons/handcuffs.ogg', 30, 1, -3)
/obj/item/device/assembly/mousetrap/attack_hand(mob/living/user as mob)
if(armed)
if(((user.getBrainLoss() >= 60 || CLUMSY in user.mutations)) && prob(50))
var/which_hand = "l_hand"
if(!user.hand)
which_hand = "r_hand"
triggered(user, which_hand)
user.visible_message("<span class='warning'>[user] accidentally sets off [src], breaking their fingers.</span>", \
"<span class='warning'>You accidentally trigger [src]!</span>")
return
..()
attack_hand(mob/living/user as mob)
if(armed)
if(((user.getBrainLoss() >= 60 || CLUMSY in user.mutations)) && prob(50))
var/which_hand = "l_hand"
if(!user.hand)
which_hand = "r_hand"
triggered(user, which_hand)
user.visible_message("<span class='warning'>[user] accidentally sets off [src], breaking their fingers.</span>", \
"<span class='warning'>You accidentally trigger [src]!</span>")
return
..()
/obj/item/device/assembly/mousetrap/Crossed(AM as mob|obj)
if(armed)
if(ishuman(AM))
var/mob/living/carbon/H = AM
if(H.m_intent == "run")
triggered(H)
H.visible_message("<span class='warning'>[H] accidentally steps on [src].</span>", \
"<span class='warning'>You accidentally step on [src]</span>")
if(ismouse(AM))
triggered(AM)
..()
Crossed(AM as mob|obj)
if(armed)
if(ishuman(AM))
var/mob/living/carbon/H = AM
if(H.m_intent == "run")
triggered(H)
H.visible_message("<span class='warning'>[H] accidentally steps on [src].</span>", \
"<span class='warning'>You accidentally step on [src]</span>")
if(ismouse(AM))
triggered(AM)
..()
/obj/item/device/assembly/mousetrap/on_found(mob/finder as mob)
if(armed)
finder.visible_message("<span class='warning'>[finder] accidentally sets off [src], breaking their fingers.</span>", \
"<span class='warning'>You accidentally trigger [src]!</span>")
triggered(finder, finder.hand ? "l_hand" : "r_hand")
return 1 //end the search!
return 0
on_found(mob/finder as mob)
if(armed)
finder.visible_message("<span class='warning'>[finder] accidentally sets off [src], breaking their fingers.</span>", \
"<span class='warning'>You accidentally trigger [src]!</span>")
triggered(finder, finder.hand ? "l_hand" : "r_hand")
return 1 //end the search!
return 0
hitby(A as mob|obj)
if(!armed)
return ..()
visible_message("<span class='warning'>[src] is triggered by [A].</span>")
triggered(null)
/obj/item/device/assembly/mousetrap/hitby(A as mob|obj)
if(!armed)
return ..()
visible_message("<span class='warning'>[src] is triggered by [A].</span>")
triggered(null)
/obj/item/device/assembly/mousetrap/armed
+38 -14
View File
@@ -15,7 +15,6 @@
var/last_loc_general//This stores a general location of the object. Ie, a container or a mob
var/last_loc_specific//This stores specific extra information about the location, pocket, hand, worn on head, etc. Only relevant to mobs
/obj/item/weapon/holder/New()
if (!item_state)
item_state = icon_state
@@ -29,24 +28,21 @@
processing_objects.Remove(src)
..()
/obj/item/weapon/holder/examine(mob/user)
if (contained)
contained.examine(user)
else
..()
/obj/item/weapon/holder/process()
if(!get_holding_mob() || contained.loc != src)
if (is_unsafe_container(loc) && contained.loc == src)
return
release_mob()
for(var/mob/M in contents)
var/atom/movable/mob_container
mob_container = M
mob_container.forceMove(src.loc)//if the holder was placed into a disposal, this should place the animal in the disposal
M.reset_view()
var/mob/L = get_holding_mob()
if (L)
L.drop_from_inventory(src)
qdel(src)
return
if (isalive && contained.stat == DEAD)
held_death(1)//If we get here, it means the mob died sometime after we picked it up. We pass in 1 so that we can play its deathmessage
@@ -63,6 +59,23 @@
return 0
//Releases all mobs inside the holder, then deletes it.
//is_unsafe_container should be checked before calling this
/obj/item/weapon/holder/proc/release_mob()
for(var/mob/M in contents)
var/atom/movable/mob_container
mob_container = M
mob_container.forceMove(src.loc)//if the holder was placed into a disposal, this should place the animal in the disposal
M.reset_view()
M.Released()
var/mob/L = get_holding_mob()
if (L)
L.drop_from_inventory(src)
qdel(src)
/obj/item/weapon/holder/attackby(obj/item/weapon/W as obj, mob/user as mob)
for(var/mob/M in src.contents)
M.attackby(W,user)
@@ -73,6 +86,13 @@
//once with it on the floor, and then once in the container
//This conditional allows us to ignore that first one. Handling of mobs dropped on the floor is done in process
if (istype(loc, /turf))
spawn(3)
//Repeat this check
//If we're still on the turf a few frames later, then we have actually been dropped or thrown
//Release the mob accordingly
if (istype(loc, /turf))
release_mob()
return
if (istype(loc, /obj/item/weapon/storage)) //The second drop reads the container its placed into as the location
@@ -144,8 +164,12 @@
if(!holder_type || buckled || pinned.len || !Adjacent(grabber))
return
if ((grabber.hand == 0 && grabber.r_hand) || (grabber.hand == 1 && grabber.l_hand))//Checking if the hand is full
grabber << "Your hand is full!"
if (user == src)
if (grabber.r_hand && grabber.l_hand)
user << "\red They have no free hands!"
return
else if ((grabber.hand == 0 && grabber.r_hand) || (grabber.hand == 1 && grabber.l_hand))//Checking if the hand is full
grabber << "\red Your hand is full!"
return
src.verbs += /mob/living/proc/get_holder_location//This has to be before we move the mob into the holder
@@ -284,7 +308,7 @@
icon_state = "mouse_brown_sleep"
item_state = "mouse_brown"
icon_state_dead = "mouse_brown_dead"
//slot_flags = SLOT_EARS //Re-enable this once superballs finishes the sprites
slot_flags = SLOT_EARS
contained_sprite = 1
origin_tech = "biotech=2"
w_class = 1
@@ -300,17 +300,7 @@
var/grabbed_something = 0
for(var/mob/M in T)
if(istype(M,/mob/living/simple_animal/lizard) || istype(M,/mob/living/simple_animal/mouse))
src.loc.visible_message("<span class='danger'>[src.loc] sucks [M] into its decompiler. There's a horrible crunching noise.</span>","<span class='danger'>It's a bit of a struggle, but you manage to suck [M] into your decompiler. It makes a series of visceral crunching noises.</span>")
new/obj/effect/decal/cleanable/blood/splatter(get_turf(src))
qdel(M)
if(wood)
wood.add_charge(2000)
if(plastic)
plastic.add_charge(2000)
return
else if(istype(M,/mob/living/silicon/robot/drone) && !M.client)
if(istype(M,/mob/living/silicon/robot/drone) && !M.client)
var/mob/living/silicon/robot/D = src.loc
@@ -337,6 +327,16 @@
wood.add_charge(2000)
if(plastic)
plastic.add_charge(1000)
else if(istype(M,/mob/living/simple_animal/lizard) || istype(M,/mob/living/simple_animal/mouse))
src.loc.visible_message("<span class='danger'>[src.loc] sucks [M] into its decompiler. There's a horrible crunching noise.</span>","<span class='danger'>It's a bit of a struggle, but you manage to suck [M] into your decompiler. It makes a series of visceral crunching noises.</span>")
new/obj/effect/decal/cleanable/blood/splatter(get_turf(src))
qdel(M)
if(wood)
wood.add_charge(2000)
if(plastic)
plastic.add_charge(2000)
return
else
continue
@@ -403,6 +403,9 @@
user << "<span class='danger'>Nothing on \the [T] is useful to you.</span>"
return
//PRETTIER TOOL LIST.
/mob/living/silicon/robot/drone/installed_modules()
@@ -16,46 +16,51 @@
response_help = "pets"
response_disarm = "gently pushes aside"
response_harm = "kicks"
var/turns_since_scan = 0
var/mob/living/simple_animal/mouse/movement_target
//var/mob/living/simple_animal/mouse/movement_target
var/mob/flee_target
min_oxy = 16 //Require atleast 16kPA oxygen
minbodytemp = 223 //Below -50 Degrees Celcius
maxbodytemp = 323 //Above 50 Degrees Celcius
holder_type = /obj/item/weapon/holder/cat
mob_size = 2.5
scan_range = 3//less aggressive about stealing food
metabolic_factor = 0.75
density = 0
var/mob/living/simple_animal/mouse/mousetarget = null
seek_speed = 5
pass_flags = PASSTABLE
/mob/living/simple_animal/cat/Life()
//MICE!
if((src.loc) && isturf(src.loc))
if(!stat && !resting && !buckled)
for(var/mob/living/simple_animal/mouse/M in loc)
if(!M.stat)
M.splat()
visible_emote(pick("bites \the [M]!","toys with \the [M].","chomps on \the [M]!"))
movement_target = null
stop_automated_movement = 0
break
..()
for(var/mob/living/simple_animal/mouse/snack in oview(src,5))
if(snack.stat < DEAD && prob(15))
audible_emote(pick("hisses and spits!","mrowls fiercely!","eyes [snack] hungrily."))
break
for(var/mob/living/simple_animal/mouse/snack in oview(src,7))
if(snack.stat != DEAD && prob(65))//The probability allows her to not get stuck target the first mouse, reducing exploits
mousetarget = snack
movement_target = snack
foodtarget = 0//chasing mice takes precedence over eating food
if(prob(15))
audible_emote(pick("hisses and spits!","mrowls fiercely!","eyes [snack] hungrily."))
break
if(!stat && !resting && !buckled)
turns_since_scan++
if (turns_since_scan > 5)
if (turns_since_move > 5 || (flee_target || mousetarget))
walk_to(src,0)
turns_since_scan = 0
turns_since_move = 0
if (flee_target) //fleeing takes precendence
handle_flee_target()
else
handle_movement_target()
if (!movement_target)
walk_to(src,0)
spawn(2)
attack_mice()
if(prob(2)) //spooky
var/mob/dead/observer/spook = locate() in range(src,5)
if(spook)
@@ -77,14 +82,32 @@
if( !movement_target || !(movement_target.loc in oview(src, 4)) )
movement_target = null
stop_automated_movement = 0
for(var/mob/living/simple_animal/mouse/snack in oview(src)) //search for a new target
if(isturf(snack.loc) && !snack.stat)
movement_target = snack
break
if(movement_target)
stop_automated_movement = 1
walk_to(src,movement_target,0,3)
walk_to(src,movement_target,0,seek_move_delay)
/mob/living/simple_animal/cat/proc/attack_mice()
if((src.loc) && isturf(src.loc))
if(!stat && !resting && !buckled)
for(var/mob/living/simple_animal/mouse/M in oview(src,1))
if(M.stat != DEAD)
M.splat()
visible_emote(pick("bites \the [M]!","toys with \the [M].","chomps on \the [M]!"))
movement_target = null
stop_automated_movement = 0
if (prob(75))
break//usually only kill one mouse per proc
/mob/living/simple_animal/cat/beg(var/atom/thing, var/atom/holder)
visible_emote("licks [get_pronoun(POSESSIVE_ADJECTIVE)] lips and hungrily glares at [holder]'s [thing.name]")
/mob/living/simple_animal/cat/Released()
//A thrown cat will immediately attack mice near where it lands
handle_movement_target()
spawn(3)
attack_mice()
..()
/mob/living/simple_animal/cat/death()
.=..()
@@ -105,7 +128,7 @@
/mob/living/simple_animal/cat/proc/set_flee_target(atom/A)
if(A)
flee_target = A
turns_since_scan = 5
turns_since_move = 5
/mob/living/simple_animal/cat/attackby(var/obj/item/O, var/mob/user)
. = ..()
@@ -154,7 +177,7 @@
//walk to friend
stop_automated_movement = 1
movement_target = friend
walk_to(src, movement_target, near_dist, 4)
walk_to(src, movement_target, near_dist, seek_move_delay)
//already following and close enough, stop
else if (current_dist <= near_dist)
@@ -19,22 +19,18 @@
response_harm = "kicks"
see_in_dark = 5
mob_size = 5
max_nutrition = 300//Dogs are insatiable eating monsters. This scales with their mob size too
max_nutrition = 250//Dogs are insatiable eating monsters. This scales with their mob size too
stomach_size_mult = 30
seek_speed = 6
var/obj/item/inventory_head
var/obj/item/inventory_back
var/facehugger
var/foodtarget = 0//If the corgi's current target is food, set this to 1
var/scanInterval = 1//Used to control how often ian scans for nearby food
//It gradually increases up to 10 when hes left alone, to save performance
//It will drop back to 1 if he spies any food.
//This short time makes him more responsive to interactions and more fun to play with
/mob/living/simple_animal/corgi/New()
..()
nutrition = max_nutrition * 0.3//Ian doesn't start with a full belly so will be hungry at roundstart
nutrition_step = mob_size * 0.15
nutrition_step = mob_size * 0.12
//IAN! SQUEEEEEEEEE~
/mob/living/simple_animal/corgi/Ian
@@ -42,8 +38,7 @@
real_name = "Ian" //Intended to hold the name without altering it.
gender = MALE
desc = "It's a corgi."
var/turns_since_scan = 0
var/obj/movement_target
//var/obj/movement_target
response_help = "pets"
response_disarm = "bops"
response_harm = "kicks"
@@ -51,72 +46,7 @@
/mob/living/simple_animal/corgi/Ian/Life()
..()
//Feeding, chasing food, FOOOOODDDD
if(!stat && !resting && !buckled)
turns_since_scan++
if(turns_since_scan > scanInterval)
turns_since_scan = 0
if((movement_target) && (!(isturf(movement_target.loc) || ishuman(movement_target.loc))) || (foodtarget && !can_eat() ))
movement_target = null
foodtarget = 0
stop_automated_movement = 0
if( !movement_target || !(movement_target.loc in oview(src, 7)) )
movement_target = null
foodtarget = 0
stop_automated_movement = 0
if (can_eat())
for(var/obj/item/weapon/reagent_containers/food/snacks/S in oview(src,7))
if(isturf(S.loc) || ishuman(S.loc))
movement_target = S
foodtarget = 1
break
//Ian looks for food in people's hand
if (!movement_target)
var/obj/item/weapon/reagent_containers/food/snacks/F = null
for(var/mob/living/carbon/human/H in oview(src,7))
if(istype(H.l_hand, /obj/item/weapon/reagent_containers/food/snacks))
F = H.l_hand
if(istype(H.r_hand, /obj/item/weapon/reagent_containers/food/snacks))
F = H.r_hand
if (F)
movement_target = F
foodtarget = 1
break
if(movement_target)
scanInterval = 1
stop_automated_movement = 1
step_to(src,movement_target,1)
sleep(3)
step_to(src,movement_target,1)
sleep(3)
step_to(src,movement_target,1)
if(movement_target) //Not redundant due to sleeps, Item can be gone in 6 decisecomds
if (movement_target.loc.x < src.x)
set_dir(WEST)
else if (movement_target.loc.x > src.x)
set_dir(EAST)
else if (movement_target.loc.y < src.y)
set_dir(SOUTH)
else if (movement_target.loc.y > src.y)
set_dir(NORTH)
else
set_dir(SOUTH)
if(isturf(movement_target.loc))
for(var/direction in alldirs)
var/turf/T = get_step(src, direction)
if(T == movement_target.loc)
UnarmedAttack(movement_target)
else if(ishuman(movement_target.loc) && prob(20))
visible_emote("stares at the [movement_target] that [movement_target.loc] has with sad puppy eyes.")
else
scanInterval = min(scanInterval+1, 10)//If nothing is happening, ian's scanning frequency slows down to save processing
if(prob(1))
visible_emote(pick("dances around","chases their tail"))
spawn(0)
@@ -124,6 +54,13 @@
set_dir(i)
sleep(1)
/mob/living/simple_animal/corgi/beg(var/atom/thing, var/atom/holder)
visible_emote("stares at the [thing] that [holder] has with sad puppy eyes.")
/obj/item/weapon/reagent_containers/food/snacks/meat/corgi
name = "Corgi meat"
desc = "Tastes like... well you know..."
@@ -134,6 +71,11 @@
for(var/mob/M in viewers(user, null))
if ((M.client && !( M.blinded )))
M.show_message("\blue [user] baps [name] on the nose with the rolled up [O]")
scan_interval = max_scan_interval//discipline your dog to make it stop stealing food for a while
movement_target = null
foodtarget = 0
stop_automated_movement = 0
turns_since_scan = 0
spawn(0)
for(var/i in list(1,2,4,8,4,2,1,2))
set_dir(i)
@@ -199,7 +141,6 @@
response_help = "pets"
response_disarm = "bops"
response_harm = "kicks"
var/turns_since_scan = 0
var/puppies = 0
//Lisa already has a cute bow!
@@ -17,7 +17,8 @@
response_harm = "stomps"
stop_automated_movement = 1
friendly = "pinches"
mob_size = 3
mob_size = 5
hunger_enabled = 0
var/obj/item/inventory_head
var/obj/item/inventory_mask
@@ -30,6 +30,9 @@
udder.my_atom = src
..()
/mob/living/simple_animal/hostile/retaliate/goat/beg(var/atom/thing, var/atom/holder)
visible_emote("butts insistently at [holder]'s legs and reaches towards their [thing].")
/mob/living/simple_animal/hostile/retaliate/goat/Life()
. = ..()
if(.)
@@ -104,7 +107,9 @@
response_disarm = "gently pushes aside"
response_harm = "kicks"
attacktext = "kicked"
maxHealth = 250//more robust because large
health = 250
autoseek_food = 0
beg_for_food = 0
var/datum/reagents/udder = null
mob_size = 20//based on mass of holstein fresian dairy cattle, what the sprite is based on
@@ -171,6 +176,8 @@
pass_flags = PASSTABLE | PASSGRILLE
small = 1
holder_type = /obj/item/weapon/holder/chick
autoseek_food = 0
beg_for_food = 0
density = 0
mob_size = 0.75//just a rough estimate, the real value should be way lower
@@ -209,7 +216,7 @@ var/global/chicken_count = 0
speak_chance = 2
turns_per_move = 3
meat_type = /obj/item/weapon/reagent_containers/food/snacks/meat
meat_amount = 2
meat_amount = 4
response_help = "pets"
response_disarm = "gently pushes aside"
response_harm = "kicks"
@@ -17,7 +17,7 @@
response_help = "pets"
response_disarm = "gently pushes aside"
response_harm = "kicks"
mob_size = 8
mob_size = 4
//Captain fox
/mob/living/simple_animal/corgi/fox/Chauncey
name = "Chauncey"
@@ -18,6 +18,12 @@
mob_size = 1
holder_type = /obj/item/weapon/holder/lizard
density = 0
seek_speed = 0.75
/mob/living/simple_animal/lizard/New()
..()
nutrition = rand(max_nutrition*0.25, max_nutrition*0.75)
/mob/living/simple_animal/lizard/attack_hand(mob/living/carbon/human/M as mob)
if (src.stat == DEAD)//If the creature is dead, we don't pet it, we just pickup the corpse on click
@@ -31,6 +31,7 @@
response_disarm = "gently pushes aside"
response_harm = "stamps on"
density = 0
meat_amount = 1
var/body_color //brown, gray and white, leave blank for random
layer = MOB_LAYER
min_oxy = 16 //Require atleast 16kPA oxygen
@@ -41,6 +42,9 @@
mob_size = 1
holder_type = /obj/item/weapon/holder/mouse
digest_factor = 0.05
min_scan_interval = 2
max_scan_interval = 20
seek_speed = 1
/mob/living/simple_animal/mouse/Life()
..()
@@ -105,7 +109,9 @@
/mob/living/simple_animal/mouse/speak_audio()
squeak_soft(0)
/mob/living/simple_animal/mouse/beg(var/atom/thing, var/atom/holder)
squeak_soft(0)
visible_emote("squeaks timidly, sniffs the air and gazes longingly up at \the [thing.name].")
/mob/living/simple_animal/mouse/attack_hand(mob/living/carbon/human/M as mob)
if (src.stat == DEAD)//If the mouse is dead, we don't pet it, we just pickup the corpse on click
@@ -132,34 +138,37 @@
//Plays a sound.
//This is triggered when a mob steps on an NPC mouse, or manually by a playermouse
/mob/living/simple_animal/mouse/proc/squeak(var/manual = 1)
playsound(src, 'sound/effects/mousesqueek.ogg', 70, 1)
if (manual)
log_say("[key_name(src)] squeaks! ")
if (stat == CONSCIOUS)
playsound(src, 'sound/effects/mousesqueek.ogg', 70, 1)
if (manual)
log_say("[key_name(src)] squeaks! ")
//Plays a random selection of four sounds, at a low volume
//This is triggered randomly periodically by any mouse, or manually
/mob/living/simple_animal/mouse/proc/squeak_soft(var/manual = 1)
var/list/new_squeaks = last_softsqueak ? soft_squeaks - last_softsqueak : soft_squeaks
var/sound = pick(new_squeaks)
if (stat == CONSCIOUS)
var/list/new_squeaks = last_softsqueak ? soft_squeaks - last_softsqueak : soft_squeaks
var/sound = pick(new_squeaks)
last_softsqueak = sound
playsound(src, sound, 6, 1)
last_softsqueak = sound
playsound(src, sound, 5, 1, -4.6)
if (manual)
log_say("[key_name(src)] squeaks softly! ")
if (manual)
log_say("[key_name(src)] squeaks softly! ")
//Plays a loud sound
//Triggered manually, when a mouse dies, or rarely when its stepped on
/mob/living/simple_animal/mouse/proc/squeak_loud(var/manual = 0)
if (squeals > 0 || !manual)
playsound(src, 'sound/effects/creatures/mouse_squeak_loud.ogg', 50, 1)
squeals --
log_say("[key_name(src)] squeals! ")
else
src << "\red Your hoarse mousey throat can't squeal just now, stop and take a breath!"
if (stat == CONSCIOUS)
if (squeals > 0 || !manual)
playsound(src, 'sound/effects/creatures/mouse_squeak_loud.ogg', 50, 1)
squeals --
log_say("[key_name(src)] squeals! ")
else
src << "\red Your hoarse mousey throat can't squeal just now, stop and take a breath!"
//Wrapper verbs for the squeak functions
@@ -27,6 +27,8 @@
var/stop_automated_movement = 0 //Use this to temporarely stop random movement or to if you write special movement code for animals.
var/wander = 1 // Does the mob wander around when idle?
var/stop_automated_movement_when_pulled = 1 //When set to 1 this stops the animal from moving when someone is pulling it.
var/atom/movement_target = null//Thing we're moving towards
var/turns_since_scan = 0
//Interaction
var/response_help = "tries to help"
@@ -69,20 +71,44 @@
//Hunger/feeding vars
var/hunger_enabled = 1//If set to 0, a creature ignores hunger
var/max_nutrition = 75
var/nutrition_step = 0.2 //nutrition lost per tick and per step, calculated from mob_size, 0.4 is a fallback
var/max_nutrition = 50
var/metabolic_factor = 1//A multiplier on how fast nutrition is lost. used to tweak the rates on a per-animal basis
var/nutrition_step = 0.2 //nutrition lost per tick and per step, calculated from mob_size, 0.2 is a fallback
var/bite_factor = 0.4
var/digest_factor = 0.2 //A multiplier on how quickly reagents are digested
var/stomach_size_mult = 5
//Food behaviour vars
var/autoseek_food = 1//If 0. this animal will not automatically eat
var/beg_for_food = 1//If 0, this animal will not show interest in food held by a person
var/min_scan_interval = 1//Minimum and maximum number of procs between a foodscan. Animals will slow down if there's no food around for a while
var/max_scan_interval = 15
var/scan_interval = 5//current scan interval, clamped between min and max
//It gradually increases up to max when its left alone, to save performance
//It will drop back to 1 if it spies any food.
//This short time makes animals more responsive to interactions and more fun to play with
var/seek_speed = 2//How many tiles per second the animal will move towards food
var/seek_move_delay
var/scan_range = 6//How far around the animal will look for food
var/foodtarget = 0
//Used to control how often ian scans for nearby food
/mob/living/simple_animal/proc/beg(var/atom/thing, var/atom/holder)
visible_emote("gazes longingly at [holder]'s [thing]")
/mob/living/simple_animal/New()
..()
seek_move_delay = (1 / seek_speed) / (world.tick_lag / 10)//number of ticks between moves
turns_since_scan = rand(min_scan_interval, max_scan_interval)//Randomise this at the start so animals don't sync up
verbs -= /mob/verb/observe
health = maxHealth
if (mob_size)
nutrition_step = mob_size * 0.05
nutrition_step = mob_size * 0.03 * metabolic_factor
bite_factor = mob_size * 0.3
max_nutrition *= 1 + (nutrition_step*3)//Max nutrition scales faster than costs, so bigger creatures eat less often
max_nutrition *= 1 + (nutrition_step*4)//Max nutrition scales faster than costs, so bigger creatures eat less often
reagents = new/datum/reagents(stomach_size_mult*mob_size, src)
else
reagents = new/datum/reagents(20, src)
@@ -94,6 +120,11 @@
if(src.nutrition && src.stat != DEAD && hunger_enabled)
src.nutrition -= nutrition_step
/mob/living/simple_animal/Released()
//These will cause mobs to immediately do things when released.
scan_interval = min_scan_interval
turns_since_move = turns_per_move
..()
/mob/living/simple_animal/Login()
if(src && src.client)
@@ -115,6 +146,8 @@
..()
//Health
if(stat == DEAD)
return 0
if(health <= 0)
@@ -130,10 +163,13 @@
update_canmove()
handle_supernatural()
process_food()
handle_foodscanning()
//Movement
turns_since_move++
if(!client && !stop_automated_movement && wander && !anchored)
if(isturf(src.loc) && !resting && !buckled && canmove) //This is so it only moves if it's not inside a closet, gentics machine, etc.
turns_since_move++
if(turns_since_move >= turns_per_move)
if(!(stop_automated_movement_when_pulled && pulledby)) //Soma animals don't move when pulled
/var/moving_to = 0 // otherwise it always picks 4, fuck if I know. Did I mention fuck BYOND
@@ -410,6 +446,8 @@
death()
/mob/living/simple_animal/death(gibbed, deathmessage = "dies!")
walk_to(src,0)
movement_target = null
icon_state = icon_dead
density = 0
return ..(gibbed,deathmessage)
@@ -488,6 +526,81 @@
gib()
//Code to handle finding and nomming nearby food items
/mob/living/simple_animal/proc/handle_foodscanning()
if (client || !hunger_enabled || !autoseek_food)
return 0
//Feeding, chasing food, FOOOOODDDD
if(!stat && !resting && !buckled)
turns_since_scan++
if(turns_since_scan >= scan_interval)
turns_since_scan = 0
if((movement_target) && (!(isturf(movement_target.loc) || ishuman(movement_target.loc))) || (foodtarget && !can_eat() ))
movement_target = null
foodtarget = 0
stop_automated_movement = 0
if( !movement_target || !(movement_target.loc in oview(src, 7)) )
walk_to(src,0)
movement_target = null
foodtarget = 0
stop_automated_movement = 0
if (can_eat())
for(var/obj/item/weapon/reagent_containers/food/snacks/S in oview(src,7))
if(isturf(S.loc) || ishuman(S.loc))
movement_target = S
foodtarget = 1
break
//Look for food in people's hand
if (!movement_target && beg_for_food)
var/obj/item/weapon/reagent_containers/food/snacks/F = null
for(var/mob/living/carbon/human/H in oview(src,scan_range))
if(istype(H.l_hand, /obj/item/weapon/reagent_containers/food/snacks))
F = H.l_hand
if(istype(H.r_hand, /obj/item/weapon/reagent_containers/food/snacks))
F = H.r_hand
if (F)
movement_target = F
foodtarget = 1
break
if(movement_target)
scan_interval = min_scan_interval
stop_automated_movement = 1
if (istype(movement_target.loc, /turf))
walk_to(src,movement_target,0, seek_move_delay)//Stand ontop of food
else
walk_to(src,movement_target.loc,1, seek_move_delay)//Don't stand ontop of people
if(movement_target) //Not redundant due to sleeps, Item can be gone in 6 decisecomds
if (movement_target.loc.x < src.x)
set_dir(WEST)
else if (movement_target.loc.x > src.x)
set_dir(EAST)
else if (movement_target.loc.y < src.y)
set_dir(SOUTH)
else if (movement_target.loc.y > src.y)
set_dir(NORTH)
else
set_dir(SOUTH)
if(isturf(movement_target.loc) && Adjacent(get_turf(movement_target), src))
UnarmedAttack(movement_target)
if (get_turf(movement_target) == src.loc)
set_dir(pick(1,2,4,8,1,1))//Face a random direction when eating, but mostly upwards
else if(ishuman(movement_target.loc) && Adjacent(src, get_turf(movement_target)) && prob(15))
beg(movement_target, movement_target.loc)
else
scan_interval = max(min_scan_interval, min(scan_interval+1, max_scan_interval))//If nothing is happening, ian's scanning frequency slows down to save processing
//For picking up small animals
/mob/living/simple_animal/MouseDrop(atom/over_object)
if (holder_type)//we need a defined holder type in order for picking up to work
+5
View File
@@ -1065,6 +1065,11 @@ mob/proc/yank_out_object()
return 0
/mob/proc/Released()
//This is called when the mob is let out of a holder
//Override for mob-specific functionality
return
/mob/proc/updateicon()
return
+52
View File
@@ -1127,4 +1127,56 @@ var/list/wierd_mobs_inclusive = list( /mob/living/simple_animal/construct,
else return null
#define POSESSIVE_PRONOUN 0
#define POSESSIVE_ADJECTIVE 1
#define REFLEXIVE 2
#define SUBJECTIVE_PERSONAL 3
#define OBJECTIVE_PERSONAL 4
/mob/proc/get_pronoun(var/type)
switch (type)
if (POSESSIVE_PRONOUN)
switch(gender)
if (MALE)
return "his"
if (FEMALE)
return "hers"
else
return "theirs"
if (POSESSIVE_ADJECTIVE)
switch(gender)
if (MALE)
return "his"
if (FEMALE)
return "her"
else
return "their"
if (REFLEXIVE)
switch(gender)
if (MALE)
return "himself"
if (FEMALE)
return "herself"
else
return "themselves"
if (SUBJECTIVE_PERSONAL)
switch(gender)
if (MALE)
return "he"
if (FEMALE)
return "she"
else
return "they"
if (OBJECTIVE_PERSONAL)
switch(gender)
if (MALE)
return "him"
if (FEMALE)
return "her"
else
return "them"
else
return "its"//Something went wrong
#undef SAFE_PERP
+1 -1
View File
@@ -11,7 +11,7 @@ var/list/sent_faxes = list() //cache for faxes that have been sent by the admins
icon_state = "fax"
insert_anim = "faxsend"
req_one_access = list(access_lawyer, access_heads, access_armory) //Warden needs to be able to Fax solgov too.
density = 0//It's a small machine that sits on a table, this allows small things to walk under that table
use_power = 1
idle_power_usage = 30
active_power_usage = 200
@@ -63,6 +63,7 @@
icon_state = "soda_dispenser"
ui_title = "Soda Dispenser"
accept_drinking = 1
density = 0//It's a half-height machine that sits on a table, this allows small things to walk under that table
/obj/machinery/chemical_dispenser/bar_soft/full
spawn_cartridges = list(
@@ -91,6 +92,7 @@
icon_state = "booze_dispenser"
ui_title = "Booze Dispenser"
accept_drinking = 1
density = 0//It's a half-height machine that sits on a table, this allows small things to walk under that table
/obj/machinery/chemical_dispenser/bar_alc/full
spawn_cartridges = list(
@@ -110,6 +110,8 @@
else if (isanimal(M))
var/mob/living/simple_animal/SA = M
SA.scan_interval = SA.min_scan_interval//Feeding an animal will make it suddenly care about food
var/m_bitesize = bitesize * SA.bite_factor//Modified bitesize based on creature size
var/amount_eaten = m_bitesize
@@ -127,8 +129,12 @@
bitecount++
if (amount_eaten >= m_bitesize)
user.visible_message("<span class='notice'>[user] feeds [M] [src].</span>")
if (!istype(M.loc, /turf))//held mobs don't see visible messages
M << "<span class='notice'>[user] feeds you [src].</span>"
else
user.visible_message("<span class='notice'>[user] feeds [M] a tiny bit of [src]. <b>It looks full.</b></span>")
if (!istype(M.loc, /turf))
M << "<span class='notice'>[user] feeds you a tiny bit of [src]. <b>You feel pretty full!</b></span>"
On_Consume(M)
return 1
else