diff --git a/code/_onclick/cyborg.dm b/code/_onclick/cyborg.dm index 59860116889..ea6a0086c4f 100644 --- a/code/_onclick/cyborg.dm +++ b/code/_onclick/cyborg.dm @@ -124,7 +124,15 @@ A.BorgCtrlClick(src) /mob/living/silicon/robot/AltClickOn(var/atom/A) - A.BorgAltClick(src) + var/doClickAction = 1 + if (istype(module_active, /obj/item/weapon)) + var/obj/item/weapon/W = module_active + doClickAction = W.alt_attack(A,src) + + if (doClickAction) + A.BorgAltClick(src) + + /atom/proc/BorgCtrlShiftClick(var/mob/living/silicon/robot/user) //forward to human click if not overriden CtrlShiftClick(user) diff --git a/code/game/objects/items/weapons/storage/storage.dm b/code/game/objects/items/weapons/storage/storage.dm index 9f5fe9ea7c7..292e1726af0 100644 --- a/code/game/objects/items/weapons/storage/storage.dm +++ b/code/game/objects/items/weapons/storage/storage.dm @@ -346,16 +346,10 @@ if(istype(W, /obj/item/weapon/tray)) var/obj/item/weapon/tray/T = W - if(T.calc_carry() > 0) - if(prob(85)) - user << "\red The tray won't fit in [src]." - return - else - W.loc = user.loc - if ((user.client && user.s_active != src)) - user.client.screen -= W - W.dropped(user) - user << "\red God damnit!" + if(T.current_weight > 0) + T.spill(user) + user << "\red Trying to place a loaded tray into [src] was a bad idea." + return W.add_fingerprint(user) return handle_item_insertion(W) diff --git a/code/game/objects/items/weapons/trays.dm b/code/game/objects/items/weapons/trays.dm index c52961eda5a..6a3b720e336 100644 --- a/code/game/objects/items/weapons/trays.dm +++ b/code/game/objects/items/weapons/trays.dm @@ -1,6 +1,10 @@ /* - * Trays - Agouri + * Trays - Nanako */ + //Use tray on an item to load it, alt+click on anything to attempt to load all the stuff on the tile + //To unload, place on a table, then rightclic > Unload tray. Alternatively, alt+click on the tray to unload it + //Tray will spill if thrown, dropped on the floor, or used to hit someone with. Spilling scatters contents + /obj/item/weapon/tray name = "tray" icon = 'icons/obj/food.dmi' @@ -14,26 +18,29 @@ flags = CONDUCT matter = list(DEFAULT_WALL_MATERIAL = 3000) var/list/carrying = list() // List of things on the tray. - Doohl - var/max_carry = 10 + var/max_carry = 20 + var/current_weight = 0 + + var/safedrop = 0//Used to tell when we should or shouldn't spill if the tray is dropped. + //Safedrop is set true when throwing, because it will spill on impact. And when placing on a table + var/list/valid = list( /obj/item/weapon/reagent_containers, + /obj/item/weapon/material/kitchen/utensil, + /obj/item/weapon/storage/fancy/cigarettes, + /obj/item/clothing/mask/smokable, + /obj/item/weapon/storage/box/matches, + /obj/item/weapon/flame/match, + /obj/item/weapon/material/ashtray) /obj/item/weapon/tray/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob) // Drop all the things. All of them. - overlays.Cut() - for(var/obj/item/I in carrying) - I.loc = M.loc - carrying.Remove(I) - if(isturf(I.loc)) - spawn() - for(var/i = 1, i <= rand(1,2), i++) - if(I) - step(I, pick(NORTH,SOUTH,EAST,WEST)) - sleep(rand(2,4)) + spill(user, M.loc) + //Note: Added a robot check to all stun/weaken procs, beccause weakening a robot causes its active modules to bug out if((CLUMSY in user.mutations) && prob(50)) //What if he's a clown? M << "\red You accidentally slam yourself with the [src]!" - M.Weaken(1) + if(!istype(M,/mob/living/silicon))M.Weaken(1) user.take_organ_damage(2) if(prob(50)) playsound(M, 'sound/items/trayhit1.ogg', 50, 1) @@ -46,7 +53,7 @@ if(!(user.zone_sel.selecting == ("eyes" || "head"))) //////////////hitting anything else other than the eyes - if(prob(33)) + if(prob(33) && !istype(M,/mob/living/silicon))//robots dont bleed src.add_blood(H) var/turf/location = H.loc if (istype(location, /turf/simulated)) @@ -57,7 +64,7 @@ msg_admin_attack("[user.name] ([user.ckey]) used the [src.name] to attack [M.name] ([M.ckey]) (JMP)") if(prob(15)) - M.Weaken(3) + if(!istype(M,/mob/living/silicon)) M.Weaken(3) M.take_organ_damage(3) else M.take_organ_damage(5) @@ -75,7 +82,7 @@ if(istype(M, /mob/living/carbon/human) && ((H.head && H.head.flags & HEADCOVERSEYES) || (H.wear_mask && H.wear_mask.flags & MASKCOVERSEYES) || (H.glasses && H.glasses.flags & GLASSESCOVERSEYES))) M << "\red You get slammed in the face with the tray, against your mask!" - if(prob(33)) + if(prob(33) && !istype(M,/mob/living/silicon)) src.add_blood(H) if (H.wear_mask) H.wear_mask.add_blood(H) @@ -96,14 +103,14 @@ for(var/mob/O in viewers(M, null)) O.show_message(text("\red [] slams [] with the tray!", user, M), 1) if(prob(10)) - M.Stun(rand(1,3)) + if(!istype(M,/mob/living/silicon))M.Stun(rand(1,3)) M.take_organ_damage(3) return else M.take_organ_damage(5) return - else //No eye or head protection, tough luck! + else if (!istype(M,/mob/living/silicon))//No eye or head protection, tough luck! M << "\red You get slammed in the face with the tray!" if(prob(33)) src.add_blood(M) @@ -133,76 +140,179 @@ /obj/item/weapon/tray/var/cooldown = 0 //shield bash cooldown. based on world.time /obj/item/weapon/tray/attackby(obj/item/weapon/W as obj, mob/user as mob) + if (istype(user,/mob/living/silicon/robot))//safety to stop robots losing their items + return + + if (istype(W, /obj/item/weapon/tray))//safety to prevent tray stacking + return + if(istype(W, /obj/item/weapon/material/kitchen/rollingpin)) if(cooldown < world.time - 25) user.visible_message("[user] bashes [src] with [W]!") playsound(user.loc, 'sound/effects/shieldbash.ogg', 50, 1) cooldown = world.time + else - ..() + var/obj/item/I = W + attempt_load_item(I, user) + //..() /* -===============~~~~~================================~~~~~==================== -= = -= Code for trays carrying things. By Doohl for Doohl erryday Doohl Doohl~ = -= = -===============~~~~~================================~~~~~==================== +============~~~~~==============~~~~~============= += = += Code for trays carrying things. By Nanako. += = +============~~~~~============~~~~~=============== */ -/obj/item/weapon/tray/proc/calc_carry() - // calculate the weight of the items on the tray - var/val = 0 // value to return - for(var/obj/item/I in carrying) - if(I.w_class == 1.0) - val ++ - else if(I.w_class == 2.0) - val += 3 +//Clicking an item individually loads it. clicking a table places the tray on it safely +/obj/item/weapon/tray/afterattack(atom/target, mob/user as mob, proximity) + if (proximity) + if (istype(target, /obj/item)) + var/obj/item/I = target + attempt_load_item(I,user,1) + + if (istype(target,/obj/structure/table)) + safedrop = 1 + + +//Alt+click with the tray in hand attempts to grab everything on the tile +/obj/item/weapon/tray/alt_attack(var/atom/A, var/mob/user) + var/dist + var/tile + if (istype(A,/turf)) + dist = get_dist(A,user.loc) + tile = A + else + dist = get_dist(A.loc,user.loc) + tile = A.loc + + if (dist == 1)//checking that we're adjacent + var/addedSomething = 0 + for(var/obj/item/I in tile) + if (attempt_load_item(I, usr,0)) + addedSomething++ + if ( addedSomething == 1) + usr.visible_message("\blue [user] loads an item onto their service tray.") + else if ( addedSomething ) + usr.visible_message("\blue [user] loads [addedSomething] items onto their service tray.") else - val += 5 + user << "The tray is full or there's nothing valid here" + return 1 + return 0//This prevents the alt-click from doing any farther actions + return 1 - return val +/obj/item/weapon/tray/AltClick(var/mob/user) + unload(user) -/obj/item/weapon/tray/pickup(mob/user) - if(!isturf(loc)) +/obj/item/weapon/tray/proc/attempt_load_item(var/obj/item/I, var/mob/user, var/messages = 1) + if( I != src && !I.anchored && !istype(I, /obj/item/projectile) ) + var/match = 0 + for (var/T in valid) + if (istype(I,T)) + match = 1 + var/remaining = max_carry - current_weight + if (remaining >= I.w_class) + load_item(I,user) + if (messages)user << "You place [I] on the tray" + return 1 + else + if (messages) + user << "The tray can't take that much weight" + if (!match && messages)user << "That item isn't suitable for a tray" + return 0 + + +/obj/item/weapon/tray/proc/load_item(var/obj/item/I, var/mob/user) + user.remove_from_mob(I) + I.loc = src + current_weight += I.w_class + carrying.Add(I) + overlays += image("icon" = I.icon, "icon_state" = I.icon_state, "layer" = 30 + I.layer, "pixel_x" = I.pixel_x, "pixel_y" = I.pixel_y) + //rand(0, (max_offset_y*2)-3)-(max_offset_y)-3 + +/obj/item/weapon/tray/verb/unload() + set name = "Unload Tray" + set category = "Object" + set src in view(1) + + if (!istype(loc,/turf))//check that we're not being held by a mob + usr << "Place the tray down first!" return + else + var/turf/dropspot = loc - for(var/obj/item/I in loc) - if( I != src && !I.anchored && !istype(I, /obj/item/clothing/under) && !istype(I, /obj/item/clothing/suit) && !istype(I, /obj/item/projectile) ) - var/add = 0 - if(I.w_class == 1.0) - add = 1 - else if(I.w_class == 2.0) - add = 3 + for(var/obj/item/I in carrying) + I.loc = dropspot + carrying.Remove(I) + overlays.Cut() + current_weight = 0 + usr.visible_message("[usr] unloads the tray.", "You unload the tray.") + +/obj/item/weapon/tray/proc/unload_at_loc(var/turf/dropspot = null, var/mob/user) + if (!istype(loc,/turf) && !dropspot)//check that we're not being held by a mob + usr << "Place the tray down first!" + return + else + if (!dropspot) + dropspot = loc + + for(var/obj/item/I in carrying) + I.loc = dropspot + carrying.Remove(I) + overlays.Cut() + current_weight = 0 + usr.visible_message("[usr] unloads the tray.", "You unload the tray.") + + +/obj/item/weapon/tray/proc/spill(var/mob/user = null, var/turf/dropspot = null) + //This proc is called when a tray is thrown or dropped on the floor + //its also called when a cyborg uses its tray on the floor + if (current_weight > 0)//can't spill a tray with nothing on it + + overlays.Cut() + + //First we have to find where the items are being dropped, unless a location has been passed in + if (!dropspot) + if (istype(src.loc, /mob))//If the tray is still held by a mob + dropspot = src.loc.loc else - add = 5 - if(calc_carry() + add >= max_carry) - break + dropspot = src.loc - I.loc = src - carrying.Add(I) - overlays += image("icon" = I.icon, "icon_state" = I.icon_state, "layer" = 30 + I.layer) -/obj/item/weapon/tray/dropped(mob/user) - - var/mob/living/M - for(M in src.loc) //to handle hand switching - return - - var/foundtable = 0 - for(var/obj/structure/table/T in loc) - foundtable = 1 - break - - overlays.Cut() - - for(var/obj/item/I in carrying) - I.loc = loc - carrying.Remove(I) - if(!foundtable && isturf(loc)) - // if no table, presume that the person just shittily dropped the tray on the ground and made a mess everywhere! + for(var/obj/item/I in carrying) + I.loc = dropspot + carrying.Remove(I) spawn() for(var/i = 1, i <= rand(1,2), i++) if(I) step(I, pick(NORTH,SOUTH,EAST,WEST)) sleep(rand(2,4)) + if (user) + user.visible_message("\blue [user] spills their tray all over the floor.") + else + src.visible_message("\blue The tray scatters its contents all over the area.") + current_weight = 0 + if(prob(50)) + playsound(dropspot, 'sound/items/trayhit1.ogg', 50, 1) + else + playsound(dropspot, 'sound/items/trayhit2.ogg', 50, 1) + +/obj/item/weapon/tray/throw_impact(atom/hit_atom) + spill(null, src.loc) + +/obj/item/weapon/tray/throw_at(/var/atom/target, var/throw_range, var/throw_speed, /var/mob/user) + safedrop = 1//we dont want the tray to spill when thrown, it will spill on impact instead + ..() + +/obj/item/weapon/tray/dropped(mob/user) + spawn(1)//A hack to avoid race conditions. Dropped procs too quickly + if (istype(src.loc, /mob)) + //If this is true, then the tray has just switched hands and is still held by a mob + return + + if (!safedrop) + spill(user, src.loc) + + safedrop = 0 \ No newline at end of file diff --git a/code/game/objects/weapons.dm b/code/game/objects/weapons.dm index b62efa1c049..b04c81d7940 100644 --- a/code/game/objects/weapons.dm +++ b/code/game/objects/weapons.dm @@ -6,4 +6,11 @@ /obj/item/weapon/Bump(mob/M as mob) spawn(0) ..() - return \ No newline at end of file + return + +//Called when the user alt-clicks on something with this item in their active hand +//this function is designed to be overridden by individual weapons +/obj/item/weapon/proc/alt_attack(var/atom/target, var/mob/user) + return 1 + //A return value of 1 continues on to do the normal alt-click action. + //A return value of 0 does not continue, and will not do the alt-click \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index c7b2da7ec3c..d51b2233746 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1444,3 +1444,13 @@ return 0 return 1 + +/mob/living/carbon/human/AltClickOn(var/atom/A) + var/doClickAction = 1 + if (istype(get_active_hand(), /obj/item/weapon)) + var/obj/item/weapon/W = get_active_hand() + doClickAction = W.alt_attack(A,src) + + if (doClickAction) + ..() + diff --git a/code/modules/mob/living/silicon/robot/robot_items.dm b/code/modules/mob/living/silicon/robot/robot_items.dm index 9346dbe5d4c..fbfd6261893 100644 --- a/code/modules/mob/living/silicon/robot/robot_items.dm +++ b/code/modules/mob/living/silicon/robot/robot_items.dm @@ -139,54 +139,14 @@ user << "Harvesting \a [target] is not the purpose of this tool. The [src] is for plants being grown." // A special tray for the service droid. Allow droid to pick up and drop items as if they were using the tray normally -// Click on table to unload, click on item to load. Otherwise works identically to a tray. -// Unlike the base item "tray", robotrays ONLY pick up food, drinks and condiments. +// Click on table to unload, click on item to load. Alt+click to load everything on tile /obj/item/weapon/tray/robotray name = "RoboTray" desc = "An autoloading tray specialized for carrying refreshments." /obj/item/weapon/tray/robotray/afterattack(atom/target, mob/user as mob, proximity) - if(!proximity) - return - if ( !target ) - return - // pick up items, mostly copied from base tray pickup proc - // see code\game\objects\items\weapons\kitchen.dm line 241 - if ( istype(target,/obj/item)) - if ( !isturf(target.loc) ) // Don't load up stuff if it's inside a container or mob! - return - var turf/pickup = target.loc - - var addedSomething = 0 - - for(var/obj/item/weapon/reagent_containers/food/I in pickup) - - - if( I != src && !I.anchored && !istype(I, /obj/item/clothing/under) && !istype(I, /obj/item/clothing/suit) && !istype(I, /obj/item/projectile) ) - var/add = 0 - if(I.w_class == 1.0) - add = 1 - else if(I.w_class == 2.0) - add = 3 - else - add = 5 - if(calc_carry() + add >= max_carry) - break - - I.loc = src - carrying.Add(I) - overlays += image("icon" = I.icon, "icon_state" = I.icon_state, "layer" = 30 + I.layer) - addedSomething = 1 - if ( addedSomething ) - user.visible_message("\blue [user] load some items onto their service tray.") - - return - - // Unloads the tray, copied from base item's proc dropped() and altered - // see code\game\objects\items\weapons\kitchen.dm line 263 - - if ( isturf(target) || istype(target,/obj/structure/table) ) + if (isturf(target) || istype(target,/obj/structure/table) ) var foundtable = istype(target,/obj/structure/table/) if ( !foundtable ) //it must be a turf! for(var/obj/structure/table/T in target) @@ -201,27 +161,12 @@ else // they clicked on a table dropspot = target.loc + if (foundtable) + unload_at_loc(dropspot, src) + else + spill(user,dropspot) - overlays = null - - var droppedSomething = 0 - - for(var/obj/item/I in carrying) - I.loc = dropspot - carrying.Remove(I) - droppedSomething = 1 - if(!foundtable && isturf(dropspot)) - // if no table, presume that the person just shittily dropped the tray on the ground and made a mess everywhere! - spawn() - for(var/i = 1, i <= rand(1,2), i++) - if(I) - step(I, pick(NORTH,SOUTH,EAST,WEST)) - sleep(rand(2,4)) - if ( droppedSomething ) - if ( foundtable ) - user.visible_message("\blue [user] unloads their service tray.") - else - user.visible_message("\blue [user] drops all the items on their tray.") + current_weight = 0 return ..() diff --git a/html/changelogs/Nanako-PR-394.yml b/html/changelogs/Nanako-PR-394.yml new file mode 100644 index 00000000000..21b3b11523f --- /dev/null +++ b/html/changelogs/Nanako-PR-394.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: + - rscadd: "Fixed trays. Trays can now be unloaded by placing them down on a table, then either alt+clicking themn, or rightclicking and selecting Unload Tray" + - rscadd: "Trays can now load individual items by using it on them, or using the item on the tray, or alt+click to attempt to load everything on the tile" + - rscadd: "Trays will now spill their contents when dropped, thrown, or when you try to place it into a container" + - tweak: "Trays now only hold specific things: Food/drinks, reagent containers, utensils, and smoking supplies" + - tweak: "Tray capacity increased" \ No newline at end of file