diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index 9febca663d..4cc269cefe 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -530,3 +530,10 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S #define SCAVENGING_SPAWN_MOUSE "spawn_mouse" #define SCAVENGING_SPAWN_MICE "spawn_mice" #define SCAVENGING_SPAWN_TOM "spawn_tom_the_mouse" + +//Scavenging element defines for ckey/mind restrictions. +#define NO_LOOT_RESTRICTION 0 +#define LOOT_RESTRICTION_MIND 1 +#define LOOT_RESTRICTION_CKEY 2 +#define LOOT_RESTRICTION_MIND_PILE 3 //limited to the current pile. +#define LOOT_RESTRICTION_CKEY_PILE 4 //Idem diff --git a/code/datums/elements/scavenging.dm b/code/datums/elements/scavenging.dm index c34fd8f430..1993005be7 100644 --- a/code/datums/elements/scavenging.dm +++ b/code/datums/elements/scavenging.dm @@ -16,13 +16,17 @@ var/can_use_hands = TRUE //bare handed scavenge time multiplier. If set to zero, only tools are usable. var/list/tool_types //which tool types the player can use instead of scavenging by hand, associated value is their speed. var/del_atom_on_depletion = FALSE //Will the atom be deleted when there is no loot left? - var/list/search_texts = list("searches through ", "search through ", "You hear rummaging...") + var/list/search_texts = list("starts searching through", "start searching through", "You hear rummaging...") + var/loot_restriction = NO_LOOT_RESTRICTION + var/maximum_loot_per_player = 1 //only relevant if there is a restriction. + var/list/scavenger_restriction_list //used for restrictions. var/mean_loot_weight = 0 var/list/progress_per_atom = list() //seconds of ditched progress per atom, used to resume the work instead of starting over. var/static/list/players_busy_scavenging = list() //players already busy scavenging. -/datum/element/scavenging/Attach(atom/target, amount = 5, list/loot, list/unique, time = 10 SECONDS, hands = TRUE, list/tools, list/texts, del_deplete = FALSE) +/datum/element/scavenging/Attach(atom/target, amount = 5, list/loot, list/unique, time = 12 SECONDS, hands = TRUE, list/tools, list/texts, \ + del_deplete = FALSE, restriction = NO_LOOT_RESTRICTION, max_per_player = 1) . = ..() if(. == ELEMENT_INCOMPATIBLE || !length(loot) || !amount || !istype(target) || isarea(target)) return ELEMENT_INCOMPATIBLE @@ -40,6 +44,8 @@ if(texts) search_texts = texts del_atom_on_depletion = del_deplete + loot_restriction = restriction + maximum_loot_per_player = max_per_player if(can_use_hands) RegisterSignal(target, list(COMSIG_ATOM_ATTACK_HAND, COMSIG_ATOM_ATTACK_PAW), .proc/scavenge_barehanded) if(tool_types) @@ -50,25 +56,25 @@ . = ..() loot_left_per_atom -= target progress_per_atom -= target + if(maximum_loot_per_player == LOOT_RESTRICTION_MIND_PILE || maximum_loot_per_player == LOOT_RESTRICTION_CKEY_PILE) + maximum_loot_per_player -= target UnregisterSignal(target, list(COMSIG_ATOM_ATTACK_HAND, COMSIG_PARENT_ATTACKBY, COMSIG_PARENT_EXAMINE)) /datum/element/scavenging/proc/on_examine(atom/source, mob/user, list/examine_list) - var/text - var/methods = tool_types + var/methods = tool_types.Copy() if(can_use_hands) - if(!length(methods)) - methods = list("bare handed") - else - methods += "simply bare handed" - text = english_list(methods, "", " or ") - . += "Looks like [source.p_they()] can be scavenged[length(tool_types) ? " with either a" : ""] [text]" + methods += list("bare handed") + if(!length(methods)) + return + var/text = english_list(methods, "", " or ") + examine_list += "Looks like [source.p_they()] can be scavenged [length(tool_types) ? "with" : ""][length(methods == 1) ? "" : "either "][length(tool_types) ? "a " : ""][text]" /datum/element/scavenging/proc/scavenge_barehanded(atom/source, mob/user) scavenge(source, user, 1) return COMPONENT_NO_ATTACK_HAND /datum/element/scavenging/proc/scavenge_tool(atom/source, obj/item/I, mob/user, params) - if(user.a_intent == INTENT_HARM) //Robust trash disposal techniques! + if(user.a_intent == INTENT_HARM || !I.tool_behaviour) //Robust trash disposal techniques! return var/speed_multi = tool_types[I.tool_behaviour] if(!speed_multi) @@ -76,7 +82,10 @@ scavenge(source, user, speed_multi) return COMPONENT_NO_AFTERATTACK +/// This proc has to be asynced (cough cough, do_after) in order to return the comsig values in time to stop the attack chain. /datum/element/scavenging/proc/scavenge(atom/source, mob/user, speed_multi = 1) + set waitfor = FALSE + if(players_busy_scavenging[user]) return players_busy_scavenging[user] = TRUE @@ -84,37 +93,58 @@ var/len_messages = length(search_texts) var/msg_first_person if(len_messages >= 2) - msg_first_person = "You [progress_done ? "resume a ditched task and " : ""][search_texts[2]] [src]." + msg_first_person = "You [progress_done ? ", resume a ditched task and " : ""][search_texts[2]] [source]." var/msg_blind if(len_messages >= 3) msg_blind = "[search_texts[3]]" - user.visible_message("[user] [search_texts[1]] [src].", msg_first_person, msg_blind) - if(do_after(user, scavenge_time, TRUE, source, TRUE, CALLBACK(src, .proc/set_progress, source, world.time), resume_time = progress_done)) + user.visible_message("[user] [search_texts[1]] [source].", msg_first_person, msg_blind) + if(do_after(user, scavenge_time * speed_multi, TRUE, source, TRUE, CALLBACK(src, .proc/set_progress, source, world.time), resume_time = progress_done * speed_multi)) spawn_loot(source, user) players_busy_scavenging -= user - progress_per_atom -= source /datum/element/scavenging/proc/set_progress(atom/source, start_time) progress_per_atom[source] = world.time - start_time + return TRUE /datum/element/scavenging/proc/spawn_loot(atom/source, mob/user) + progress_per_atom -= source + var/loot = pickweight(loot_table) var/special = TRUE var/free = FALSE if(!loot_left_per_atom[source]) - to_chat(user, "Looks likes there is nothing worth of interest left in [src] anymore, further attempts would be futile.") + to_chat(user, "Looks likes there is nothing worth of interest left in [source], what a shame...") return + + var/num_times = 0 + switch(loot_restriction) + if(LOOT_RESTRICTION_MIND) + num_times = LAZYACCESS(scavenger_restriction_list, user.mind) + if(LOOT_RESTRICTION_CKEY) + num_times = LAZYACCESS(scavenger_restriction_list, user.ckey) + if(LOOT_RESTRICTION_MIND_PILE) + var/list/L = LAZYACCESS(scavenger_restriction_list, source) + if(L) + num_times = LAZYACCESS(L, user.mind) + if(LOOT_RESTRICTION_CKEY_PILE) + var/list/L = LAZYACCESS(scavenger_restriction_list, source) + if(L) + num_times = LAZYACCESS(L, user.ckey) + if(num_times >= maximum_loot_per_player) + to_chat(user, "You can't find anything else vaguely useful in [source]. Another set of eyes might, however.") + return + switch(loot) // TODO: datumize these out. if(SCAVENGING_FOUND_NOTHING) to_chat(user, "You found nothing, better luck next time.") free = TRUE //doesn't consume the loot pile. if(SCAVENGING_SPAWN_MOUSE) var/nasty_rodent = pick("mouse", "rodent", "squeaky critter", "stupid pest", "annoying cable chewer", "nasty, ugly, evil, disease-ridden rodent") - to_chat(user, "You found something in [src]... no wait, that's just another [nasty_rodent].") + to_chat(user, "You found something in [source]... no wait, that's just another [nasty_rodent].") new /mob/living/simple_animal/mouse(source.loc) if(SCAVENGING_SPAWN_MICE) user.visible_message("A small gang of mice emerges from [source].", \ - "You found something in [src]... no wait, that's just another- no wait, that's a lot of damn mice.") + "You found something in [source]... no wait, that's just another- no wait, that's a lot of damn mice.") for(var/i in 1 to rand(4, 6)) new /mob/living/simple_animal/mouse(source.loc) if(SCAVENGING_SPAWN_TOM) @@ -122,7 +152,7 @@ to_chat(user, "You found nothing, better luck next time.") free = TRUE else - to_chat(user, "You found something in [src]... no wait, that's Tom, the mouse! What is he doing here?") + to_chat(user, "You found something in [source]... no wait, that's Tom, the mouse! What is he doing here?") new /mob/living/simple_animal/mouse/brown/Tom(source.loc) else special = FALSE @@ -145,7 +175,7 @@ rarity_append = ". Nice." if(20 to 50) rarity_append = ". Not bad." - to_chat(user, "You found something in [src]... it's \a [A][rarity_append]") + to_chat(user, "You found something in [source]... it's \a [A][rarity_append]") if(unique_loot[loot]) var/loot_left = --unique_loot[loot] @@ -157,8 +187,29 @@ mean_loot_weight += loot_table[A] mean_loot_weight /= length(loot_table) - if(!free) - --loot_left_per_atom[source] - if(del_atom_on_depletion && !loot_left_per_atom[source]) - source.visible_message("[src] has been looted clean.") - qdel(source) + if(free) + return + + --loot_left_per_atom[source] + if(del_atom_on_depletion && !loot_left_per_atom[source]) + source.visible_message("[source] has been looted clean.") + qdel(source) + return + + if(!loot_restriction) + return + + LAZYINITLIST(scavenger_restriction_list) + switch(loot_restriction) + if(LOOT_RESTRICTION_MIND) + scavenger_restriction_list[user.mind]++ + if(LOOT_RESTRICTION_CKEY) + scavenger_restriction_list[user.ckey]++ + if(LOOT_RESTRICTION_MIND_PILE) + LAZYINITLIST(scavenger_restriction_list[source]) + var/list/L = scavenger_restriction_list[source] + L[user.mind]++ + if(LOOT_RESTRICTION_CKEY_PILE) + LAZYINITLIST(scavenger_restriction_list[source]) + var/list/L = scavenger_restriction_list[source] + L[user.ckey]++ diff --git a/code/game/objects/structures/loot_pile.dm b/code/game/objects/structures/loot_pile.dm index 0886c1c8b7..bbcfacd9c1 100644 --- a/code/game/objects/structures/loot_pile.dm +++ b/code/game/objects/structures/loot_pile.dm @@ -6,6 +6,7 @@ name = "pile of junk" desc = "Lots of junk lying around. They say one man's trash is another man's treasure." icon = 'icons/obj/loot_piles.dmi' + icon_state = "randompile" density = FALSE anchored = TRUE var/loot_amount = 5 @@ -14,43 +15,20 @@ var/scavenge_time = 12 SECONDS var/allowed_tools = list(TOOL_SHOVEL = 0.6) //list of tool_behaviours with associated speed multipliers (lower is better) var/icon_states_to_use = list("junk_pile1", "junk_pile2", "junk_pile3", "junk_pile4", "junk_pile5") - var/list/loot = list( - SCAVENGING_FOUND_NOTHING = 50, - SCAVENGING_SPAWN_MOUSE = 10, - SCAVENGING_SPAWN_MICE = 5, - SCAVENGING_SPAWN_TOM = 1, - /obj/item/flashlight/flare = 10, - /obj/item/flashlight/glowstick = 10, - /obj/item/flashlight/glowstick/blue = 10, - /obj/item/flashlight/glowstick/orange = 10, - /obj/item/flashlight/glowstick/red = 10, - /obj/item/flashlight/glowstick/yellow = 10, - /obj/item/clothing/mask/gas = 5, - /obj/item/clothing/mask/breath = 10, - /obj/item/storage/box = 10, - /obj/item/clothing/shoes/galoshes = 2, - /obj/item/clothing/shoes/sneakers/black = 10, - /obj/item/clothing/gloves/color/fyellow = 5, - /obj/item/clothing/gloves/color/yellow = 2, - /obj/item/clothing/glasses/sunglasses = 3, - /obj/item/clothing/glasses/meson = 3, - /obj/item/clothing/glasses/welding = 3, - /obj/item/clothing/head/hardhat = 10, - /obj/item/clothing/head/ushanka = 10, - /obj/item/clothing/head/welding = 5, - /obj/item/clothing/suit/hazardvest = 10, - /obj/item/clothing/under/syndicate/tacticool = 5, - /obj/item/clothing/under/pants/camo = 10, - /obj/item/stack/spacecash/c10 = 20, - /obj/item/stack/spacecash/c20 = 20, - /obj/item/stack/spacecash/c50 = 20, - /obj/item/radio/headset = 10) + var/list/loot /* * Associated values in this list are not weights but numbers of times the kery can be rolled * before being removed from ALL piles with same kind. This is why I wanted 'scavenging' to be an element and not a component. */ - var/list/unique_loot = list(/obj/item/clothing/gloves/color/yellow = 2, SCAVENGING_SPAWN_TOM = 1) + var/list/unique_loot + + /* + * used for restrictions such as "one per mind", "one per ckey". Depending on the setting, these can be either limited to + * the current pile or shared throughout all atoms attached to this element. + */ + var/loot_restriction = NO_LOOT_RESTRICTION + var/maximum_loot_per_player = 1 /obj/structure/loot_pile/Initialize() . = ..() @@ -58,9 +36,31 @@ /obj/structure/loot_pile/ComponentInitialize() . = ..() - AddElement(/datum/element/scavenging, loot_amount, loot, unique_loot, scavenge_time, can_use_hands, allowed_tools, null, delete_on_depletion) + if(loot) + AddElement(/datum/element/scavenging, loot_amount, loot, unique_loot, scavenge_time, can_use_hands, allowed_tools, null, delete_on_depletion, loot_restriction, maximum_loot_per_player) -/obj/structure/loot_pile/infinite - name = "endless pile of junk." - desc = "Lots of awful code lying around. They don't say one coder's trash is another coder's treasure though..." - loot_amount = INFINITY +//uses the maintenance_loot global list, mostly boring stuff and mices. +/obj/structure/loot_pile/maint + name = "trash pile" + desc = "A heap of garbage, but maybe there's something interesting inside?" + density = TRUE + layer = TABLE_LAYER + climbable = TRUE + pass_flags = LETPASSTHROW + loot = list( + SCAVENGING_FOUND_NOTHING = 50, + SCAVENGING_SPAWN_MOUSE = 10, + SCAVENGING_SPAWN_MICE = 5, + SCAVENGING_SPAWN_TOM = 1, + /obj/item/clothing/gloves/color/yellow = 0.5) + unique_loot = list(/obj/item/clothing/gloves/color/yellow = 5, SCAVENGING_SPAWN_TOM = 1) + +/obj/structure/loot_pile/maint/ComponentInitialize() + var/static/safe_maint_items + if(!safe_maint_items) + safe_maint_items = list() + for(var/A in GLOB.maintenance_loot) + if(ispath(A, /obj/item)) + safe_maint_items[A] = GLOB.maintenance_loot[A] + loot += safe_maint_items + return ..()