mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-26 06:22:26 +01:00
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:
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user