From 9d58b77e18a765bdd560aa87b3a180053eb7e149 Mon Sep 17 00:00:00 2001 From: NanakoAC Date: Fri, 12 Aug 2016 21:00:27 +0100 Subject: [PATCH] Fixes #721, fixes #710, fixes #706 (#731) --- code/modules/mob/holder.dm | 100 +++++++++++++----- .../simple_animal/constructs/constructs.dm | 2 +- .../living/simple_animal/friendly/mouse.dm | 76 +++++++++---- .../living/simple_animal/hostile/hostile.dm | 2 +- .../mob/living/simple_animal/simple_animal.dm | 53 +++++----- code/modules/mob/mob_helpers.dm | 3 + html/changelogs/Nanako-HungerMouseFix.yml | 40 +++++++ icons/mob/mouse.dmi | Bin 0 -> 2938 bytes 8 files changed, 205 insertions(+), 71 deletions(-) create mode 100644 html/changelogs/Nanako-HungerMouseFix.yml create mode 100644 icons/mob/mouse.dmi diff --git a/code/modules/mob/holder.dm b/code/modules/mob/holder.dm index fcc27fcb8d2..94c20f97016 100644 --- a/code/modules/mob/holder.dm +++ b/code/modules/mob/holder.dm @@ -12,6 +12,9 @@ var/name_dead var/isalive + 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 @@ -30,18 +33,18 @@ return - 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() + 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) + 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 @@ -61,6 +64,33 @@ for(var/mob/M in src.contents) M.attackby(W,user) +/obj/item/weapon/holder/dropped(mob/user) + + ///When an object is put into a container, drop fires twice. + //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)) + return + + if (istype(loc, /obj/item/weapon/storage)) //The second drop reads the container its placed into as the location + update_location() + + +/obj/item/weapon/holder/equipped(var/mob/user, var/slot) + ..() + update_location(slot) + +/obj/item/weapon/holder/proc/update_location(var/slotnumber = null) + if (!slotnumber) + if (istype(loc, /mob)) + slotnumber = get_equip_slot() + + report_onmob_location(1, slotnumber, contained) + + + + + /obj/item/weapon/holder/attack_self(mob/M as mob) if (contained && !(contained.stat & DEAD)) @@ -115,26 +145,47 @@ grabber << "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 - var/obj/item/weapon/holder/H = new holder_type(loc) - src.forceMove(H) - H.name = loc.name - H.attack_hand(grabber) - H.contained = src - if (src.stat == DEAD) - H.held_death()//We've scooped up an animal that's already dead. use the proper dead icons - else - H.isalive = 1//We note that the mob is alive when picked up. If it dies later, we can know that its death happened while held, and play its deathmessage for it + spawn(2) + var/obj/item/weapon/holder/H = new holder_type(loc) + H.name = loc.name + src.forceMove(H) - if (user == src) - grabber << "[src.name] climbs up onto you." - src << "You climb up onto [grabber]." - else - grabber << "You scoop up [src]." - src << "[grabber] scoops you up." - grabber.status_flags |= PASSEMOTES - return + + H.contained = src + + + + if (src.stat == DEAD) + H.held_death()//We've scooped up an animal that's already dead. use the proper dead icons + else + H.isalive = 1//We note that the mob is alive when picked up. If it dies later, we can know that its death happened while held, and play its deathmessage for it + + if (user == src) + grabber << "[src.name] climbs up onto you." + src << "You climb up onto [grabber]." + else + grabber << "You scoop up [src]." + src << "[grabber] scoops you up." + grabber.status_flags |= PASSEMOTES + H.attack_hand(grabber)//We put this last to prevent some race conditions + return + + +/mob/living/proc/get_holder_location() + set category = "Abilities" + set name = "Check held location" + set desc = "Find out where on their person, someone is holding you." + + if (!usr.get_holding_mob()) + src << "Nobody is holding you!" + return + + if (istype(usr.loc, /obj/item/weapon/holder)) + var/obj/item/weapon/holder/H = usr.loc + H.report_onmob_location(0, H.get_equip_slot(), src) //Mob specific holders. //w_class mainly determines whether they can fit in trashbags. <=2 can, >=3 cannot @@ -231,7 +282,6 @@ origin_tech = "biotech=2" w_class = 1 - /obj/item/weapon/holder/mouse/white icon_state = "mouse_white" icon_state_dead = "mouse_white_dead" diff --git a/code/modules/mob/living/simple_animal/constructs/constructs.dm b/code/modules/mob/living/simple_animal/constructs/constructs.dm index e79b7dea738..50eea50f0d3 100644 --- a/code/modules/mob/living/simple_animal/constructs/constructs.dm +++ b/code/modules/mob/living/simple_animal/constructs/constructs.dm @@ -32,7 +32,7 @@ mob_swap_flags = HUMAN|SIMPLE_ANIMAL|SLIME|MONKEY mob_push_flags = ALLMOBS - + hunger_enabled = 0 var/list/construct_spells = list() /mob/living/simple_animal/construct/cultify() diff --git a/code/modules/mob/living/simple_animal/friendly/mouse.dm b/code/modules/mob/living/simple_animal/friendly/mouse.dm index 7d45fabbaf5..5f4cd032eca 100644 --- a/code/modules/mob/living/simple_animal/friendly/mouse.dm +++ b/code/modules/mob/living/simple_animal/friendly/mouse.dm @@ -2,6 +2,7 @@ name = "mouse" real_name = "mouse" desc = "It's a small rodent." + icon = 'icons/mob/mouse.dmi' icon_state = "mouse_gray" icon_living = "mouse_gray" icon_dead = "mouse_gray_dead" @@ -14,6 +15,9 @@ 'sound/effects/creatures/mouse_squeaks_3.ogg', 'sound/effects/creatures/mouse_squeaks_4.ogg') var/last_softsqueak = null//Used to prevent the same soft squeak twice in a row + var/squeals = 5//Spam control. You people are why we cant have nice things >:( + var/maxSqueals = 5//SPAM PROTECTION + var/last_squealgain = 0// #TODO-FUTURE: Remove from life() once something else is created pass_flags = PASSTABLE small = 1 @@ -40,10 +44,19 @@ /mob/living/simple_animal/mouse/Life() ..() - //Player-animals don't do random speech normally, so this is here + + if(client) + //Player-animals don't do random speech normally, so this is here //Player-controlled mice will still squeak, but less often than NPC mice - if(client && stat == CONSCIOUS && prob(speak_chance*0.4)) - squeak_soft() + if (stat == CONSCIOUS && prob(speak_chance*0.1)) + squeak_soft(0) + + if (squeals < maxSqueals) + var/diff = world.time - last_squealgain + if (diff > 600) + world << "+1 squeak" + squeals++ + last_squealgain = world.time if(!ckey && stat == CONSCIOUS && prob(0.5)) stat = UNCONSCIOUS @@ -60,9 +73,12 @@ else if(prob(5)) audible_emote("snuffles.") + + /mob/living/simple_animal/mouse/New() ..() + nutrition = rand(max_nutrition*0.25, max_nutrition*0.75) verbs += /mob/living/proc/ventcrawl verbs += /mob/living/proc/hide @@ -83,12 +99,12 @@ if (body_color == "white") holder_type = /obj/item/weapon/holder/mouse/white - verbs += /mob/living/simple_animal/mouse/proc/squeak - verbs += /mob/living/simple_animal/mouse/proc/squeak_soft - verbs += /mob/living/simple_animal/mouse/proc/squeak_loud + //verbs += /mob/living/simple_animal/mouse/proc/squeak + //verbs += /mob/living/simple_animal/mouse/proc/squeak_soft + //verbs += /mob/living/simple_animal/mouse/proc/squeak_loud(1) /mob/living/simple_animal/mouse/speak_audio() - squeak_soft() + squeak_soft(0) @@ -116,34 +132,54 @@ //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() - set name = "Squeak" - set category = "Abilities" +/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! ") //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() - set name = "Soft Squeaking" - set category = "Abilities" - +/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) last_softsqueak = sound playsound(src, sound, 6, 1) + 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() +/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!" + + +//Wrapper verbs for the squeak functions +/mob/living/simple_animal/mouse/verb/squeak_loud_verb() set name = "Squeal!" set category = "Abilities" - playsound(src, 'sound/effects/creatures/mouse_squeak_loud.ogg', 50, 1) + squeak_loud(1) + +/mob/living/simple_animal/mouse/verb/squeak_soft_verb() + set name = "Soft Squeaking" + set category = "Abilities" + squeak_soft(1) + +/mob/living/simple_animal/mouse/verb/squeak_verb() + set name = "Squeak" + set category = "Abilities" + squeak(1) + /mob/living/simple_animal/mouse/Crossed(AM as mob|obj) if( ishuman(AM) ) @@ -151,15 +187,15 @@ var/mob/M = AM M << "\blue \icon[src] Squeek!" if (prob(95)) - squeak() + squeak(0) else - squeak_loud()//You trod on its tail + squeak_loud(0)//You trod on its tail ..() /mob/living/simple_animal/mouse/death() layer = MOB_LAYER if (ckey || prob(50)) - squeak_loud()//deathgasp + squeak_loud(0)//deathgasp if(client) client.time_died_as_mouse = world.time diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm index 2016ebd155b..4931e5d1eae 100644 --- a/code/modules/mob/living/simple_animal/hostile/hostile.dm +++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm @@ -13,7 +13,7 @@ var/break_stuff_probability = 10 stop_automated_movement_when_pulled = 0 var/destroy_surroundings = 1 - + hunger_enabled = 0//Until automated eating mechanics are enabled, disable hunger for hostile mobs var/shuttletarget = null var/enroute = 0 diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 162577ae187..1642a1cf60d 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -66,6 +66,9 @@ var/supernatural = 0 var/purge = 0 + + //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/bite_factor = 0.4 @@ -87,7 +90,7 @@ /mob/living/simple_animal/Move(NewLoc, direct) . = ..() if(.) - if(src.nutrition && src.stat != DEAD) + if(src.nutrition && src.stat != DEAD && hunger_enabled) src.nutrition -= nutrition_step @@ -101,12 +104,14 @@ /mob/living/simple_animal/examine(mob/user) ..() - if (!nutrition) - user << "It looks starving!" - else if (nutrition < max_nutrition *0.5) - user << "It looks hungry." - else if ((reagents.total_volume > 0 && nutrition > max_nutrition *0.75) || nutrition > max_nutrition *0.9) - user << "It looks full and contented." + + if (hunger_enabled) + if (!nutrition) + user << "It looks starving!" + else if (nutrition < max_nutrition *0.5) + user << "It looks hungry." + else if ((reagents.total_volume > 0 && nutrition > max_nutrition *0.75) || nutrition > max_nutrition *0.9) + user << "It looks full and contented." /mob/living/simple_animal/Life() ..() @@ -247,28 +252,28 @@ //This allows animals to digest food, and only food //Most drugs, poisons etc, are designed to work on carbons and affect many values a simple animal doesnt have /mob/living/simple_animal/proc/process_food() - - if (nutrition) - nutrition -= nutrition_step//Bigger animals get hungry faster - nutrition = max(0,min(nutrition, max_nutrition))//clamp the value - else - if (prob(3)) - src << "You feel hungry..." + if (hunger_enabled) + if (nutrition) + nutrition -= nutrition_step//Bigger animals get hungry faster + nutrition = max(0,min(nutrition, max_nutrition))//clamp the value + else + if (prob(3)) + src << "You feel hungry..." - if (!reagents || !reagents.total_volume) - return + if (!reagents || !reagents.total_volume) + return - for(var/datum/reagent/current in reagents.reagent_list) - var/removed = min(current.metabolism*digest_factor, current.volume) - if (istype(current, /datum/reagent/nutriment))//If its food, it feeds us - var/datum/reagent/nutriment/N = current - nutrition += removed*N.nutriment_factor - health = min(health+(removed*N.regen_factor), maxHealth) - current.remove_self(removed)//If its not food, it just does nothing. no fancy effects + for(var/datum/reagent/current in reagents.reagent_list) + var/removed = min(current.metabolism*digest_factor, current.volume) + if (istype(current, /datum/reagent/nutriment))//If its food, it feeds us + var/datum/reagent/nutriment/N = current + nutrition += removed*N.nutriment_factor + health = min(health+(removed*N.regen_factor), maxHealth) + current.remove_self(removed)//If its not food, it just does nothing. no fancy effects /mob/living/simple_animal/proc/can_eat() - if (nutrition > max_nutrition * 0.9) + if (!hunger_enabled || nutrition > max_nutrition * 0.9) return 0//full else if ((nutrition > max_nutrition * 0.8) || health < maxHealth) diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 0bd3306a938..53e6c5114f3 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -931,6 +931,9 @@ proc/is_blind(A) var/atom/a = src while (x < 5) x++ + if (isnull(a)) + return null + a = a.loc if (istype(a, /turf)) return null//We must be on a table or a floor, or maybe in a wall. Either way we're not held. diff --git a/html/changelogs/Nanako-HungerMouseFix.yml b/html/changelogs/Nanako-HungerMouseFix.yml new file mode 100644 index 00000000000..d522090f540 --- /dev/null +++ b/html/changelogs/Nanako-HungerMouseFix.yml @@ -0,0 +1,40 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# wip (For works in progress) +# tweak +# soundadd +# sounddel +# rscadd (general adding of nice things) +# rscdel (general deleting of nice things) +# imageadd +# imagedel +# maptweak +# spellcheck (typo fixes) +# experiment +################################# + +# Your name. +author: Nanako + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. +# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. +changes: + - bugfix: "Fixed Check Held Location verb for held mobs not being there." + - tweak: "Mouse starting nutrition randomised a little." + - bugfix: "Fixed hungry constructs." + - tweak: "Nerfed mice." + \ No newline at end of file diff --git a/icons/mob/mouse.dmi b/icons/mob/mouse.dmi new file mode 100644 index 0000000000000000000000000000000000000000..ec4ff5c0d5036ef38b449b34b814f7b5c58d48f1 GIT binary patch literal 2938 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