From e9bf432a0df148be149157b5af65f65becb92495 Mon Sep 17 00:00:00 2001
From: Ghommie <42542238+Ghommie@users.noreply.github.com>
Date: Wed, 22 Apr 2020 03:30:40 +0200
Subject: [PATCH 01/14] Scavenging element.
---
code/__DEFINES/dcs/signals.dm | 2 +-
code/__DEFINES/misc.dm | 7 +
code/__HELPERS/_lists.dm | 26 +--
code/__HELPERS/mobs.dm | 12 +-
code/controllers/subsystem/vote.dm | 2 +-
code/datums/ai_laws.dm | 2 +-
code/datums/components/archaeology.dm | 95 ----------
code/datums/elements/scavenging.dm | 164 ++++++++++++++++++
code/game/gamemodes/game_mode.dm | 2 +-
code/game/objects/effects/landmarks.dm | 2 +-
code/game/objects/structures/loot_pile.dm | 66 +++++++
.../antagonists/traitor/datum_traitor.dm | 2 +-
.../living/simple_animal/friendly/mouse.dm | 6 +
icons/obj/loot_piles.dmi | Bin 0 -> 12091 bytes
tgstation.dme | 2 +
15 files changed, 261 insertions(+), 129 deletions(-)
delete mode 100644 code/datums/components/archaeology.dm
create mode 100644 code/datums/elements/scavenging.dm
create mode 100644 code/game/objects/structures/loot_pile.dm
create mode 100644 icons/obj/loot_piles.dmi
diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm
index 53348b3467..a09c96ad30 100644
--- a/code/__DEFINES/dcs/signals.dm
+++ b/code/__DEFINES/dcs/signals.dm
@@ -30,7 +30,7 @@
#define COMSIG_PARENT_ATTACKBY "atom_attackby" //from base of atom/attackby(): (/obj/item, /mob/living, params)
#define COMPONENT_NO_AFTERATTACK 1 //Return this in response if you don't want afterattack to be called
#define COMSIG_ATOM_HULK_ATTACK "hulk_attack" //from base of atom/attack_hulk(): (/mob/living/carbon/human)
-#define COMSIG_PARENT_EXAMINE "atom_examine" //from base of atom/examine(): (/mob)
+#define COMSIG_PARENT_EXAMINE "atom_examine" //from base of atom/examine(): (/mob, list/examine_list)
#define COMSIG_ATOM_GET_EXAMINE_NAME "atom_examine_name" //from base of atom/get_examine_name(): (/mob, list/overrides)
//Positions for overrides list
#define EXAMINE_POSITION_ARTICLE 1
diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index 3fb149d071..9febca663d 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -523,3 +523,10 @@ GLOBAL_LIST_INIT(pda_reskins, list(PDA_SKIN_CLASSIC = 'icons/obj/pda.dmi', PDA_S
#define NIGHTSHIFT_AREA_NONE 4 //default/highest.
#define UNTIL(X) while(!(X)) stoplag()
+
+
+//Scavenging element defines for special loot "events".
+#define SCAVENGING_FOUND_NOTHING "found_nothing"
+#define SCAVENGING_SPAWN_MOUSE "spawn_mouse"
+#define SCAVENGING_SPAWN_MICE "spawn_mice"
+#define SCAVENGING_SPAWN_TOM "spawn_tom_the_mouse"
diff --git a/code/__HELPERS/_lists.dm b/code/__HELPERS/_lists.dm
index a34b3ce67c..754b56a202 100644
--- a/code/__HELPERS/_lists.dm
+++ b/code/__HELPERS/_lists.dm
@@ -234,38 +234,20 @@
//2. Gets a number between 1 and that total
//3. For each element in the list, subtracts its weighting from that number
//4. If that makes the number 0 or less, return that element.
-/proc/pickweight(list/L)
+/proc/pickweight(list/L, base_weight = 1)
var/total = 0
var/item
for (item in L)
if (!L[item])
- L[item] = 1
+ L[item] = base_weight
total += L[item]
- total = rand(1, total)
+ total = rand() * total
for (item in L)
- total -=L [item]
+ total -= L[item]
if (total <= 0)
return item
- return null
-
-/proc/pickweightAllowZero(list/L) //The original pickweight proc will sometimes pick entries with zero weight. I'm not sure if changing the original will break anything, so I left it be.
- var/total = 0
- var/item
- for (item in L)
- if (!L[item])
- L[item] = 0
- total += L[item]
-
- total = rand(0, total)
- for (item in L)
- total -=L [item]
- if (total <= 0 && L[item])
- return item
-
- return null
-
//Pick a random element from the list and remove it from the list.
/proc/pick_n_take(list/L)
RETURN_TYPE(L[_].type)
diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm
index 2827e40120..d3ad4dcaec 100644
--- a/code/__HELPERS/mobs.dm
+++ b/code/__HELPERS/mobs.dm
@@ -311,7 +311,7 @@ GLOBAL_LIST_EMPTY(species_list)
else
return "unknown"
-/proc/do_mob(mob/user , mob/target, time = 30, uninterruptible = 0, progress = 1, datum/callback/extra_checks = null, ignorehelditem = 0)
+/proc/do_mob(mob/user , mob/target, time = 30, uninterruptible = 0, progress = 1, datum/callback/extra_checks = null, ignorehelditem = FALSE, resume_time = 0 SECONDS)
if(!user || !target)
return 0
var/user_loc = user.loc
@@ -330,10 +330,10 @@ GLOBAL_LIST_EMPTY(species_list)
var/endtime = world.time+time
var/starttime = world.time
. = 1
- while (world.time < endtime)
+ while (world.time + resume_time < endtime)
stoplag(1)
if (progress)
- progbar.update(world.time - starttime)
+ progbar.update(world.time - starttime + resume_time)
if(QDELETED(user) || QDELETED(target))
. = 0
break
@@ -365,7 +365,7 @@ GLOBAL_LIST_EMPTY(species_list)
checked_health["health"] = health
return ..()
-/proc/do_after(mob/user, var/delay, needhand = 1, atom/target = null, progress = 1, datum/callback/extra_checks = null, required_mobility_flags = (MOBILITY_USE|MOBILITY_MOVE))
+/proc/do_after(mob/user, var/delay, needhand = 1, atom/target = null, progress = 1, datum/callback/extra_checks = null, required_mobility_flags = (MOBILITY_USE|MOBILITY_MOVE), resume_time = 0 SECONDS)
if(!user)
return 0
var/atom/Tloc = null
@@ -394,10 +394,10 @@ GLOBAL_LIST_EMPTY(species_list)
var/starttime = world.time
. = 1
var/mob/living/L = isliving(user) && user //evals to last thing eval'd
- while (world.time < endtime)
+ while (world.time + resume_time < endtime)
stoplag(1)
if (progress)
- progbar.update(world.time - starttime)
+ progbar.update(world.time - starttime + resume_time)
if(drifting && !user.inertia_dir)
drifting = 0
diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm
index a202afd905..df3f24f0dc 100644
--- a/code/controllers/subsystem/vote.dm
+++ b/code/controllers/subsystem/vote.dm
@@ -361,7 +361,7 @@ SUBSYSTEM_DEF(vote)
picked = S
runnable_storytellers[S] *= round(stored_gamemode_votes[initial(S.name)]*100000,1)
if(!picked)
- picked = pickweightAllowZero(runnable_storytellers)
+ picked = pickweight(runnable_storytellers, 0)
GLOB.dynamic_storyteller_type = picked
if("map")
var/datum/map_config/VM = config.maplist[.]
diff --git a/code/datums/ai_laws.dm b/code/datums/ai_laws.dm
index ebddc187ae..9c6bb2ebfd 100644
--- a/code/datums/ai_laws.dm
+++ b/code/datums/ai_laws.dm
@@ -253,7 +253,7 @@
var/datum/ai_laws/lawtype
var/list/law_weights = CONFIG_GET(keyed_list/law_weight)
while(!lawtype && law_weights.len)
- var/possible_id = pickweightAllowZero(law_weights)
+ var/possible_id = pickweight(law_weights, 0)
lawtype = lawid_to_type(possible_id)
if(!lawtype)
law_weights -= possible_id
diff --git a/code/datums/components/archaeology.dm b/code/datums/components/archaeology.dm
deleted file mode 100644
index b5740650e9..0000000000
--- a/code/datums/components/archaeology.dm
+++ /dev/null
@@ -1,95 +0,0 @@
-/datum/component/archaeology
- dupe_mode = COMPONENT_DUPE_UNIQUE
- var/list/archdrops = list(/obj/item/bikehorn = list(ARCH_PROB = 100, ARCH_MAXDROP = 1)) // honk~
- var/prob2drop
- var/dug
- var/datum/callback/callback
-
-/datum/component/archaeology/Initialize(list/_archdrops = list(), datum/callback/_callback)
- archdrops = _archdrops
- for(var/i in archdrops)
- if(isnull(archdrops[i][ARCH_MAXDROP]))
- archdrops[i][ARCH_MAXDROP] = 1
- stack_trace("ARCHAEOLOGY WARNING: [parent] contained a null max_drop value in [i].")
- if(isnull(archdrops[i][ARCH_PROB]))
- archdrops[i][ARCH_PROB] = 100
- stack_trace("ARCHAEOLOGY WARNING: [parent] contained a null probability value in [i].")
- callback = _callback
- RegisterSignal(parent, COMSIG_PARENT_ATTACKBY,.proc/Dig)
- RegisterSignal(parent, COMSIG_ATOM_EX_ACT, .proc/BombDig)
- RegisterSignal(parent, COMSIG_ATOM_SING_PULL, .proc/SingDig)
-
-/datum/component/archaeology/InheritComponent(datum/component/archaeology/A, i_am_original)
- var/list/other_archdrops = A.archdrops
- var/list/_archdrops = archdrops
- for(var/I in other_archdrops)
- _archdrops[I] += other_archdrops[I]
-
-/datum/component/archaeology/proc/Dig(datum/source, obj/item/I, mob/living/user)
- if(dug)
- to_chat(user, "Looks like someone has dug here already.")
- return
-
- if(!isturf(user.loc))
- return
-
- if(I.tool_behaviour == TOOL_SHOVEL || I.tool_behaviour == TOOL_MINING)
- to_chat(user, "You start digging...")
-
- if(I.use_tool(parent, user, 40, volume=50))
- to_chat(user, "You dig a hole.")
- gets_dug()
- dug = TRUE
- SSblackbox.record_feedback("tally", "pick_used_mining", 1, I.type)
- return COMPONENT_NO_AFTERATTACK
-
-/datum/component/archaeology/proc/gets_dug()
- if(dug)
- return
- else
- var/turf/open/OT = get_turf(parent)
- for(var/thing in archdrops)
- var/maxtodrop = archdrops[thing][ARCH_MAXDROP]
- for(var/i in 1 to maxtodrop)
- if(prob(archdrops[thing][ARCH_PROB])) // can't win them all!
- new thing(OT)
-
- if(isopenturf(OT))
- if(OT.postdig_icon_change)
- if(istype(OT, /turf/open/floor/plating/asteroid/) && !OT.postdig_icon)
- var/turf/open/floor/plating/asteroid/AOT = parent
- AOT.icon_plating = "[AOT.environment_type]_dug"
- AOT.icon_state = "[AOT.environment_type]_dug"
- else
- if(isplatingturf(OT))
- var/turf/open/floor/plating/POT = parent
- POT.icon_plating = "[POT.postdig_icon]"
- POT.icon_state = "[OT.postdig_icon]"
-
- if(OT.slowdown) //Things like snow slow you down until you dig them.
- OT.slowdown = 0
- dug = TRUE
- if(callback)
- callback.Invoke()
-
-/datum/component/archaeology/proc/SingDig(datum/source, S, current_size)
- switch(current_size)
- if(STAGE_THREE)
- if(prob(30))
- gets_dug()
- if(STAGE_FOUR)
- if(prob(50))
- gets_dug()
- else
- if(current_size >= STAGE_FIVE && prob(70))
- gets_dug()
-
-/datum/component/archaeology/proc/BombDig(datum/source, severity, target)
- switch(severity)
- if(3)
- return
- if(2)
- if(prob(20))
- gets_dug()
- if(1)
- gets_dug()
diff --git a/code/datums/elements/scavenging.dm b/code/datums/elements/scavenging.dm
new file mode 100644
index 0000000000..b2ca7adcc3
--- /dev/null
+++ b/code/datums/elements/scavenging.dm
@@ -0,0 +1,164 @@
+ /*
+ * Scavenging element. Its scope shouldn't elude your imagination.
+ * Basically loot piles that can be searched through for some items.
+ * In my opinion, these are more engaging than normal maintenance loot spawners.
+ * The loot doesn't have to be strictly made of items and objects, you could also use it to invoke some "events"
+ * such as mice, rats, an halloween spook, persistent relics, traps, etcetera, go wild.
+ */
+/datum/element/scavenging
+ element_flags = ELEMENT_BESPOKE|ELEMENT_DETACH
+ id_arg_index = 3
+
+ var/list/loot_left_per_atom = list() //loot left per attached atom.
+ var/list/loot_table //pickweight list of available loot.
+ var/list/unique_loot //limited loot, once the associated value reaches zero, its key is removed from loot_table
+ var/scavenge_time = 12 SECONDS //how much time it takes
+ 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/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)
+ . = ..()
+ if(. == ELEMENT_INCOMPATIBLE || !length(loot) || !amount || !istype(target) || isarea(target))
+ return ELEMENT_INCOMPATIBLE
+ loot_left_per_atom[target] = amount
+ if(!loot_table)
+ loot_table = loot
+ for(var/A in loot_table) //tally the list weights
+ mean_loot_weight += loot_table[A]
+ mean_loot_weight /= length(loot_table)
+ if(!unique_loot)
+ unique_loot = unique || list()
+ scavenge_time = time
+ can_use_hands = hands
+ tool_types = tools
+ if(texts)
+ search_texts = texts
+ del_atom_on_depletion = del_deplete
+ if(can_use_hands)
+ RegisterSignal(target, list(COMSIG_ATOM_ATTACK_HAND, COMSIG_ATOM_ATTACK_PAW), .proc/scavenge_barehanded)
+ if(tool_types)
+ RegisterSignal(target, COMSIG_PARENT_ATTACKBY, .proc/scavenge_tool)
+ RegisterSignal(target, COMSIG_PARENT_EXAMINE, .proc/on_examine)
+
+/datum/element/scavenging/Detach(atom/target)
+ . = ..()
+ loot_left_per_atom -= target
+ progress_per_atom -= 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
+ 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]"
+
+/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/living/user, params)
+ if(mob.a_intent == INTENT_HARM) //Robust trash disposal techniques!
+ return
+ var/speed_multi = tool_types[I.tool_behaviour]
+ if(!speed_multi)
+ return
+ scavenge(source, user, speed_multi)
+ return COMPONENT_NO_AFTERATTACK
+
+/datum/element/scavenging/proc/scavenge(atom/source, mob/user, speed_multi = 1)
+ if(players_busy_scavenging[user])
+ return
+ players_busy_scavenging[user] = TRUE
+ var/progress_done = progress_per_atom[source]
+ 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]."
+ 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))
+ 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
+
+/datum/element/scavenging/proc/spawn_loot(atom/source, mob/user)
+ 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.")
+ 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].")
+ 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.")
+ for(var/i in 1 to rand(4, 6))
+ new /mob/living/simple_animal/mouse(source.loc)
+ if(SCAVENGING_SPAWN_TOM)
+ if(GLOB.tom_existed) //There can only be one.
+ 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?")
+ new /mob/living/simple_animal/mouse/brown/Tom(source.loc)
+ else
+ special = FALSE
+
+ if(!special) //generic loot. Nothing too strange like more loot spawners anyway.
+ var/atom/A = new loot(source.loc)
+ if(isitem(A) && !user.get_active_held_item())
+ user.put_in_hands(A)
+ var/rarity_append = "."
+ switch(loot_table[loot]/mean_loot_weight*100)
+ if(0 to 1)
+ rarity_append = "! AMAZING!"
+ if(1 to 2)
+ rarity_append = "! Woah!"
+ if(2 to 5)
+ rarity_append = ". Rare!"
+ if(5 to 10)
+ rarity_append = ". Great."
+ if(10 to 25)
+ 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]")
+
+ if(unique_loot[loot])
+ var/loot_left = --unique_loot[loot]
+ if(!loot_left)
+ loot_table -= loot
+ unique_loot -= loot
+ mean_loot_weight = 0
+ for(var/A in loot_table) //re-tally the list weights
+ 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)
diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm
index 5affeba6d6..57919863f2 100644
--- a/code/game/gamemodes/game_mode.dm
+++ b/code/game/gamemodes/game_mode.dm
@@ -272,7 +272,7 @@
reports += config.mode_reports[config_tag]
Count++
for(var/i in Count to rand(3,5)) //Between three and five wrong entries on the list.
- var/false_report_type = pickweightAllowZero(report_weights)
+ var/false_report_type = pickweight(report_weights, 0)
report_weights[false_report_type] = 0 //Make it so the same false report won't be selected twice
reports += config.mode_reports[false_report_type]
diff --git a/code/game/objects/effects/landmarks.dm b/code/game/objects/effects/landmarks.dm
index 04f14692e3..851a041aab 100644
--- a/code/game/objects/effects/landmarks.dm
+++ b/code/game/objects/effects/landmarks.dm
@@ -483,7 +483,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark/start/new_player)
if(!SSmapping.station_room_templates[t])
log_world("Station room spawner placed at ([T.x], [T.y], [T.z]) has invalid ruin name of \"[t]\" in its list")
templates -= t
- template_name = pickweightAllowZero(templates)
+ template_name = pickweight(templates, 0)
if(!template_name)
GLOB.stationroom_landmarks -= src
qdel(src)
diff --git a/code/game/objects/structures/loot_pile.dm b/code/game/objects/structures/loot_pile.dm
new file mode 100644
index 0000000000..0886c1c8b7
--- /dev/null
+++ b/code/game/objects/structures/loot_pile.dm
@@ -0,0 +1,66 @@
+ /*
+ * Loot piles structures, somewhat inspired from Polaris 13 ones but without the one search per pile ckey/mind restriction
+ * because the actual code is located its own element and has enough variables already. the piles themselves merely cosmetical.
+ */
+/obj/structure/loot_pile
+ 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'
+ density = FALSE
+ anchored = TRUE
+ var/loot_amount = 5
+ var/delete_on_depletion = FALSE
+ var/can_use_hands = TRUE
+ 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)
+
+ /*
+ * 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)
+
+/obj/structure/loot_pile/Initialize()
+ . = ..()
+ icon_state = pick(icon_states_to_use)
+
+/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)
+
+/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
diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm
index cf10f87bf8..df5e6004ba 100644
--- a/code/modules/antagonists/traitor/datum_traitor.dm
+++ b/code/modules/antagonists/traitor/datum_traitor.dm
@@ -48,7 +48,7 @@
var/datum/traitor_class/class = GLOB.traitor_classes[C]
var/weight = LOGISTIC_FUNCTION(1.5*class.weight,chaos_weight,class.chaos,0)
weights[C] = weight * 1000
- var/choice = pickweightAllowZero(weights)
+ var/choice = pickweight(weights, 0)
if(!choice)
choice = TRAITOR_HUMAN // it's an "easter egg"
var/datum/traitor_class/actual_class = GLOB.traitor_classes[choice]
diff --git a/code/modules/mob/living/simple_animal/friendly/mouse.dm b/code/modules/mob/living/simple_animal/friendly/mouse.dm
index 370442d4c4..7f83bb9f9b 100644
--- a/code/modules/mob/living/simple_animal/friendly/mouse.dm
+++ b/code/modules/mob/living/simple_animal/friendly/mouse.dm
@@ -97,6 +97,8 @@
body_color = "brown"
icon_state = "mouse_brown"
+GLOBAL_VAR(tom_existed)
+
//TOM IS ALIVE! SQUEEEEEEEE~K :)
/mob/living/simple_animal/mouse/brown/Tom
name = "Tom"
@@ -106,6 +108,10 @@
response_harm = "splats"
gold_core_spawnable = NO_SPAWN
+/mob/living/simple_animal/mouse/brown/Tom/Initialize()
+ . = ..()
+ GLOB.tom_existed = TRUE
+
/obj/item/reagent_containers/food/snacks/deadmouse
name = "dead mouse"
desc = "It looks like somebody dropped the bass on it. A lizard's favorite meal."
diff --git a/icons/obj/loot_piles.dmi b/icons/obj/loot_piles.dmi
new file mode 100644
index 0000000000000000000000000000000000000000..3d83d6612ec49b238a0934962192abac1d90d6f9
GIT binary patch
literal 12091
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
B=b!)p
literal 0
HcmV?d00001
diff --git a/tgstation.dme b/tgstation.dme
index 3b3bb74df1..147c91c92e 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -516,6 +516,7 @@
#include "code\datums\elements\ghost_role_eligibility.dm"
#include "code\datums\elements\mob_holder.dm"
#include "code\datums\elements\polychromic.dm"
+#include "code\datums\elements\scavenging.dm"
#include "code\datums\elements\spellcasting.dm"
#include "code\datums\elements\swimming.dm"
#include "code\datums\elements\sword_point.dm"
@@ -1119,6 +1120,7 @@
#include "code\game\objects\structures\lattice.dm"
#include "code\game\objects\structures\life_candle.dm"
#include "code\game\objects\structures\loom.dm"
+#include "code\game\objects\structures\loot_pile.dm"
#include "code\game\objects\structures\manned_turret.dm"
#include "code\game\objects\structures\memorial.dm"
#include "code\game\objects\structures\mineral_doors.dm"
From 122067c5f4e0fe81a722c68b961df7a0a3d1eac1 Mon Sep 17 00:00:00 2001
From: Ghommie <42542238+Ghommie@users.noreply.github.com>
Date: Wed, 22 Apr 2020 03:52:45 +0200
Subject: [PATCH 02/14] wip
---
code/datums/elements/scavenging.dm | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/code/datums/elements/scavenging.dm b/code/datums/elements/scavenging.dm
index b2ca7adcc3..c34fd8f430 100644
--- a/code/datums/elements/scavenging.dm
+++ b/code/datums/elements/scavenging.dm
@@ -67,8 +67,8 @@
scavenge(source, user, 1)
return COMPONENT_NO_ATTACK_HAND
-/datum/element/scavenging/proc/scavenge_tool(atom/source, obj/item/I, mob/living/user, params)
- if(mob.a_intent == INTENT_HARM) //Robust trash disposal techniques!
+/datum/element/scavenging/proc/scavenge_tool(atom/source, obj/item/I, mob/user, params)
+ if(user.a_intent == INTENT_HARM) //Robust trash disposal techniques!
return
var/speed_multi = tool_types[I.tool_behaviour]
if(!speed_multi)
From af3651172c1c4c60e1f8033e35fcd19ad8c08536 Mon Sep 17 00:00:00 2001
From: kevinz000 <2003111+kevinz000@users.noreply.github.com>
Date: Sun, 26 Apr 2020 03:29:31 -0700
Subject: [PATCH 03/14] wow lotsa effort huh
---
code/controllers/subsystem/mapping.dm | 24 +++
.../crafting/recipes/recipes_misc.dm | 9 ++
code/game/objects/items/crayons.dm | 9 +-
.../items/devices/electrochromatic_kit.dm | 15 ++
code/game/objects/structures/window.dm | 141 +++++++++++++++++-
code/modules/assembly/doorcontrol.dm | 47 +++++-
.../autolathe_designs_electronics.dm | 8 +
tgstation.dme | 1 +
8 files changed, 241 insertions(+), 13 deletions(-)
create mode 100644 code/game/objects/items/devices/electrochromatic_kit.dm
diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm
index 89155cefb3..ffda2731b1 100644
--- a/code/controllers/subsystem/mapping.dm
+++ b/code/controllers/subsystem/mapping.dm
@@ -42,6 +42,13 @@ SUBSYSTEM_DEF(mapping)
var/stat_map_name = "Loading..."
+ /// Lookup list for random generated IDs.
+ var/list/random_generated_ids_by_original = list()
+ /// next id for separating obfuscated ids.
+ var/obfuscation_next_id = 1
+ /// "secret" key
+ var/obfuscation_secret
+
//dlete dis once #39770 is resolved
/datum/controller/subsystem/mapping/proc/HACK_LoadMapConfig()
if(!config)
@@ -52,6 +59,10 @@ SUBSYSTEM_DEF(mapping)
#endif
stat_map_name = config.map_name
+/datum/controller/subsystem/mapping/PreInit()
+ if(!obfuscation_secret)
+ obfuscation_secret = md5(GUID()) //HAH! Guess this!
+
/datum/controller/subsystem/mapping/Initialize(timeofday)
HACK_LoadMapConfig()
if(initialized)
@@ -568,3 +579,16 @@ GLOBAL_LIST_EMPTY(the_station_areas)
LM.load()
if(GLOB.stationroom_landmarks.len)
seedStation() //I'm sure we can trust everyone not to insert a 1x1 rooms which loads a landmark which loads a landmark which loads a la...
+
+/**
+ * Generates an obfuscated but constant id for an original id for cases where you don't want players codediving for an id.
+ * WARNING: MAKE SURE PLAYERS ARE NOT ABLE TO ACCESS THIS. To save performance, it's just secret + an incrementing number. Very guessable if you know what the secret is.
+ */
+/datum/controller/subsystem/mapping/proc/get_obfuscated_id(original, id_type = "GENERAL")
+ if(!original)
+ return //no.
+ var/key = "[original]%[id_type]"
+ if(random_generated_ids_by_original[key])
+ return random_generated_ids_by_original[key]
+ random_generated_ids_by_original[key] = "[obfuscation_secret]%[obfuscation_next++]"
+ return value
diff --git a/code/datums/components/crafting/recipes/recipes_misc.dm b/code/datums/components/crafting/recipes/recipes_misc.dm
index cf0e1bdec9..b26755d4ac 100644
--- a/code/datums/components/crafting/recipes/recipes_misc.dm
+++ b/code/datums/components/crafting/recipes/recipes_misc.dm
@@ -233,6 +233,15 @@
subcategory = CAT_TOOL
category = CAT_MISC
+/datum/crafting_recipe/electrochromatic_kit
+ name = "Electrochromatic Kit"
+ result = /obj/item/electronics/electrochromatic_kit
+ reqs = list(/obj/item/stack/metal = 1,
+ /obj/item/stack/cable_coil = 1)
+ time = 5
+ subcategory = CAT_MISCELLANEOUS
+ category = CAT_MISC
+
////////////
//Vehicles//
////////////
diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm
index 3dad3877b7..f60edf2917 100644
--- a/code/game/objects/items/crayons.dm
+++ b/code/game/objects/items/crayons.dm
@@ -726,13 +726,12 @@
to_chat(usr, "A color that dark on an object like this? Surely not...")
return FALSE
- target.add_atom_colour(paint_color, WASHABLE_COLOUR_PRIORITY)
if(istype(target, /obj/structure/window))
- if(color_hex2num(paint_color) < 255)
- target.set_opacity(255)
- else
- target.set_opacity(initial(target.opacity))
+ var/obj/structure/window/W = target
+ W.spraycan_paint(paint_color)
+ else
+ target.add_atom_colour(paint_color, WASHABLE_COLOUR_PRIORITY)
. = use_charges(user, 2)
var/fraction = min(1, . / reagents.maximum_volume)
diff --git a/code/game/objects/items/devices/electrochromatic_kit.dm b/code/game/objects/items/devices/electrochromatic_kit.dm
new file mode 100644
index 0000000000..aae886d397
--- /dev/null
+++ b/code/game/objects/items/devices/electrochromatic_kit.dm
@@ -0,0 +1,15 @@
+/obj/item/electronics/electrochromatic_kit
+ name = "electrochromatic kit"
+ desc = "A kit for upgrading a window into an electrochromatic one."
+ icon = 'icons/obj/device.dmi'
+ /// Electrochromatic ID
+ var/id
+
+/obj/item/electronics/electrochromatic_kit/attack_self(mob/user)
+ . = ..()
+ if(.)
+ return
+ var/new_id = input(user, "Set this kit's electrochromatic ID", "Set ID", id) as text|null
+ if(isnull(new_id))
+ return
+ id = new_id
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index 5dd4e7d987..07fd8142cb 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -1,3 +1,19 @@
+#define NOT_ELECTROCHROMATIC 0
+#define ELECTROCHROMATIC_OFF 1
+#define ELECTROCHROMATIC_DIMMED 2
+
+GLOBAL_LIST_EMPTY(electrochromatic_window_lookup)
+
+/proc/do_electrochromatic_toggle(new_status, id)
+ var/list/windows = GLOB.electrochromatic_window_lookup["[id]"]
+ if(!windows)
+ return
+ var/obj/structure/window/W = i
+ for(var/i in windows)
+ W = i
+ new_status? W.electrochromatic_dim() : W.electrochromatic_off()
+
+
/obj/structure/window
name = "window"
desc = "A window."
@@ -28,8 +44,15 @@
rad_insulation = RAD_VERY_LIGHT_INSULATION
rad_flags = RAD_PROTECT_CONTENTS
+ /// Electrochromatic status
+ var/electrochromatic_status = NOT_ELECTROCHROMATIC
+ /// Electrochromatic ID. Set the first character to ! to replace with a SSmapping generated pseudorandom obfuscated ID for mapping purposes.
+ var/electrochromatic_id
+
/obj/structure/window/examine(mob/user)
. = ..()
+ if(electrochromatic_status != NOT_ELECTROCHROMATIC)
+ . += "The window has electrochromatic circuitry on it.")
if(reinf)
if(anchored && state == WINDOW_SCREWED_TO_FRAME)
. += "The window is screwed to the frame."
@@ -52,6 +75,10 @@
if(reinf && anchored)
state = WINDOW_SCREWED_TO_FRAME
+ if(mapload && electrochromatic_id)
+ if(copytext(electrochromatic_id, 1, 2) == "!")
+ electrochromatic_id = SSmapping.get_obfuscated_id(electrochromatic_id)
+
ini_dir = dir
air_update_turf(1)
@@ -62,6 +89,12 @@
real_explosion_block = explosion_block
explosion_block = EXPLOSION_BLOCK_PROC
+ if(electrochromatic_status != NOT_ELECTROCHROMATIC)
+ var/old = electrochromatic_status
+ make_electrochromatic()
+ if(old == ELECTROCHROMATIC_DIMMED)
+ electrochromatic_dim()
+
/obj/structure/window/ComponentInitialize()
. = ..()
AddComponent(/datum/component/simple_rotation,ROTATION_ALTCLICK | ROTATION_CLOCKWISE | ROTATION_COUNTERCLOCKWISE | ROTATION_VERBS ,null,CALLBACK(src, .proc/can_be_rotated),CALLBACK(src,.proc/after_rotation))
@@ -177,6 +210,24 @@
to_chat(user, "[src] is already in good condition!")
return
+ if(!anchored && istype(I, /obj/item/electronics/electrochromatic_kit && user.a_intent == INTENT_HELP)
+ var/obj/item/electronics/electrochromatic_kit/K = I
+ if(!user.temporarilyRemoveItemFromInventory(K))
+ to_chat(user, "[K] is stuck to your hand!")
+ return
+ if(is_electrochromatic)
+ to_chat(user, "[src] is already electrochromatic!")
+ return
+ if(!anchored)
+ to_chat(user, "[src] must not be attached to the floor!")
+ return
+ if(!K.id)
+ to_chat(user, "[K] has no ID set!")
+ return
+ user.visible_message("[user] upgrades [src] with [I].", "You upgrade [src] with [I].")
+ make_electrochromatic(K.id)
+ qdel(K)
+
if(!(flags_1&NODECONSTRUCT_1))
if(istype(I, /obj/item/screwdriver))
I.play_tool_sound(src, 75)
@@ -224,6 +275,85 @@
air_update_turf(TRUE)
update_nearby_icons()
+/obj/structure/window/proc/spraycan_paint(paint_color)
+ if(color_hex2num(paint_color) < 255)
+ set_opacity(255)
+ else
+ set_opacity(initial(opacity))
+ add_atom_colour(paint_color, WASHABLE_COLOUR_PRIORITY)
+
+/obj/structure/window/proc/electrochromatic_dim()
+ if(electrochromatic_status == ELECTROCHROMATIC_DIMMED)
+ return
+ electrochromatic_status = ELECTROCHROMATIC_DIMMED
+ animate(src, color = "#222222", time = 2)
+ set_opacity(TRUE)
+
+/obj/structure/window/proc/electrochromatic_off()
+ if(electrochromatic_status == ELECTROCHROMATIC_OFF)
+ return
+ electrochromatic_on = FALSE
+ var/current = color
+ update_atom_colour()
+ var/newcolor = color
+ color = current
+ animate(src, color = newcolor, time = 2)
+
+/obj/structure/window/proc/remove_electrochromatic()
+ electrochromatic_status = NOT_ELECTROCHROMATIC
+ if(!electrochromatic_id)
+ return
+ var/list/L = GLOB.electrochromatic_window_lookup["[electrochromatic_id]"]
+ if(L)
+ L -= src
+ electrochromatic_id = null
+
+/obj/structure/window/vv_edit_var(var_name, var_value)
+ var/old_id
+ var/check_status
+ if(var_name == NAMEOF(src, electrochromatic_id))
+ if((electrochromatic_status != NOT_ELECTROCHROMATIC) && electrochromatic_id)
+ old_id = electrochromatic_id
+ if(var_name == NAMEOF(src, electrochromatic_status))
+ check_status = TRUE
+ . = ..() //do this first incase it runtimes.
+ if(check_status)
+ if(electrochromatic_status == NOT_ELECTROCHROMATIC)
+ remove_electrochromatic()
+ return
+ else if(electrochromatic_status == ELECTROCHROMATIC_OFF)
+ if(!electrochromatic_id)
+ return
+ else
+ make_electrochromatic()
+ electrochromatic_off()
+ return
+ else if(electrochromatic_status == ELECTROCHROMATIC_DIMMED)
+ if(!electrochromatic_id)
+ return
+ else
+ make_electrochromatic()
+ electrochromatic_dim()
+ return
+ else
+ remove_electrochromatic()
+ if(old_id)
+ GLOB.electrochromatic_window_lookup[old_id] -= src
+ if(electrochromatic_id)
+ GLOB.electrochromatic_window_lookup[electrochromatic_id] += src
+
+/obj/structure/window/proc/make_electrochromatic(new_id)
+ remove_electrochromatic()
+ electrochromatic_id = new_id
+ electrochromatic_status = ELECTROCHROMATIC_OFF
+ LAZYINITLIST(GLOB.electrochromatic_window_lookup["[electrochromatic_id]")
+ GLOB.electrochromatic_window_lookup[electrochromatic_id] |= src
+
+/obj/structure/window/update_atom_colour()
+ if((electrochromatic_status != ELECTROCHROMATIC_OFF) && (electrochromatic_status != ELECTROCHROMATIC_DIMMED))
+ return FALSE
+ return ..()
+
/obj/structure/window/proc/check_state(checked_state)
if(state == checked_state)
return TRUE
@@ -263,7 +393,6 @@
if(BURN)
playsound(src, 'sound/items/Welder.ogg', 100, 1)
-
/obj/structure/window/deconstruct(disassembled = TRUE)
if(QDELETED(src))
return
@@ -272,6 +401,9 @@
if(!(flags_1 & NODECONSTRUCT_1))
for(var/obj/item/shard/debris in spawnDebris(drop_location()))
transfer_fingerprints_to(debris) // transfer fingerprints to shards only
+ if(electrochromatic_status != NOT_ELECTROCHROMATIC) //eh fine keep your kit.
+ new /obj/item/electrochromatic_kit/K(drop_location())
+ // Intentionally not setting the ID so you can't decon one to know all of the IDs.
qdel(src)
update_nearby_icons()
@@ -315,9 +447,9 @@
density = FALSE
air_update_turf(1)
update_nearby_icons()
+ remove_electrochromatic()
return ..()
-
/obj/structure/window/Move()
var/turf/T = loc
. = ..()
@@ -731,7 +863,6 @@
set_opacity(TRUE)
queue_smooth(src)
-
/obj/structure/window/paperframe/attackby(obj/item/W, mob/user)
if(W.get_temperature())
fire_act(W.get_temperature())
@@ -749,3 +880,7 @@
return
..()
update_icon()
+
+#undef NOT_ELECTROCHROMATIC
+#undef ELECTROCHROMATIC_OFF
+#undef ELECTROCHROMATIC_DIMMED
diff --git a/code/modules/assembly/doorcontrol.dm b/code/modules/assembly/doorcontrol.dm
index 1c9c1a0203..1b9e63abaa 100644
--- a/code/modules/assembly/doorcontrol.dm
+++ b/code/modules/assembly/doorcontrol.dm
@@ -3,14 +3,42 @@
desc = "A small electronic device able to control a blast door remotely."
icon_state = "control"
attachable = TRUE
- var/id = null
- var/can_change_id = 0
+ /// Our ID. Make the first character ! if you want to obfuscate it as a mapper via randomization.
+ var/id
+ /// Can the ID be changed if used in hand?
+ var/can_change_id = FALSE
+ /// Show ID?
+ var/show_id = TRUE
+ /// Numerical ID or text?
+ var/id_is_number = FALSE
var/cooldown = FALSE //Door cooldowns
+/obj/item/assembly/Initialize(mapload)
+ if(mapload && id)
+ if(copytext(id, 1, 2) == "!")
+ id = SSmapping.get_obfuscated_id(id)
+ return ..()
+
/obj/item/assembly/control/examine(mob/user)
. = ..()
- if(id)
+ if(id && show_id)
. += "Its channel ID is '[id]'."
+ if(can_change_id)
+ . += "Use in hand to change ID."
+
+/obj/item/assembly/control/attack_self(mob/living/user)
+ . = ..()
+ if(.)
+ return
+ if(!can_change_id)
+ return
+ var/new_id
+ if(id_is_number)
+ new_id = input(user, "Set ID (number)", "Set ID", show_id? id : null) as number|null
+ else
+ new_id = input(user, "Set ID", "Set ID", show_id? id : null) as text|null
+ if(!isnull(new_id)) //0/"" is considered !, so check null instead of just !.
+ id = new_id
/obj/item/assembly/control/activate()
cooldown = TRUE
@@ -22,7 +50,6 @@
INVOKE_ASYNC(M, openclose ? /obj/machinery/door/poddoor.proc/open : /obj/machinery/door/poddoor.proc/close)
addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 10)
-
/obj/item/assembly/control/airlock
name = "airlock controller"
desc = "A small electronic device able to control an airlock remotely."
@@ -123,7 +150,6 @@
addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 50)
-
/obj/item/assembly/control/crematorium
name = "crematorium controller"
desc = "An evil-looking remote controller for a crematorium."
@@ -135,3 +161,14 @@
C.cremate(usr)
addtimer(VARSET_CALLBACK(src, cooldown, FALSE), 50)
+
+/obj/item/assembly/control/electrochromatic
+ name = "electrochromatic window controller"
+ desc = "Toggles linked electrochromatic windows."
+ can_change_id = TRUE
+ /// Stores our status to prevent windows from desyncing.
+ var/on = FALSE
+
+/obj/item/assembly/control/electrochromatic/activate()
+ on = !on
+ SEND_GLOBAL_SIGNAL(COMSIG_GLOB_ELECTROCHROMATIC_WINDOW_TOGGLE, on, id)
diff --git a/code/modules/research/designs/autolathe_desings/autolathe_designs_electronics.dm b/code/modules/research/designs/autolathe_desings/autolathe_designs_electronics.dm
index 86e11010bc..5d80b91087 100644
--- a/code/modules/research/designs/autolathe_desings/autolathe_designs_electronics.dm
+++ b/code/modules/research/designs/autolathe_desings/autolathe_designs_electronics.dm
@@ -74,3 +74,11 @@
materials = list(/datum/material/glass = 20)
build_path = /obj/item/stock_parts/cell/emergency_light
category = list("initial", "Electronics")
+
+/datum/design/electrochromatic_control
+ name = "Electrochromatic Control Circuit"
+ id = "electrochromatic_control_circuit"
+ build_type = AUTOLATHE
+ materials = list(/datum/material/iron = 100, /datum/material/glass = 100)
+ build_path = /obj/item/assembly/control/electrochromatic
+ category = list("initial", "Electronics")
diff --git a/tgstation.dme b/tgstation.dme
index 848d149ae0..ceed653acc 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -980,6 +980,7 @@
#include "code\game\objects\items\devices\dogborg_sleeper.dm"
#include "code\game\objects\items\devices\doorCharge.dm"
#include "code\game\objects\items\devices\electroadaptive_pseudocircuit.dm"
+#include "code\game\objects\items\devices\electrochromatic_kit.dm"
#include "code\game\objects\items\devices\flashlight.dm"
#include "code\game\objects\items\devices\forcefieldprojector.dm"
#include "code\game\objects\items\devices\geiger_counter.dm"
From a9d0ce45b9eb6188856492798015ca85af93e005 Mon Sep 17 00:00:00 2001
From: kevinz000 <2003111+kevinz000@users.noreply.github.com>
Date: Sun, 26 Apr 2020 03:29:43 -0700
Subject: [PATCH 04/14] wow lotsa effort huh
---
code/game/objects/structures/window.dm | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index 07fd8142cb..6bc2ada140 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -52,7 +52,7 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup)
/obj/structure/window/examine(mob/user)
. = ..()
if(electrochromatic_status != NOT_ELECTROCHROMATIC)
- . += "The window has electrochromatic circuitry on it.")
+ . += "The window has electrochromatic circuitry on it."
if(reinf)
if(anchored && state == WINDOW_SCREWED_TO_FRAME)
. += "The window is screwed to the frame."
From e3b987879e3b9a2461e54b7bfcceda5eebaac8f7 Mon Sep 17 00:00:00 2001
From: kevinz000 <2003111+kevinz000@users.noreply.github.com>
Date: Sun, 26 Apr 2020 03:30:18 -0700
Subject: [PATCH 05/14] wow lotsa effort huh
---
code/game/objects/structures/window.dm | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index 6bc2ada140..54590134d2 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -210,7 +210,7 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup)
to_chat(user, "[src] is already in good condition!")
return
- if(!anchored && istype(I, /obj/item/electronics/electrochromatic_kit && user.a_intent == INTENT_HELP)
+ if(istype(I, /obj/item/electronics/electrochromatic_kit) && user.a_intent == INTENT_HELP)
var/obj/item/electronics/electrochromatic_kit/K = I
if(!user.temporarilyRemoveItemFromInventory(K))
to_chat(user, "[K] is stuck to your hand!")
@@ -218,7 +218,7 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup)
if(is_electrochromatic)
to_chat(user, "[src] is already electrochromatic!")
return
- if(!anchored)
+ if(anchored)
to_chat(user, "[src] must not be attached to the floor!")
return
if(!K.id)
@@ -346,7 +346,7 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup)
remove_electrochromatic()
electrochromatic_id = new_id
electrochromatic_status = ELECTROCHROMATIC_OFF
- LAZYINITLIST(GLOB.electrochromatic_window_lookup["[electrochromatic_id]")
+ LAZYINITLIST(GLOB.electrochromatic_window_lookup["[electrochromatic_id]"])
GLOB.electrochromatic_window_lookup[electrochromatic_id] |= src
/obj/structure/window/update_atom_colour()
From aeaf6ea102cd024fa2bfd08fa9c6152f618708c9 Mon Sep 17 00:00:00 2001
From: kevinz000 <2003111+kevinz000@users.noreply.github.com>
Date: Sun, 26 Apr 2020 03:33:08 -0700
Subject: [PATCH 06/14] wow lotsa effort huh
---
code/game/objects/structures/window.dm | 6 +++++-
code/modules/assembly/doorcontrol.dm | 2 +-
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index 54590134d2..1a5ebf17e0 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -352,7 +352,11 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup)
/obj/structure/window/update_atom_colour()
if((electrochromatic_status != ELECTROCHROMATIC_OFF) && (electrochromatic_status != ELECTROCHROMATIC_DIMMED))
return FALSE
- return ..()
+ . = ..()
+ if(color_hex2num(color) < 255)
+ set_opacity(255)
+ else
+ set_opacity(FALSE)
/obj/structure/window/proc/check_state(checked_state)
if(state == checked_state)
diff --git a/code/modules/assembly/doorcontrol.dm b/code/modules/assembly/doorcontrol.dm
index 1b9e63abaa..6016fd6453 100644
--- a/code/modules/assembly/doorcontrol.dm
+++ b/code/modules/assembly/doorcontrol.dm
@@ -34,7 +34,7 @@
return
var/new_id
if(id_is_number)
- new_id = input(user, "Set ID (number)", "Set ID", show_id? id : null) as number|null
+ new_id = input(user, "Set ID (number)", "Set ID", show_id? id : null) as num|null
else
new_id = input(user, "Set ID", "Set ID", show_id? id : null) as text|null
if(!isnull(new_id)) //0/"" is considered !, so check null instead of just !.
From 1b5e4b32cb8886facf8a342ad83406fa6e03719a Mon Sep 17 00:00:00 2001
From: kevinz000 <2003111+kevinz000@users.noreply.github.com>
Date: Sun, 26 Apr 2020 03:33:26 -0700
Subject: [PATCH 07/14] wow lotsa effort huh
---
code/modules/assembly/doorcontrol.dm | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/code/modules/assembly/doorcontrol.dm b/code/modules/assembly/doorcontrol.dm
index 6016fd6453..3c2d9fbce3 100644
--- a/code/modules/assembly/doorcontrol.dm
+++ b/code/modules/assembly/doorcontrol.dm
@@ -9,8 +9,6 @@
var/can_change_id = FALSE
/// Show ID?
var/show_id = TRUE
- /// Numerical ID or text?
- var/id_is_number = FALSE
var/cooldown = FALSE //Door cooldowns
/obj/item/assembly/Initialize(mapload)
@@ -33,10 +31,7 @@
if(!can_change_id)
return
var/new_id
- if(id_is_number)
- new_id = input(user, "Set ID (number)", "Set ID", show_id? id : null) as num|null
- else
- new_id = input(user, "Set ID", "Set ID", show_id? id : null) as text|null
+ new_id = input(user, "Set ID", "Set ID", show_id? id : null) as text|null
if(!isnull(new_id)) //0/"" is considered !, so check null instead of just !.
id = new_id
From bf7962d8f989ba0e1c5168a0b3f5c6bd2f6b7798 Mon Sep 17 00:00:00 2001
From: kevinz000 <2003111+kevinz000@users.noreply.github.com>
Date: Sun, 26 Apr 2020 03:36:09 -0700
Subject: [PATCH 08/14] wow lotsa effort huh
---
code/controllers/subsystem/mapping.dm | 3 +--
code/datums/components/crafting/recipes/recipes_misc.dm | 2 +-
code/game/objects/structures/window.dm | 9 ++++-----
code/modules/assembly/doorcontrol.dm | 4 ++--
4 files changed, 8 insertions(+), 10 deletions(-)
diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm
index ffda2731b1..526e4b98e3 100644
--- a/code/controllers/subsystem/mapping.dm
+++ b/code/controllers/subsystem/mapping.dm
@@ -590,5 +590,4 @@ GLOBAL_LIST_EMPTY(the_station_areas)
var/key = "[original]%[id_type]"
if(random_generated_ids_by_original[key])
return random_generated_ids_by_original[key]
- random_generated_ids_by_original[key] = "[obfuscation_secret]%[obfuscation_next++]"
- return value
+ . = random_generated_ids_by_original[key] = "[obfuscation_secret]%[obfuscation_next_id++]"
diff --git a/code/datums/components/crafting/recipes/recipes_misc.dm b/code/datums/components/crafting/recipes/recipes_misc.dm
index b26755d4ac..940e6c134f 100644
--- a/code/datums/components/crafting/recipes/recipes_misc.dm
+++ b/code/datums/components/crafting/recipes/recipes_misc.dm
@@ -236,7 +236,7 @@
/datum/crafting_recipe/electrochromatic_kit
name = "Electrochromatic Kit"
result = /obj/item/electronics/electrochromatic_kit
- reqs = list(/obj/item/stack/metal = 1,
+ reqs = list(/obj/item/stack/sheet/metal = 1,
/obj/item/stack/cable_coil = 1)
time = 5
subcategory = CAT_MISCELLANEOUS
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index 1a5ebf17e0..143024bf97 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -8,12 +8,11 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup)
var/list/windows = GLOB.electrochromatic_window_lookup["[id]"]
if(!windows)
return
- var/obj/structure/window/W = i
+ var/obj/structure/window/W //define outside for performance because obviously this matters.
for(var/i in windows)
W = i
new_status? W.electrochromatic_dim() : W.electrochromatic_off()
-
/obj/structure/window
name = "window"
desc = "A window."
@@ -215,7 +214,7 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup)
if(!user.temporarilyRemoveItemFromInventory(K))
to_chat(user, "[K] is stuck to your hand!")
return
- if(is_electrochromatic)
+ if(electrochromatic_status != NOT_ELECTROCHROMATIC)
to_chat(user, "[src] is already electrochromatic!")
return
if(anchored)
@@ -292,7 +291,7 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup)
/obj/structure/window/proc/electrochromatic_off()
if(electrochromatic_status == ELECTROCHROMATIC_OFF)
return
- electrochromatic_on = FALSE
+ electrochromatic_status = ELECTROCHROMATIC_OFF
var/current = color
update_atom_colour()
var/newcolor = color
@@ -406,7 +405,7 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup)
for(var/obj/item/shard/debris in spawnDebris(drop_location()))
transfer_fingerprints_to(debris) // transfer fingerprints to shards only
if(electrochromatic_status != NOT_ELECTROCHROMATIC) //eh fine keep your kit.
- new /obj/item/electrochromatic_kit/K(drop_location())
+ new /obj/item/electronics/electrochromatic_kit/K(drop_location())
// Intentionally not setting the ID so you can't decon one to know all of the IDs.
qdel(src)
update_nearby_icons()
diff --git a/code/modules/assembly/doorcontrol.dm b/code/modules/assembly/doorcontrol.dm
index 3c2d9fbce3..41b063f43e 100644
--- a/code/modules/assembly/doorcontrol.dm
+++ b/code/modules/assembly/doorcontrol.dm
@@ -11,7 +11,7 @@
var/show_id = TRUE
var/cooldown = FALSE //Door cooldowns
-/obj/item/assembly/Initialize(mapload)
+/obj/item/assembly/control/Initialize(mapload)
if(mapload && id)
if(copytext(id, 1, 2) == "!")
id = SSmapping.get_obfuscated_id(id)
@@ -166,4 +166,4 @@
/obj/item/assembly/control/electrochromatic/activate()
on = !on
- SEND_GLOBAL_SIGNAL(COMSIG_GLOB_ELECTROCHROMATIC_WINDOW_TOGGLE, on, id)
+ do_electrochromatic_toggle(on, id)
From ff9f18bdbdbb0fb1bfb67a308cf2485f4447d2a4 Mon Sep 17 00:00:00 2001
From: kevinz000 <2003111+kevinz000@users.noreply.github.com>
Date: Sun, 26 Apr 2020 03:38:41 -0700
Subject: [PATCH 09/14] wow lotsa effort huh
---
code/game/objects/structures/window.dm | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index 143024bf97..796db7a9c6 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -405,7 +405,7 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup)
for(var/obj/item/shard/debris in spawnDebris(drop_location()))
transfer_fingerprints_to(debris) // transfer fingerprints to shards only
if(electrochromatic_status != NOT_ELECTROCHROMATIC) //eh fine keep your kit.
- new /obj/item/electronics/electrochromatic_kit/K(drop_location())
+ new /obj/item/electronics/electrochromatic_kit(drop_location())
// Intentionally not setting the ID so you can't decon one to know all of the IDs.
qdel(src)
update_nearby_icons()
From 2e35a42f4356cc9795fe3925a25d97ec154b196a Mon Sep 17 00:00:00 2001
From: kevinz000 <2003111+kevinz000@users.noreply.github.com>
Date: Sun, 26 Apr 2020 04:10:38 -0700
Subject: [PATCH 10/14] wow lotsa effort huh
---
.../objects/items/devices/electrochromatic_kit.dm | 1 -
code/game/objects/structures/window.dm | 12 +++++++-----
code/modules/assembly/doorcontrol.dm | 2 --
3 files changed, 7 insertions(+), 8 deletions(-)
diff --git a/code/game/objects/items/devices/electrochromatic_kit.dm b/code/game/objects/items/devices/electrochromatic_kit.dm
index aae886d397..d582eab00e 100644
--- a/code/game/objects/items/devices/electrochromatic_kit.dm
+++ b/code/game/objects/items/devices/electrochromatic_kit.dm
@@ -1,7 +1,6 @@
/obj/item/electronics/electrochromatic_kit
name = "electrochromatic kit"
desc = "A kit for upgrading a window into an electrochromatic one."
- icon = 'icons/obj/device.dmi'
/// Electrochromatic ID
var/id
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index 796db7a9c6..a8c6dfb898 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -211,9 +211,6 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup)
if(istype(I, /obj/item/electronics/electrochromatic_kit) && user.a_intent == INTENT_HELP)
var/obj/item/electronics/electrochromatic_kit/K = I
- if(!user.temporarilyRemoveItemFromInventory(K))
- to_chat(user, "[K] is stuck to your hand!")
- return
if(electrochromatic_status != NOT_ELECTROCHROMATIC)
to_chat(user, "[src] is already electrochromatic!")
return
@@ -223,6 +220,9 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup)
if(!K.id)
to_chat(user, "[K] has no ID set!")
return
+ if(!user.temporarilyRemoveItemFromInventory(K))
+ to_chat(user, "[K] is stuck to your hand!")
+ return
user.visible_message("[user] upgrades [src] with [I].", "You upgrade [src] with [I].")
make_electrochromatic(K.id)
qdel(K)
@@ -341,8 +341,10 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup)
if(electrochromatic_id)
GLOB.electrochromatic_window_lookup[electrochromatic_id] += src
-/obj/structure/window/proc/make_electrochromatic(new_id)
+/obj/structure/window/proc/make_electrochromatic(new_id = electrochromatic_id)
remove_electrochromatic()
+ if(!new_id)
+ CRASH("Attempted to make electrochromatic with null ID.")
electrochromatic_id = new_id
electrochromatic_status = ELECTROCHROMATIC_OFF
LAZYINITLIST(GLOB.electrochromatic_window_lookup["[electrochromatic_id]"])
@@ -352,7 +354,7 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup)
if((electrochromatic_status != ELECTROCHROMATIC_OFF) && (electrochromatic_status != ELECTROCHROMATIC_DIMMED))
return FALSE
. = ..()
- if(color_hex2num(color) < 255)
+ if(color && (color_hex2num(color) < 255))
set_opacity(255)
else
set_opacity(FALSE)
diff --git a/code/modules/assembly/doorcontrol.dm b/code/modules/assembly/doorcontrol.dm
index 41b063f43e..32e262ce65 100644
--- a/code/modules/assembly/doorcontrol.dm
+++ b/code/modules/assembly/doorcontrol.dm
@@ -26,8 +26,6 @@
/obj/item/assembly/control/attack_self(mob/living/user)
. = ..()
- if(.)
- return
if(!can_change_id)
return
var/new_id
From f70490c61dce9205ae46979d0661191c3608e801 Mon Sep 17 00:00:00 2001
From: kevinz000 <2003111+kevinz000@users.noreply.github.com>
Date: Sun, 26 Apr 2020 04:40:18 -0700
Subject: [PATCH 11/14] fixes
---
code/game/machinery/buttons.dm | 8 ++++++++
code/game/objects/structures/window.dm | 14 +++++++-------
2 files changed, 15 insertions(+), 7 deletions(-)
diff --git a/code/game/machinery/buttons.dm b/code/game/machinery/buttons.dm
index ad3dd5d720..3a90707bbe 100644
--- a/code/game/machinery/buttons.dm
+++ b/code/game/machinery/buttons.dm
@@ -16,6 +16,9 @@
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
/obj/machinery/button/Initialize(mapload, ndir = 0, built = 0)
+ if(istext(id) && mapload)
+ if(copytext(id, 1, 2) == "!")
+ id = SSmapping.get_obfuscated_id(id)
. = ..()
if(built)
setDir(ndir)
@@ -260,6 +263,11 @@
req_access = list()
id = 1
+/obj/machinery/button/electrochromatic
+ name = "window dim control"
+ desc = "Controls linked electrochromatic windows"
+ device_type = /obj/item/assembly/control/electrochromatic
+
/obj/item/wallframe/button
name = "button frame"
desc = "Used for building buttons."
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index a8c6dfb898..e4d93ea8de 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -299,6 +299,7 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup)
animate(src, color = newcolor, time = 2)
/obj/structure/window/proc/remove_electrochromatic()
+ electrochromatic_off()
electrochromatic_status = NOT_ELECTROCHROMATIC
if(!electrochromatic_id)
return
@@ -308,14 +309,17 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup)
electrochromatic_id = null
/obj/structure/window/vv_edit_var(var_name, var_value)
- var/old_id
var/check_status
if(var_name == NAMEOF(src, electrochromatic_id))
- if((electrochromatic_status != NOT_ELECTROCHROMATIC) && electrochromatic_id)
- old_id = electrochromatic_id
+ if(electrochromatic_id && GLOB.electrochromatic_window_lookup["[electrochromatic_id]"])
+ GLOB.electrochromatic_window_lookup[electrochromatic_id] -= src
if(var_name == NAMEOF(src, electrochromatic_status))
check_status = TRUE
. = ..() //do this first incase it runtimes.
+ if(var_name == NAMEOF(src, electrochromatic_id))
+ if((electrochromatic_status != NOT_ELECTROCHROMATIC) && electrochromatic_id)
+ LAZYINITLIST(GLOB.electrochromatic_window_lookup[electrochromatic_id])
+ GLOB.electrochromatic_window_lookup[electrochromatic_id] += src
if(check_status)
if(electrochromatic_status == NOT_ELECTROCHROMATIC)
remove_electrochromatic()
@@ -336,10 +340,6 @@ GLOBAL_LIST_EMPTY(electrochromatic_window_lookup)
return
else
remove_electrochromatic()
- if(old_id)
- GLOB.electrochromatic_window_lookup[old_id] -= src
- if(electrochromatic_id)
- GLOB.electrochromatic_window_lookup[electrochromatic_id] += src
/obj/structure/window/proc/make_electrochromatic(new_id = electrochromatic_id)
remove_electrochromatic()
From 28da033111afe9857394579220c2f102462da8c0 Mon Sep 17 00:00:00 2001
From: kevinz000 <2003111+kevinz000@users.noreply.github.com>
Date: Sun, 26 Apr 2020 17:37:27 -0700
Subject: [PATCH 12/14] fine
---
code/datums/components/crafting/recipes/recipes_misc.dm | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/code/datums/components/crafting/recipes/recipes_misc.dm b/code/datums/components/crafting/recipes/recipes_misc.dm
index 940e6c134f..cd254943ea 100644
--- a/code/datums/components/crafting/recipes/recipes_misc.dm
+++ b/code/datums/components/crafting/recipes/recipes_misc.dm
@@ -239,7 +239,7 @@
reqs = list(/obj/item/stack/sheet/metal = 1,
/obj/item/stack/cable_coil = 1)
time = 5
- subcategory = CAT_MISCELLANEOUS
+ subcategory = CAT_TOOL
category = CAT_MISC
////////////
From c38c1755cd84f75e245ea24665f0a585b6944f80 Mon Sep 17 00:00:00 2001
From: Ghommie <42542238+Ghommie@users.noreply.github.com>
Date: Sat, 2 May 2020 19:05:41 +0200
Subject: [PATCH 13/14] Done, tested, too many options.
---
code/__DEFINES/misc.dm | 7 ++
code/datums/elements/scavenging.dm | 101 ++++++++++++++++------
code/game/objects/structures/loot_pile.dm | 74 ++++++++--------
3 files changed, 120 insertions(+), 62 deletions(-)
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 ..()
From 7ae2615f519ad3ce2fffa8264d6351e955ee94f9 Mon Sep 17 00:00:00 2001
From: Ghommie <42542238+Ghommie@users.noreply.github.com>
Date: Sat, 2 May 2020 19:13:21 +0200
Subject: [PATCH 14/14] Whops.
---
code/game/objects/structures/loot_pile.dm | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/code/game/objects/structures/loot_pile.dm b/code/game/objects/structures/loot_pile.dm
index bbcfacd9c1..b6249ec1e4 100644
--- a/code/game/objects/structures/loot_pile.dm
+++ b/code/game/objects/structures/loot_pile.dm
@@ -60,7 +60,7 @@
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]
+ if(ispath(A, /obj/item))
+ safe_maint_items[A] = GLOB.maintenance_loot[A]
loot += safe_maint_items
return ..()