Scavenging element.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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, "<span class='notice'>Looks like someone has dug here already.</span>")
|
||||
return
|
||||
|
||||
if(!isturf(user.loc))
|
||||
return
|
||||
|
||||
if(I.tool_behaviour == TOOL_SHOVEL || I.tool_behaviour == TOOL_MINING)
|
||||
to_chat(user, "<span class='notice'>You start digging...</span>")
|
||||
|
||||
if(I.use_tool(parent, user, 40, volume=50))
|
||||
to_chat(user, "<span class='notice'>You dig a hole.</span>")
|
||||
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()
|
||||
@@ -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 ")
|
||||
. += "<span class='notice'>Looks like [source.p_they()] can be scavenged[length(tool_types) ? " with either a" : ""] [text]</span>"
|
||||
|
||||
/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 = "<span class='notice'>You [progress_done ? "resume a ditched task and " : ""][search_texts[2]] [src].</span>"
|
||||
var/msg_blind
|
||||
if(len_messages >= 3)
|
||||
msg_blind = "<span class='italic'>[search_texts[3]]</span>"
|
||||
user.visible_message("<span class='notice'>[user] [search_texts[1]] [src].</span>", 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, "<span class='warning'>Looks likes there is nothing worth of interest left in [src] anymore, further attempts would be futile.</span>")
|
||||
return
|
||||
switch(loot) // TODO: datumize these out.
|
||||
if(SCAVENGING_FOUND_NOTHING)
|
||||
to_chat(user, "<span class='notice'>You found nothing, better luck next time.</span>")
|
||||
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, "<span class='notice'>You found something in [src]... no wait, that's just another [nasty_rodent].</span>")
|
||||
new /mob/living/simple_animal/mouse(source.loc)
|
||||
if(SCAVENGING_SPAWN_MICE)
|
||||
user.visible_message("<span class='notice'>A small gang of mice emerges from [source].</span>", \
|
||||
"<span class='notice'>You found something in [src]... no wait, that's just another- <b>no wait, that's a lot of damn mice.</b></span>")
|
||||
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, "<span class='notice'>You found nothing, better luck next time.</span>")
|
||||
free = TRUE
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You found something in [src]... no wait, that's Tom, the mouse! What is he doing here?</span>")
|
||||
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 = "! <b>AMAZING!</b>"
|
||||
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("<span class='warning'>[src] has been looted clean.</span>")
|
||||
qdel(source)
|
||||
Reference in New Issue
Block a user