diff --git a/code/datums/components/cooktop.dm b/code/datums/components/cooktop.dm
index a72a08dc8630..97452fc515f7 100644
--- a/code/datums/components/cooktop.dm
+++ b/code/datums/components/cooktop.dm
@@ -4,12 +4,14 @@
if(!isobj(parent))
return FALSE
parent.register_event(/event/attackhand, src, nameof(src::on_attackhand()))
+ parent.register_event(/event/item_attack_self, src, nameof(src::on_attackself()))
parent.register_event(/event/attackby, src, nameof(src::on_attackby()))
parent.register_event(/event/examined, src, nameof(src::on_examine()))
return TRUE
/datum/component/cooktop/Destroy()
parent.unregister_event(/event/attackhand, src, nameof(src::on_attackhand()))
+ parent.unregister_event(/event/item_attack_self, src, nameof(src::on_attackself()))
parent.unregister_event(/event/attackby, src, nameof(src::on_attackby()))
parent.unregister_event(/event/examined, src, nameof(src::on_examine()))
..()
@@ -24,6 +26,16 @@
P.render_cookvessel()
P.remove_particles()
+/datum/component/cooktop/proc/on_attackself(mob/user)
+ var/obj/P = parent
+ if(P.cookvessel && ismob(user))
+ if(user.put_in_inactive_hand(P.cookvessel))
+ P.cookvessel.cook_stop()
+ P.cookvessel = null
+ P.on_cook_stop()
+ P.render_cookvessel()
+ P.remove_particles()
+
/datum/component/cooktop/proc/on_attackby(mob/attacker, obj/item/item)
var/obj/P = parent
if(P.cookvessel)
diff --git a/code/game/machinery/bots/mulebot.dm b/code/game/machinery/bots/mulebot.dm
index 1fb0d9387569..8e200f3824da 100644
--- a/code/game/machinery/bots/mulebot.dm
+++ b/code/game/machinery/bots/mulebot.dm
@@ -27,7 +27,7 @@ var/global/mulebot_count = 0
/obj/machinery/bot/mulebot
name = "\improper MULEbot"
desc = "A Multiple Utility Load Effector bot."
- icon_state = "mulebot0"
+ icon_state = "mulebot"
icon_initial = "mulebot"
density = 1
anchored = 1
@@ -80,6 +80,7 @@ var/global/mulebot_count = 0
var/honk_cooldown = 1 SECONDS //how often a pAI-controlled MULEbot can damage a mob by running over them
var/coolingdown = FALSE
var/honk_coolingdown = FALSE
+ var/list/bot_sprites = list("default","flames","cargonia","gold")
// Technically if we were true to form, the navbeacon should've an insider radio which would be sending the signal rather than sending the signal itself
// The gain in functionality if it were to be implented is negligeble for a lot of confusing code
@@ -129,6 +130,14 @@ var/global/mulebot_count = 0
..()
+/obj/machinery/bot/mulebot/update_icon()
+ overlays.Cut()
+ if(!on && open)
+ overlays += image(icon,src,"mulebot-hatch")
+ else if(on && mode != MODE_WAITING && wires.MobAvoid() != 0)
+ overlays += image(icon,src,"mulebot1")
+ ..()
+
// attack by item
// emag : lock/unlock,
// screwdriver: open/close hatch
@@ -155,14 +164,12 @@ var/global/mulebot_count = 0
return
I.playtoolsound(src, 25, extrarange = -6)
open = !open
+ var/openword = "close"
if(open)
- src.visible_message("[user] opens the maintenance hatch of [src]", "You open [src]'s maintenance hatch.")
+ openword = "open"
on = 0
- icon_state="[icon_initial]-hatch"
- else
- src.visible_message("[user] closes the maintenance hatch of [src]", "You close [src]'s maintenance hatch.")
- icon_state = "[icon_initial]0"
-
+ src.visible_message("[user] [openword]s the maintenance hatch of [src]", "You [openword] [src]'s maintenance hatch.")
+ update_icon()
updateDialog()
else if (I.is_wrench(user) && user.a_intent != I_HURT)
if (src.health < maxHealth)
@@ -187,8 +194,12 @@ var/global/mulebot_count = 0
/obj/machinery/bot/mulebot/emag_act(mob/user)
toggle_lock(user, TRUE)
to_chat(user, "You [locked ? "lock" : "unlock"] [src]'s controls!")
- flick("[icon_initial]-emagged", src)
playsound(src, 'sound/effects/sparks1.ogg', 100, 0)
+ if(!(on && mode != MODE_WAITING && wires.MobAvoid() != 0))
+ overlays += image(icon,src,"mulebot1")
+ overlays += image(icon,src,"mulebot-emagged")
+ spawn(4)
+ update_icon()
/obj/machinery/bot/mulebot/ex_act(var/severity)
unload(0)
@@ -337,7 +348,7 @@ var/global/mulebot_count = 0
if ("pause")
if(mode != MODE_WAITING)
mode = MODE_WAITING
- icon_state = "[icon_initial]0"
+ update_icon()
else
mode = MODE_IDLE
if ("clear_queue")
@@ -374,7 +385,7 @@ var/global/mulebot_count = 0
if("power")
if (src.on)
turn_off()
- icon_state = "[icon_initial]0"
+ update_icon()
else if (cell && !open)
turn_on()
else
@@ -408,7 +419,7 @@ var/global/mulebot_count = 0
if("stop")
if(mode != MODE_WAITING)
mode = MODE_WAITING
- icon_state = "[icon_initial]0"
+ update_icon()
updateDialog()
if("go")
@@ -505,7 +516,7 @@ var/global/mulebot_count = 0
/obj/machinery/bot/mulebot/turn_off()
..()
- icon_state = "[icon_initial]0"
+ update_icon()
summoned = FALSE
target = null
destination = ""
@@ -683,7 +694,7 @@ var/global/mulebot_count = 0
mode = MODE_MOVING
else
mode = MODE_IDLE
- icon_state = "[icon_initial][(wires.MobAvoid() != 0)]"
+ update_icon()
/obj/machinery/bot/mulebot/set_destination(var/new_dest)
astar_debug_mulebots("Requesting a path to [new_dest]")
@@ -1003,7 +1014,7 @@ var/global/mulebot_count = 0
if(!on || remaining_steps <= 0 || !path.len || mode == MODE_WAITING)
return FALSE
//Ok, we're on, we're not done, and we have a path.
- icon_state = "[icon_initial][(wires.MobAvoid() != 0)]"
+ update_icon()
set_glide_size(DELAY2GLIDESIZE(SS_WAIT_BOTS/steps_per))
if(!process_astar_path()) // Process the pathfinding. This handles most movement/delivery stuff.
//And if there are problems processing, go here.
@@ -1086,7 +1097,7 @@ var/global/mulebot_count = 0
destination = ""
target = null
summoned = FALSE
- icon_state = "[icon_initial]0"
+ update_icon()
if(!destinations_queue.len && current_order.returning && current_order.loc_description != home_destination)
//Finished our current task, nothing in the queue, we're not home? Let's go home.
start_home()
diff --git a/code/game/objects/items/trader.dm b/code/game/objects/items/trader.dm
index 4f933ffb9e8c..e4a30cf5325a 100644
--- a/code/game/objects/items/trader.dm
+++ b/code/game/objects/items/trader.dm
@@ -3,61 +3,6 @@
* Feel free to add stuff. Don't forget to add them to the vmachine afterwards.
*/
-/area/vault/mecha_graveyard
-
-/obj/item/weapon/disk/shuttle_coords/vault/mecha_graveyard
- name = "Coordinates to the Mecha Graveyard"
- desc = "Here lay the dead steel of lost mechas, so says some gypsy."
- destination = /obj/docking_port/destination/vault/mecha_graveyard
-
-/obj/docking_port/destination/vault/mecha_graveyard
- areaname = "mecha graveyard"
-
-/datum/map_element/dungeon/mecha_graveyard
- file_path = "maps/randomvaults/dungeons/mecha_graveyard.dmm"
- unique = TRUE
-
-/obj/effect/decal/mecha_wreckage/graveyard_ripley
- name = "Ripley wreckage"
- desc = "Surprisingly well preserved."
- icon_state = "ripley-broken"
-
-/obj/effect/decal/mecha_wreckage/graveyard_ripley/New()
- ..()
- var/list/parts = list(/obj/item/mecha_parts/part/ripley_torso,
- /obj/item/mecha_parts/part/ripley_left_arm,
- /obj/item/mecha_parts/part/ripley_right_arm,
- /obj/item/mecha_parts/part/ripley_left_leg,
- /obj/item/mecha_parts/part/ripley_right_leg)
- welder_salvage += parts
-
- if(prob(80))
- add_salvagable_equipment(new /obj/item/mecha_parts/mecha_equipment/tool/drill,100)
- else
- add_salvagable_equipment(new /obj/item/mecha_parts/mecha_equipment/tool/drill/diamonddrill,100)
- add_salvagable_equipment(new /obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp,100)
- add_salvagable_equipment(new /obj/item/mecha_parts/mecha_equipment/jetpack,100)
-
-/obj/effect/decal/mecha_wreckage/graveyard_clarke
- name = "Clarke wreckage"
- desc = "Surprisingly well preserved."
- icon_state = "clarke-broken"
-
-/obj/effect/decal/mecha_wreckage/graveyard_clarke/New()
- ..()
- var/list/parts = list(
- /obj/item/mecha_parts/part/clarke_torso,
- /obj/item/mecha_parts/part/clarke_head,
- /obj/item/mecha_parts/part/clarke_left_arm,
- /obj/item/mecha_parts/part/clarke_right_arm,
- /obj/item/mecha_parts/part/clarke_left_tread,
- /obj/item/mecha_parts/part/clarke_right_tread)
- welder_salvage += parts
-
- add_salvagable_equipment(new /obj/item/mecha_parts/mecha_equipment/tool/collector,100)
- add_salvagable_equipment(new /obj/item/mecha_parts/mecha_equipment/tool/tiler,100)
- add_salvagable_equipment(new /obj/item/mecha_parts/mecha_equipment/tool/switchtool,100)
-
/obj/item/weapon/mech_expansion_kit
name = "exosuit expansion kit"
desc = "All the equipment you need to replace that useless legroom with a useful bonus equipment slot on your mech."
@@ -279,80 +224,3 @@
return ..()
myvac.whrr(get_turf(target))
return 1
-
-/obj/item/weapon/fakeposter_kit
- name = "cargo cache kit"
- desc = "Used to create a hidden cache behind what appears to be a cargo poster."
- icon = 'icons/obj/barricade.dmi'
- icon_state = "barricade_kit"
- w_class = W_CLASS_MEDIUM
- w_type = RECYK_WOOD
- flammable = TRUE
-
-/obj/item/weapon/fakeposter_kit/preattack(atom/target, mob/user , proximity)
- if(!proximity)
- return
- if(istype(target,/turf/simulated/wall))
- playsound(user.loc, 'sound/effects/shieldbash.ogg', 50, 1)
- if(do_after(user,target,4 SECONDS))
- to_chat(user,"Using the kit, you hollow out the wall and hang the poster in front.")
- var/obj/structure/fakecargoposter/FCP = new(target)
- FCP.access_loc = get_turf(user)
- qdel(src)
- return 1
- else
- return ..()
-
-/obj/structure/fakecargoposter
- icon = 'icons/obj/posters.dmi'
- var/obj/item/weapon/storage/cargocache/cash
- var/turf/access_loc
-
-/obj/structure/fakecargoposter/New()
- ..()
- var/datum/poster/type = pick(/datum/poster/special/cargoflag,/datum/poster/special/cargofull)
- icon_state = initial(type.icon_state)
- desc = initial(type.desc)
- name = initial(type.name)
- cash = new(src)
-
-/obj/structure/fakecargoposter/examine(mob/user)
- ..()
- if(user.loc == access_loc)
- to_chat(user, "Upon closer inspection, there's a hidden cache behind it accessible with a free hand.")
-
-/obj/structure/fakecargoposter/Destroy()
- for(var/atom/movable/A in cash.contents)
- A.forceMove(loc)
- QDEL_NULL(cash)
- ..()
-
-/obj/structure/fakecargoposter/attackby(var/obj/item/weapon/W, mob/user)
- if(iswelder(W))
- visible_message("[user] is destroying the hidden cache disguised as a poster!")
- var/obj/item/tool/weldingtool/WT=W
- if(WT.do_weld(user, src, 10 SECONDS, 5))
- visible_message("[user] destroyed the hidden cache!")
- qdel(src)
- else if(user.loc == access_loc)
- cash.attackby(W,user)
- else
- ..()
-
-/obj/structure/fakecargoposter/attack_hand(mob/user)
- if(user.loc == access_loc)
- cash.AltClick(user)
-
-/obj/item/weapon/storage/cargocache
- name = "cargo cache"
- desc = "A large hidey hole for all your goodies."
- icon = 'icons/obj/posters.dmi'
- icon_state = "cargoposter-flag"
- fits_max_w_class = W_CLASS_LARGE
- max_combined_w_class = 28
- slot_flags = 0
-
-/obj/item/weapon/storage/cargocache/distance_interact(mob/user)
- if(istype(loc,/obj/structure/fakecargoposter) && user.Adjacent(loc))
- return TRUE
- return FALSE
diff --git a/code/game/objects/structures/vehicles/gigadrill.dm b/code/game/objects/structures/vehicles/gigadrill.dm
index ca5ede4613fe..f83e1d380f4a 100644
--- a/code/game/objects/structures/vehicles/gigadrill.dm
+++ b/code/game/objects/structures/vehicles/gigadrill.dm
@@ -66,13 +66,13 @@
var/turf/unsimulated/mineral/M = target
if(M.mining_difficulty > MINE_DIFFICULTY_TOUGH)
return
- if(M.finds && M.finds.len) //Shameless copypaste. TODO: Make an actual proc for this then apply it to mechs as well.
+ if(M.finddatum?.finds?.len) //Shameless copypaste. TODO: Make an actual proc for this then apply it to mechs as well.
if(prob(5))
- M.excavate_find(5, M.finds[1])
+ M.finddatum.excavate_find(5, M.finddatum.finds[1])
else if(prob(50))
- M.finds.Remove(M.finds[1])
+ M.finddatum.finds.Remove(M.finddatum.finds[1])
if(prob(50))
- M.artifact_debris()
+ M.finddatum.artifact_debris()
M.GetDrilled()
if(OB)
var/count = 0
diff --git a/code/game/turfs/unsimulated.dm b/code/game/turfs/unsimulated.dm
index a50794a76d4d..8bda6e52c5dc 100644
--- a/code/game/turfs/unsimulated.dm
+++ b/code/game/turfs/unsimulated.dm
@@ -2,4 +2,8 @@
intact = 1
name = "command"
oxygen = MOLES_O2STANDARD
- nitrogen = MOLES_N2STANDARD
\ No newline at end of file
+ nitrogen = MOLES_N2STANDARD
+ var/datum/finds/finddatum // for xenoarch, common supertype
+
+/turf/unsimulated/proc/color_finds()
+ return "#ffffff"
\ No newline at end of file
diff --git a/code/modules/admin/artifacts_panel.dm b/code/modules/admin/artifacts_panel.dm
index cb0bb147a38d..0ae464ed21fe 100644
--- a/code/modules/admin/artifacts_panel.dm
+++ b/code/modules/admin/artifacts_panel.dm
@@ -165,9 +165,9 @@
for (var/turf/unsimulated/mineral/M in SSxenoarch.artifact_spawning_turfs)
if (!istype(M))
continue
- if (!M.artifact_find)
+ if (!M.finddatum || !M.finddatum.artifact_find)
continue
- var/datum/artifact_find/A = M.artifact_find
+ var/datum/artifact_find/A = M.finddatum.artifact_find
dat += {"
[A.artifact_id] |
Buried ([M.x],[M.y],[M.z]) |
diff --git a/code/modules/mining/mine_turfs.dm b/code/modules/mining/mine_turfs.dm
index 4d3251b5b9c1..78a9352c1163 100644
--- a/code/modules/mining/mine_turfs.dm
+++ b/code/modules/mining/mine_turfs.dm
@@ -63,13 +63,6 @@ var/global/list/mineralSpawnChance[]
//temperature = TCMB
var/mineral/mineral
var/last_act = 0
- var/datum/geosample/geologic_data
- var/excavation_level = 0
- var/list/finds = list()//no longer null to prevent those pesky runtime errors
-// var/next_rock = 0
- var/archaeo_overlay = ""
- var/excav_overlay = ""
- var/datum/artifact_find/artifact_find
var/busy = 0 //Used for a bunch of do_after actions, because we can walk into the rock to trigger them
var/mineral_overlay
var/mined_type = /turf/unsimulated/floor/asteroid
@@ -188,10 +181,23 @@ var/list/icon_state_to_appearance = list()
..(img = image('icons/turf/spookycave.dmi', "spooky_cave",layer = SIDE_LAYER),offset=-16)
..(img = image('icons/turf/spookycave.dmi', "spooky_cave_corners",layer = CORNER_LAYER),offset = -16)
-/turf/unsimulated/mineral/ChangeTurf(var/turf/N, var/tell_universe=1, var/force_lighting_update = 0, var/allow = 1)
+/turf/unsimulated/mineral/ChangeTurf(var/turf/N, var/tell_universe=1, var/force_lighting_update = 0, var/allow = 1, var/digsite_depressed = 0)
mineral_turfs -= src
- return ..(N, tell_universe, 1, allow)
-
+ var/datum/finds/old_finds = finddatum
+ . = ..(N, tell_universe, 1, allow)
+ if(digsite_depressed && istype(.,/turf/unsimulated/floor/asteroid))
+ var/turf/unsimulated/floor/asteroid/AS = .
+ if(old_finds)
+ AS.finddatum = old_finds
+ AS.finddatum.holder = makeweakref(AS)
+ if(AS.finddatum.archaeo_overlay)
+ var/image/I = image('icons/turf/walls.dmi',AS,AS.finddatum.archaeo_overlay)
+ I.color = color_finds()
+ AS.overlays += I
+ if(AS.finddatum.excav_overlay)
+ var/image/I = image('icons/turf/walls.dmi',AS,AS.finddatum.excav_overlay)
+ I.color = color_finds()
+ AS.overlays += I
/turf/unsimulated/mineral/ex_act(severity)
if(mining_difficulty > MINE_DIFFICULTY_TOUGH)
@@ -283,23 +289,15 @@ var/list/icon_state_to_appearance = list()
to_chat(user, "You don't have the dexterity to do this!")
return
- if (istype(W, /obj/item/device/core_sampler))
- if(!geologic_data)
- geologic_data = new/datum/geosample(src)
- geologic_data.UpdateNearbyArtifactInfo(src)
+ if (istype(W, /obj/item/device/core_sampler) && finddatum)
+ if(!finddatum.geologic_data)
+ finddatum.geologic_data = new/datum/geosample(src)
+ finddatum.geologic_data.UpdateNearbyArtifactInfo(src)
var/obj/item/device/core_sampler/C = W
C.sample_item(src, user)
return
- if (istype(W, /obj/item/device/depth_scanner))
- var/obj/item/device/depth_scanner/C = W
- C.scan_atom(user, src)
- return
-
- if (istype(W, /obj/item/device/measuring_tape))
- var/obj/item/device/measuring_tape/P = W
- user.visible_message("[user] extends [P] towards [src].","You extend [P] towards [src].")
- to_chat(user, "[bicon(P)] [src] has been excavated to a depth of [excavation_level]cm.")
+ if(finddatum && finddatum.handle_attackby(W,user))
return
if(istype(W,/obj/item/stack/sheet/metal))
@@ -342,109 +340,45 @@ var/list/icon_state_to_appearance = list()
P.playtoolsound(user, 20)
- var/broke_find = FALSE
- //handle any archaeological finds we might uncover
- if (finds && finds.len != 0)
- var/datum/find/top_find = finds[1]
-
- var/exc_diff = excavation_level + P.excavation_amount - top_find.excavation_required
-
- if (exc_diff > 0)
- // Digging too far, probably breaking the artifact.
- var/fail_message = "[pick("There is a crunching noise","[W] collides with some different rock","Part of the rock face crumbles away","Something breaks under [W]")]"
- to_chat(user, "[fail_message].")
- broke_find = TRUE
-
- var/destroy_prob = 50
- if (exc_diff > 5)
- destroy_prob = 95
-
- if (prob(destroy_prob))
- finds.Remove(top_find)
- if (prob(40))
- artifact_debris()
-
- else
- excavate_find(5, top_find)
+ var/broke_find = finddatum ? finddatum.exceed_depth(P,user,P.depresses_digsites) : FALSE
busy = 1
if(do_after(user, src, max((MINE_DURATION * P.toolspeed),minimum_mine_time)) && user)
busy = 0
- if(finds && finds.len && !broke_find)
- var/datum/find/F = finds[1]
- if(round(excavation_level + P.excavation_amount) == F.excavation_required)
- excavate_find(100, F)
-
- else if(excavation_level + P.excavation_amount > F.excavation_required - F.clearance_range)
- excavate_find(0, F)
+ if(finddatum)
+ finddatum.drill_find(P,broke_find,P.depresses_digsites)
- if( excavation_level + P.excavation_amount >= 100 )
-
- var/obj/structure/boulder/B
- var/artifact_destroyed = TRUE
- if(artifact_find)
- if(excavation_level > 0)
-
- B = new /obj/structure/boulder(src)
- B.geological_data = geologic_data
-
- B.artifact_find = artifact_find
- B.investigation_log(I_ARTIFACT, "|| [artifact_find.artifact_find_type] - [artifact_find.artifact_id] found by [key_name(user)].")
- artifact_destroyed = FALSE
-
- else
- artifact_debris(1)
-
- else if(excavation_level > 0 && prob(15))
- B = new /obj/structure/boulder(src)
- B.geological_data = geologic_data
+ var/excalevel = finddatum ? finddatum.excavation_level : 0
+ if(excalevel + P.excavation_amount >= 100 )
+ var/artifact_destroyed = finddatum ? finddatum.spawn_boulder(user,P.depresses_digsites) : FALSE
if(P.has_slimes & SLIME_OIL)
for(var/turf/unsimulated/mineral/M in range(user,1))
- M.GetDrilled(safety_override = TRUE, driller = user, multiplier = (P.has_slimes & SLIME_PYRITE) ? 2 : 1)
+ M.GetDrilled(safety_override = TRUE, driller = user, multiplier = (P.has_slimes & SLIME_PYRITE) ? 2 : 1, digsitedepressed = P.depresses_digsites)
return
- GetDrilled(artifact_destroyed, multiplier = (P.has_slimes & SLIME_PYRITE) ? 2 : 1)
+ GetDrilled(artifact_destroyed, multiplier = (P.has_slimes & SLIME_PYRITE) ? 2 : 1, digsitedepressed = P.depresses_digsites)
return
- if(finds && finds.len)
- var/I = rand(1,100)
- if(I == 1)
- switch(polarstar)
- if(0)
- new/obj/item/weapon/gun/energy/polarstar(src)
- polarstar = 1
- visible_message("A gun was buried within!")
- if(1)
- new/obj/item/device/modkit/spur_parts(src)
- visible_message("Something came out of the wall! Looks like scrap metal.")
- polarstar = 2
-
- excavation_level += P.excavation_amount
-
- if(!archaeo_overlay && finds && finds.len)
- var/datum/find/F = finds[1]
- if(F.excavation_required <= excavation_level + F.view_range)
- archaeo_overlay = "overlay_archaeo[rand(1,3)]"
- overlays += archaeo_overlay
-
- var/update_excav_overlay = 0
-
- var/subtractions = 0
- while(excavation_level - 25*(subtractions + 1) >= 0 && subtractions < 3)
- subtractions++
- if(excavation_level - P.excavation_amount < subtractions * 25)
- update_excav_overlay = 1
-
- //update overlays displaying excavation level
- if( !(excav_overlay && excavation_level > 0) || update_excav_overlay )
- var/excav_quadrant = round(excavation_level / 25) + 1
- excav_overlay = "overlay_excv[excav_quadrant]_[rand(1,3)]"
- overlays += excav_overlay
+ if(finddatum)
+ if(finddatum.finds?.len)
+ var/I = rand(1,100)
+ if(I == 1)
+ switch(polarstar)
+ if(0)
+ new/obj/item/weapon/gun/energy/polarstar(src)
+ polarstar = 1
+ visible_message("A gun was buried within!")
+ if(1)
+ new/obj/item/device/modkit/spur_parts(src)
+ visible_message("Something came out of the wall! Looks like scrap metal.")
+ polarstar = 2
+
+ finddatum.update_excav_level(P)
/*
//drop some rocks
next_rock += P.excavation_amount * 10
@@ -490,7 +424,7 @@ var/list/icon_state_to_appearance = list()
* disabled after drilling (ie. gibtonite will be immediately disarmed).
* driller: Whatever is doing the drilling. Used for some messages.
*/
-/turf/unsimulated/mineral/proc/GetDrilled(var/artifact_fail = TRUE, var/safety_override = FALSE, var/atom/driller, var/multiplier = 1)
+/turf/unsimulated/mineral/proc/GetDrilled(var/artifact_fail = TRUE, var/safety_override = FALSE, var/atom/driller, var/multiplier = 1, var/digsitedepressed = 0)
if (mineral && mineral.result_amount)
if(multiplier >= 2 && fortune_multiplier >= 2)
for(var/i in 1 to round(fortune_multiplier*(multiplier/2)))
@@ -506,18 +440,11 @@ var/list/icon_state_to_appearance = list()
var/mob/living/simple_animal/hostile/asteroid/rockernaut/boss/R = new(src)
if(mineral)
R.possessed_ore = mineral.ore
+
//destroyed artifacts have weird, unpleasant effects
//make sure to destroy them before changing the turf though
- if(artifact_find && artifact_fail)
- var/datum/artifact_postmortem_data/destroyed = new(null, FALSE, TRUE)
- destroyed.artifact_id = artifact_find.artifact_id
- destroyed.last_loc = src
- destroyed.artifact_type = artifact_find.artifact_find_type
- if (artifact_find.artifact_find_type == /obj/machinery/artifact)
- destroyed.primary_effect = "???"
- destroyed.secondary_effect = "???"
- razed_large_artifacts[artifact_find.artifact_id] += destroyed
- ArtifactRepercussion(src, usr, "", "[artifact_find.artifact_find_type]")
+ if(!digsitedepressed && artifact_fail && finddatum)
+ finddatum.large_artifact_fail()
if(artifact_fail && !mineral)
if(prob(multiplier))
@@ -535,7 +462,7 @@ var/list/icon_state_to_appearance = list()
visible_message("An old dusty crate was buried within!")
DropAbandonedCrate()
- ChangeTurf(mined_type)
+ ChangeTurf(mined_type, digsite_depressed = digsitedepressed)
/turf/unsimulated/mineral/proc/DropAbandonedCrate()
var/crate_type = pick(valid_abandoned_crate_types)
@@ -549,53 +476,6 @@ var/list/icon_state_to_appearance = list()
return mineral_name
return null
-/turf/unsimulated/mineral/proc/excavate_find(var/prob_clean = 0, var/datum/find/F)
- //with skill or luck, players can cleanly extract finds
- //otherwise, they come out inside a chunk of rock
- var/obj/item/weapon/X
- if(prob_clean)
- X = F.create_find(src)
- else
- X = new /obj/item/weapon/strangerock(src, F)
- if(!geologic_data)
- geologic_data = new/datum/geosample(src)
- geologic_data.UpdateNearbyArtifactInfo(src)
- X:geologic_data = geologic_data
-
- finds.Remove(F)
-
-/turf/unsimulated/mineral/proc/artifact_debris(var/severity = 0)
- if(severity)
- switch(rand(1,3))
- if(1)
- var/obj/item/stack/sheet/metal/M = new /obj/item/stack/sheet/metal((src))
- M.amount = rand(5,25)
- if(2)
- var/obj/item/stack/sheet/plasteel/R = new(src)
- R.amount = rand(5,25)
- if(3)
- var/obj/item/stack/sheet/mineral/uranium/R = new(src)
- R.amount = rand(5,25)
- else
- switch(rand(1,5))
- if(1)
- var/obj/item/stack/rods/R = new(src)
- R.amount = rand(5,25)
- if(2)
- var/obj/item/stack/tile/metal/R = new(src)
- R.amount = rand(1,5)
- if(3)
- var/obj/item/stack/sheet/metal/M = new /obj/item/stack/sheet/metal((src))
- M.amount = rand(1,5)
- if(4)
- var/quantity = rand(1,3)
- for(var/i=0, iYou can't dig soft soil with \the [W].")
- return
-
- if (dug)
- to_chat(user, "This area has already been dug.")
- return
+ var/broke_find = FALSE
+ if(finddatum)
+ broke_find = finddatum.exceed_depth(used_digging,user)
+ else
+ if(!(used_digging.diggables & DIG_SOIL)) //if the pickaxe can't dig soil, we don't
+ to_chat(user, "You can't dig soft soil with \the [W].")
+ return
+
+ if (dug)
+ to_chat(user, "This area has already been dug.")
+ return
playsound(src, 'sound/effects/rustle1.ogg', 50, 1) //russle sounds sounded better
if(do_after(user, src, (MINE_DURATION * used_digging.toolspeed)) && user) //the better the drill, the faster the digging
- playsound(src, 'sound/items/shovel.ogg', 50, 1)
- gets_dug()
+ var/totaldug = used_digging.excavation_amount
+ if(finddatum)
+ finddatum.drill_find(used_digging,broke_find)
+ totaldug += finddatum.excavation_level
+ finddatum.update_excav_level(used_digging)
+ if(totaldug >= 100)
+ if(finddatum && finddatum.spawn_boulder(user))
+ finddatum.large_artifact_fail()
+ playsound(src, 'sound/items/shovel.ogg', 50, 1)
+ gets_dug()
else
..(W,user)
@@ -705,6 +608,8 @@ var/list/icon_state_to_appearance = list()
/turf/unsimulated/floor/asteroid/update_icon()
if(dug && ispath(sand_type, /obj/item/stack/ore/glass))
icon_state = "asteroid_dug"
+ overlays.Cut()
+ add_rock_overlay()
/turf/unsimulated/floor/asteroid/proc/gets_dug()
if(dug)
@@ -1093,7 +998,7 @@ var/list/icon_state_to_appearance = list()
det_time = 0
visible_message("The chain reaction was stopped! The gibtonite had [src.det_time] reactions left till the explosion!")
-/turf/unsimulated/mineral/gibtonite/GetDrilled(var/artifact_fail = TRUE, var/safety_override = FALSE, var/atom/driller, var/multiplier = 1)
+/turf/unsimulated/mineral/gibtonite/GetDrilled(var/artifact_fail = TRUE, var/safety_override = FALSE, var/atom/driller, var/multiplier = 1, var/digsitedepressed = 0)
if(stage == 0 && mineral.result_amount >= 1) //Gibtonite deposit is activated
playsound(src,'sound/effects/hit_on_shattered_glass.ogg',50,1)
explosive_reaction()
diff --git a/code/modules/mining/minerals.dm b/code/modules/mining/minerals.dm
index ac762ed10383..aeb53bfc4a1c 100644
--- a/code/modules/mining/minerals.dm
+++ b/code/modules/mining/minerals.dm
@@ -41,10 +41,11 @@ var/list/name_to_mineral
O.pixel_y = rand(-16,16) * PIXEL_MULTIPLIER
if(istype(O, /obj/item/stack/ore))
var/obj/item/stack/ore/OR = O
- if(!T.geologic_data)
- T.geologic_data = new/datum/geosample(T)
- T.geologic_data.UpdateNearbyArtifactInfo(T)
- OR.geologic_data = T.geologic_data
+ if(T.finddatum)
+ if(!T.finddatum.geologic_data)
+ T.finddatum.geologic_data = new/datum/geosample(T)
+ T.finddatum.geologic_data.UpdateNearbyArtifactInfo(T)
+ OR.geologic_data = T.finddatum.geologic_data
return O
/mineral/uranium
diff --git a/code/modules/research/xenoarchaeology/finds/finds_container.dm b/code/modules/research/xenoarchaeology/finds/finds_container.dm
new file mode 100644
index 000000000000..278e49583bee
--- /dev/null
+++ b/code/modules/research/xenoarchaeology/finds/finds_container.dm
@@ -0,0 +1,210 @@
+/datum/finds
+ var/datum/geosample/geologic_data
+ var/excavation_level = 0
+ var/list/finds = list()//no longer null to prevent those pesky runtime errors
+ // var/next_rock = 0
+ var/archaeo_overlay
+ var/excav_overlay
+ var/datum/artifact_find/artifact_find
+ var/datum/weakref/holder
+
+/datum/finds/New(turf/T)
+ ..()
+ holder = makeweakref(T)
+
+/datum/finds/proc/create_finds(datum/digsite/D)
+ if(prob(50)) //Single find
+ finds.Add(D.gen_find(rand(5,95)))
+ else if(prob(75)) //Two finds
+ finds.Add(D.gen_find(rand(5,45)))
+ finds.Add(D.gen_find(rand(55,95)))
+ else //Three finds!
+ finds.Add(D.gen_find(rand(5,30)))
+ finds.Add(D.gen_find(rand(35,75)))
+ finds.Add(D.gen_find(rand(75,95)))
+
+ update_archaeo_overlay()
+
+/datum/finds/proc/handle_attackby(obj/item/weapon/W, mob/user)
+ var/turf/unsimulated/T = holder.get()
+ if(!istype(T))
+ return
+ if (istype(W, /obj/item/device/depth_scanner))
+ var/obj/item/device/depth_scanner/C = W
+ C.scan_atom(user, T)
+ return TRUE
+
+ if (istype(W, /obj/item/device/measuring_tape))
+ var/obj/item/device/measuring_tape/P = W
+ user.visible_message("[user] extends [P] towards [T].","You extend [P] towards [T].")
+ to_chat(user, "[bicon(P)] [T] has been excavated to a depth of [excavation_level]cm.")
+ return TRUE
+ return FALSE
+
+/datum/finds/proc/exceed_depth(obj/item/weapon/pickaxe/P, mob/user, depresses_digsites = FALSE)
+ . = FALSE
+ if(!depresses_digsites && finds && finds.len)
+ var/datum/find/top_find = finds[1]
+
+ var/exc_diff = excavation_level + P.excavation_amount - top_find.excavation_required
+
+ if (exc_diff > 0)
+ // Digging too far, probably breaking the artifact.
+ var/fail_message = "[pick("There is a crunching noise","[P] collides with some different rock","Part of the rock face crumbles away","Something breaks under [P]")]"
+ to_chat(user, "[fail_message].")
+ . = TRUE
+
+ var/destroy_prob = 50
+ if (exc_diff > 5)
+ destroy_prob = 95
+
+ if (prob(destroy_prob))
+ finds.Remove(top_find)
+ if (prob(40))
+ artifact_debris()
+
+ else
+ excavate_find(5, top_find)
+
+/datum/finds/proc/drill_find(obj/item/weapon/pickaxe/P, broke_find, depresses_digsites = FALSE)
+ if(!depresses_digsites && finds && finds.len && !broke_find)
+ var/datum/find/F = finds[1]
+ if(round(excavation_level + P.excavation_amount) == F.excavation_required)
+ excavate_find(100, F)
+
+ else if(excavation_level + P.excavation_amount > F.excavation_required - F.clearance_range)
+ excavate_find(0, F)
+
+/datum/finds/proc/artifact_debris(var/severity = 0)
+ var/turf/unsimulated/T = holder.get()
+ if(!istype(T))
+ return
+ if(severity)
+ var/obj/item/stack/S
+ var/bigamount = rand(5,25)
+ switch(rand(1,3))
+ if(1)
+ S = new /obj/item/stack/sheet/metal(T)
+ if(2)
+ S = new /obj/item/stack/sheet/plasteel(T)
+ if(3)
+ S = new /obj/item/stack/sheet/mineral/uranium(T)
+ S.amount = bigamount
+ else
+ var/quantity = rand(1,3)
+ switch(rand(1,5))
+ if(1)
+ var/obj/item/stack/rods/R = new(T)
+ R.amount = rand(5,25)
+ if(2)
+ var/obj/item/stack/tile/metal/R = new(T)
+ R.amount = rand(1,5)
+ if(3)
+ var/obj/item/stack/sheet/metal/M = new(T)
+ M.amount = rand(1,5)
+ if(4)
+ for(var/i in 1 to quantity)
+ new /obj/item/weapon/shard(T)
+ if(5)
+ for(var/i in 1 to quantity)
+ new /obj/item/weapon/shard/plasma(T)
+
+/datum/finds/proc/excavate_find(var/prob_clean = 0, var/datum/find/F)
+ //with skill or luck, players can cleanly extract finds
+ //otherwise, they come out inside a chunk of rock
+ var/turf/unsimulated/T = holder.get()
+ if(!istype(T))
+ return
+ var/obj/item/weapon/X
+ if(prob_clean)
+ X = F.create_find(T)
+ else
+ X = new /obj/item/weapon/strangerock(T, F)
+ if(!geologic_data)
+ geologic_data = new/datum/geosample(T)
+ geologic_data.UpdateNearbyArtifactInfo(T)
+ X:geologic_data = geologic_data
+
+ finds.Remove(F)
+
+/datum/finds/proc/update_excav_level(obj/item/weapon/pickaxe/P)
+ if(excavation_level < 100) //sanity because not everything changes turf anymore, thank you sand
+ var/turf/unsimulated/T = holder.get()
+ if(!istype(T))
+ return
+ excavation_level += P.excavation_amount
+ if(excavation_level >= 100)
+ excavation_level = 100
+
+ update_archaeo_overlay()
+
+ var/update_excav_overlay = 0
+
+ var/subtractions = 0
+ while(excavation_level - 25*(subtractions + 1) >= 0 && subtractions < 3)
+ subtractions++
+ if(excavation_level - P.excavation_amount < subtractions * 25)
+ update_excav_overlay = 1
+
+ //update overlays displaying excavation level
+ if( !(excav_overlay && excavation_level > 0) || update_excav_overlay )
+ var/excav_quadrant = round(excavation_level / 25) + 1
+ excav_overlay = "overlay_excv[excav_quadrant]_[rand(1,3)]"
+ var/image/I = image('icons/turf/walls.dmi',T,excav_overlay)
+ I.color = T.color_finds()
+ T.overlays += I
+
+/datum/finds/proc/update_archaeo_overlay()
+ var/turf/unsimulated/T = holder.get()
+ if(!istype(T))
+ return
+ if(!archaeo_overlay && finds && finds.len)
+ //sometimes a find will be close enough to the surface to show
+ var/datum/find/F = finds[1]
+ if(F.excavation_required <= excavation_level + F.view_range)
+ archaeo_overlay = "overlay_archaeo[rand(1,3)]"
+ var/image/I = image('icons/turf/walls.dmi',T,archaeo_overlay)
+ I.color = T.color_finds()
+ T.overlays += I
+
+/datum/finds/proc/spawn_boulder(mob/user,depresses_digsites = FALSE)
+ var/turf/unsimulated/T = holder.get()
+ if(!istype(T))
+ return
+ var/obj/structure/boulder/B
+ . = TRUE
+ if(!depresses_digsites)
+ if(artifact_find)
+ if(excavation_level > 0)
+
+ B = new /obj/structure/boulder(T)
+ B.geological_data = geologic_data
+
+ B.artifact_find = artifact_find
+ B.investigation_log(I_ARTIFACT, "|| [artifact_find.artifact_find_type] - [artifact_find.artifact_id] found by [key_name(user)].")
+ . = FALSE
+
+ else
+ artifact_debris(1)
+
+ else if(!excavation_level > 0 && prob(15))
+ B = new /obj/structure/boulder(T)
+ B.geological_data = geologic_data
+
+
+/datum/finds/proc/large_artifact_fail()
+ var/turf/unsimulated/T = holder.get()
+ if(!istype(T))
+ return
+ //destroyed artifacts have weird, unpleasant effects
+ //make sure to destroy them before changing the turf though
+ if(artifact_find)
+ var/datum/artifact_postmortem_data/destroyed = new(null, FALSE, TRUE)
+ destroyed.artifact_id = artifact_find.artifact_id
+ destroyed.last_loc = T
+ destroyed.artifact_type = artifact_find.artifact_find_type
+ if (artifact_find.artifact_find_type == /obj/machinery/artifact)
+ destroyed.primary_effect = "???"
+ destroyed.secondary_effect = "???"
+ razed_large_artifacts[artifact_find.artifact_id] += destroyed
+ ArtifactRepercussion(T, usr, "", "[artifact_find.artifact_find_type]")
\ No newline at end of file
diff --git a/code/modules/research/xenoarchaeology/geosample.dm b/code/modules/research/xenoarchaeology/geosample.dm
index dfe8192d42f9..a15b3e0d531f 100644
--- a/code/modules/research/xenoarchaeology/geosample.dm
+++ b/code/modules/research/xenoarchaeology/geosample.dm
@@ -58,20 +58,20 @@
if(!container || !istype(container))
return
- if(container.artifact_find)
+ if(container.finddatum?.artifact_find)
artifact_distance = rand() // 0-1
- artifact_id = container.artifact_find.artifact_id
+ artifact_id = container.finddatum.artifact_find.artifact_id
return
if(!SSxenoarch) //Sanity check due to runtimes ~Z
return
for(var/turf/unsimulated/mineral/T in SSxenoarch.artifact_spawning_turfs)
- if(T.artifact_find)
+ if(T.finddatum?.artifact_find)
var/cur_dist = sqrt(get_dist_squared(container, T))
if(artifact_distance < 0 || cur_dist < artifact_distance)
artifact_distance = cur_dist + rand() * 2 - 1
- artifact_id = T.artifact_find.artifact_id
+ artifact_id = T.finddatum.artifact_find.artifact_id
else
SSxenoarch.artifact_spawning_turfs.Remove(T)
diff --git a/code/modules/research/xenoarchaeology/misc.dm b/code/modules/research/xenoarchaeology/misc.dm
index 22ff874b6a90..fbb96ebeb726 100644
--- a/code/modules/research/xenoarchaeology/misc.dm
+++ b/code/modules/research/xenoarchaeology/misc.dm
@@ -12,6 +12,9 @@
archaeo_types[initial(F.find_ID)] = i
for(var/turf/unsimulated/mineral/M in mineral_turfs)
+ if(!M.finddatum)
+ M.finddatum = new(M)
+
if(M.no_finds || !prob(XENOARCH_SPAWN_CHANCE))
continue
@@ -24,7 +27,7 @@
var/turf/unsimulated/mineral/archeo_turf = turfs_to_process[1]
for(var/turf/unsimulated/mineral/T in orange(1, archeo_turf))
- if(T.finds.len)
+ if(T.finddatum?.finds.len)
continue
if(T in processed_turfs)
@@ -36,31 +39,17 @@
turfs_to_process.Remove(archeo_turf)
processed_turfs.Add(archeo_turf)
- if(!archeo_turf.finds || !archeo_turf.finds.len)
-
- if(prob(50)) //Single find
- archeo_turf.finds.Add(D.gen_find(rand(5,95)))
- else if(prob(75)) //Two finds
- archeo_turf.finds.Add(D.gen_find(rand(5,45)))
- archeo_turf.finds.Add(D.gen_find(rand(55,95)))
- else //Three finds!
- archeo_turf.finds.Add(D.gen_find(rand(5,30)))
- archeo_turf.finds.Add(D.gen_find(rand(35,75)))
- archeo_turf.finds.Add(D.gen_find(rand(75,95)))
-
- //sometimes a find will be close enough to the surface to show
- var/datum/find/F = archeo_turf.finds[1]
-
- if(F.excavation_required <= F.view_range)
- archeo_turf.archaeo_overlay = "overlay_archaeo[rand(1,3)]"
- archeo_turf.overlays += archeo_turf.archaeo_overlay
+ if(!archeo_turf.finddatum)
+ archeo_turf.finddatum = new(archeo_turf)
+ if(!archeo_turf.finddatum.finds || !archeo_turf.finddatum.finds.len)
+ archeo_turf.finddatum.create_finds(D)
- if(!M.artifact_find && D.gen_large_artifacts && prob(ARTIFACT_SPAWN_CHANCE))
- M.artifact_find = new()
+ if(!M.finddatum.artifact_find && D.gen_large_artifacts && prob(ARTIFACT_SPAWN_CHANCE))
+ M.finddatum.artifact_find = new()
SSxenoarch.artifact_spawning_turfs.Add(M)
- if(isnull(M.geologic_data))
- M.geologic_data = new/datum/geosample(M)
+ if(isnull(M.finddatum.geologic_data))
+ M.finddatum.geologic_data = new/datum/geosample(M)
#undef XENOARCH_SPAWN_CHANCE
#undef XENOARCH_SPREAD_CHANCE
diff --git a/code/modules/research/xenoarchaeology/tools/tools_anoscanner.dm b/code/modules/research/xenoarchaeology/tools/tools_anoscanner.dm
index cc501c51d396..725b1e79c532 100644
--- a/code/modules/research/xenoarchaeology/tools/tools_anoscanner.dm
+++ b/code/modules/research/xenoarchaeology/tools/tools_anoscanner.dm
@@ -36,12 +36,12 @@
if(SSxenoarch) //Sanity check due to runtimes ~Z
for(var/turf/unsimulated/mineral/T in SSxenoarch.artifact_spawning_turfs)
- if(T.artifact_find)
+ if(T.finddatum?.artifact_find)
if(T.z == cur_turf.z)
var/cur_dist = sqrt(get_dist_squared(cur_turf, T))
- if((nearest_artifact_distance < 0 || cur_dist < nearest_artifact_distance) && cur_dist <= T.artifact_find.artifact_detect_range)
+ if((nearest_artifact_distance < 0 || cur_dist < nearest_artifact_distance) && cur_dist <= T.finddatum.artifact_find.artifact_detect_range)
nearest_artifact_distance = cur_dist + rand() * 2 - 1
- nearest_artifact_id = T.artifact_find.artifact_id
+ nearest_artifact_id = T.finddatum.artifact_find.artifact_id
else
SSxenoarch.artifact_spawning_turfs.Remove(T)
diff --git a/code/modules/research/xenoarchaeology/tools/tools_coresampler.dm b/code/modules/research/xenoarchaeology/tools/tools_coresampler.dm
index dfbb96e066a3..800097b77f07 100644
--- a/code/modules/research/xenoarchaeology/tools/tools_coresampler.dm
+++ b/code/modules/research/xenoarchaeology/tools/tools_coresampler.dm
@@ -40,10 +40,11 @@
var/datum/geosample/geo_data
if(istype(item_to_sample, /turf/unsimulated/mineral))
var/turf/unsimulated/mineral/T = item_to_sample
- T.geologic_data.UpdateNearbyArtifactInfo(T)
- geo_data = T.geologic_data
- var/excav_overlay = "overlay_excv1_[rand(1,3)]"
- T.overlays += excav_overlay
+ if(T.finddatum)
+ T.finddatum.geologic_data.UpdateNearbyArtifactInfo(T)
+ geo_data = T.finddatum.geologic_data
+ var/excav_overlay = "overlay_excv1_[rand(1,3)]"
+ T.overlays += excav_overlay
else if(istype(item_to_sample, /obj/item/weapon/strangerock))
var/obj/item/weapon/strangerock/O = item_to_sample
geo_data = O.geologic_data
diff --git a/code/modules/research/xenoarchaeology/tools/tools_depthscanner.dm b/code/modules/research/xenoarchaeology/tools/tools_depthscanner.dm
index 19ba072dff4f..a0e64eff4f06 100644
--- a/code/modules/research/xenoarchaeology/tools/tools_depthscanner.dm
+++ b/code/modules/research/xenoarchaeology/tools/tools_depthscanner.dm
@@ -25,40 +25,45 @@
/obj/item/device/depth_scanner/proc/scan_atom(var/mob/user, var/atom/A)
user.visible_message("[user] scans [A], the air around them humming gently.")
- if(istype(A,/turf/unsimulated/mineral))
- var/turf/unsimulated/mineral/M = A
- if(M.finds.len || M.artifact_find)
- for(var/mob/L in range(src, 1))
- to_chat(L, "[bicon(src)] [src] pings.")
- playsound(user, 'sound/machines/info.ogg', 20, 1)
- //create a new scanlog entry
- var/datum/depth_scan/D = new()
- D.coords = "[M.x-WORLD_X_OFFSET[M.z]].[rand(0,9)]:[M.y-WORLD_Y_OFFSET[M.z]].[rand(0,9)]:[10 * M.z].[rand(0,9)]"
- D.time = worldtime2text()
- D.record_index = positive_locations.len + 1
- D.material = M.mineral ? M.mineral.display_name : "Rock"
+ if(istype(A,/turf/unsimulated))
+ var/turf/unsimulated/M = A
+ if(M.finddatum)
+ if(M.finddatum.finds.len || M.finddatum.artifact_find)
+ for(var/mob/L in range(src, 1))
+ to_chat(L, "[bicon(src)] [src] pings.")
+ playsound(user, 'sound/machines/info.ogg', 20, 1)
+ //create a new scanlog entry
+ var/datum/depth_scan/D = new()
+ D.coords = "[M.x-WORLD_X_OFFSET[M.z]].[rand(0,9)]:[M.y-WORLD_Y_OFFSET[M.z]].[rand(0,9)]:[10 * M.z].[rand(0,9)]"
+ D.time = worldtime2text()
+ D.record_index = positive_locations.len + 1
+ D.material = "Rock"
+ if(istype(M,/turf/unsimulated/mineral))
+ var/turf/unsimulated/mineral/MI = M
+ if(MI.mineral)
+ D.material = MI.mineral.display_name
- //find the first artifact and store it
- if(M.finds.len)
- var/datum/find/F = M.finds[1]
- D.depth = F.excavation_required //0-100% and 0-100cm
- D.clearance = F.clearance_range
- D.material = F.responsive_reagent
- to_chat(user,"Anomaly depth: [F.excavation_required] cm")
- to_chat(user,"Clearance above anomaly depth: [F.clearance_range] cm")
- var/index = responsive_carriers.Find(F.responsive_reagent)
- if(index > 0 && index <= finds_as_strings.len)
- to_chat(user,"Anomaly material: [finds_as_strings[index]]")
+ //find the first artifact and store it
+ if(M.finddatum.finds.len)
+ var/datum/find/F = M.finddatum.finds[1]
+ D.depth = F.excavation_required //0-100% and 0-100cm
+ D.clearance = F.clearance_range
+ D.material = F.responsive_reagent
+ to_chat(user,"Anomaly depth: [F.excavation_required] cm")
+ to_chat(user,"Clearance above anomaly depth: [F.clearance_range] cm")
+ var/index = responsive_carriers.Find(F.responsive_reagent)
+ if(index > 0 && index <= finds_as_strings.len)
+ to_chat(user,"Anomaly material: [finds_as_strings[index]]")
+ else
+ to_chat(user,"Anomaly material: Unknown")
else
+ to_chat(user,"Anomaly depth: 0 cm")
+ to_chat(user,"Clearance above anomaly depth: 0 cm")
to_chat(user,"Anomaly material: Unknown")
- else
- to_chat(user,"Anomaly depth: 0 cm")
- to_chat(user,"Clearance above anomaly depth: 0 cm")
- to_chat(user,"Anomaly material: Unknown")
- positive_locations.Add(D)
- else
- playsound(user, 'sound/items/detscan.ogg', 10, 1)
+ positive_locations.Add(D)
+ else
+ playsound(user, 'sound/items/detscan.ogg', 10, 1)
else if(istype(A,/obj/structure/boulder))
var/obj/structure/boulder/B = A
diff --git a/code/modules/research/xenoarchaeology/tools/tools_digsitelocator.dm b/code/modules/research/xenoarchaeology/tools/tools_digsitelocator.dm
index e22571e5ad51..0805d2534fc7 100644
--- a/code/modules/research/xenoarchaeology/tools/tools_digsitelocator.dm
+++ b/code/modules/research/xenoarchaeology/tools/tools_digsitelocator.dm
@@ -31,37 +31,38 @@
return
cooldown = world.time
playtoolsound(src, 50)
- for(var/turf/unsimulated/mineral/M in range(7, user))
- if(M.finds.len)
- var/n = 0
- var/list/image/IS = list()
- var/totalfinds = M.finds.len
- for(var/datum/find/F in M.finds)
- n++
- var/image/I = image('icons/turf/mine_overlays.dmi', loc = M, icon_state = "find_overlay[rand(1,3)]", layer = UNDER_HUD_LAYER)
- IS.Add(I)
- I.color = color_from_find_reagent[F.responsive_reagent]
+ for(var/turf/unsimulated/M in range(7, user))
+ if(M.finddatum)
+ if(M.finddatum.finds.len)
+ var/n = 0
+ var/list/image/IS = list()
+ var/totalfinds = M.finddatum.finds.len
+ for(var/datum/find/F in M.finddatum.finds)
+ n++
+ var/image/I = image('icons/turf/mine_overlays.dmi', loc = M, icon_state = "find_overlay[rand(1,3)]", layer = UNDER_HUD_LAYER)
+ IS.Add(I)
+ I.color = color_from_find_reagent[F.responsive_reagent]
+ I.plane = HUD_PLANE
+ if(n > 1)
+ var/matrix/TR = matrix()
+ TR.Scale(((totalfinds + 1) - n) / totalfinds, ((totalfinds + 1) - n) / totalfinds)
+ I.transform = TR
+ var/list/col = rgb2num(I.color)
+ I.filters = filter(type="outline",color=rgb(255-col[1],255-col[2],255-col[3]))
+ C.images += I
+ spawn(1 SECONDS)
+ for(var/image/I in IS)
+ animate(I, alpha = 0, time = 4 SECONDS)
+ spawn(5 SECONDS)
+ for(var/image/I in IS)
+ if(C)
+ C.images -= I
+ if (adv && M.finddatum.artifact_find)
+ var/image/I = image('icons/turf/mine_overlays.dmi', loc = M, icon_state = "artifact_overlay", layer = UNDER_HUD_LAYER)
I.plane = HUD_PLANE
- if(n > 1)
- var/matrix/TR = matrix()
- TR.Scale(((totalfinds + 1) - n) / totalfinds, ((totalfinds + 1) - n) / totalfinds)
- I.transform = TR
- var/list/col = rgb2num(I.color)
- I.filters = filter(type="outline",color=rgb(255-col[1],255-col[2],255-col[3]))
C.images += I
- spawn(1 SECONDS)
- for(var/image/I in IS)
+ spawn(1 SECONDS)
animate(I, alpha = 0, time = 4 SECONDS)
- spawn(5 SECONDS)
- for(var/image/I in IS)
+ spawn(5 SECONDS)
if(C)
C.images -= I
- if (adv && M.artifact_find)
- var/image/I = image('icons/turf/mine_overlays.dmi', loc = M, icon_state = "artifact_overlay", layer = UNDER_HUD_LAYER)
- I.plane = HUD_PLANE
- C.images += I
- spawn(1 SECONDS)
- animate(I, alpha = 0, time = 4 SECONDS)
- spawn(5 SECONDS)
- if(C)
- C.images -= I
diff --git a/code/modules/trader/crates/lostcrate.dm b/code/modules/trader/crates/lostcrate.dm
new file mode 100644
index 000000000000..64261986dc0a
--- /dev/null
+++ b/code/modules/trader/crates/lostcrate.dm
@@ -0,0 +1,432 @@
+var/global/list/lemuria_stuff = list(
+ //3 of a kind
+ /obj/item/weapon/fakeposter_kit, /obj/item/weapon/fakeposter_kit, /obj/item/weapon/fakeposter_kit,
+ //2 of a kind
+ /obj/item/weapon/storage/bag/gibtonite,/obj/item/weapon/storage/bag/gibtonite,
+ /obj/item/device/digsite_depressor_modkit,/obj/item/device/digsite_depressor_modkit,
+ //1 of a kind
+ /obj/item/weapon/quantumroutingcomputer,
+ /obj/item/weapon/disk/shuttle_coords/vault/mecha_graveyard,
+ /obj/item/goliath_lure,
+ /obj/item/cosmic_grill/preloaded,
+ /obj/item/device/mule_painter
+)
+/obj/structure/closet/crate/lemuria
+ name = "Lost Crate of Lemuria"
+ desc = "Famously, Space Lemuria was once a sacred warehouse-planet among Cargo peoples, and the holiest city in the Cargo Cult. It was lost, along with most of its crates. Why has this one resurfaced now...? What does it mean?"
+
+/obj/structure/closet/crate/lemuria/New()
+ ..()
+ for(var/i = 1 to 5)
+ if(!shoal_stuff.len)
+ return
+ var/path = pick_n_take(lemuria_stuff)
+ new path(src)
+
+/obj/item/weapon/quantumroutingcomputer
+ name = "quantum routing computer"
+ desc = "A quantum supercomputer uses q-bits to perform very large calculations. This one can reduce shipping times dramatically by calculating the most efficient use of gravity wells along a route."
+ inhand_states = list("left_hand" = 'icons/mob/in-hand/left/boxes_and_storage.dmi', "right_hand" = 'icons/mob/in-hand/right/boxes_and_storage.dmi')
+ icon = 'icons/obj/items_weird.dmi'
+ icon_state = "quantumrouter"
+ item_state = "box_of_doom"
+
+/obj/item/weapon/quantumroutingcomputer/preattack(var/atom/A, var/mob/user, proximity_flag)
+ if(proximity_flag != 1)
+ return
+ if(istype(A,/obj/machinery/computer/supplycomp))
+ visible_message("You add \the [src] to \the [A]. It sets to work calculating a faster route.")
+ SSsupply_shuttle.movetime /= 2
+ playsound(src, 'sound/items/Deconstruct.ogg', 50, 1)
+ qdel(src)
+
+/area/vault/mecha_graveyard
+
+/obj/item/weapon/disk/shuttle_coords/vault/mecha_graveyard
+ name = "Coordinates to the Mecha Graveyard"
+ desc = "Here lay the dead steel of lost mechas, so says some gypsy."
+ destination = /obj/docking_port/destination/vault/mecha_graveyard
+
+/obj/docking_port/destination/vault/mecha_graveyard
+ areaname = "mecha graveyard"
+
+/datum/map_element/dungeon/mecha_graveyard
+ file_path = "maps/randomvaults/dungeons/mecha_graveyard.dmm"
+ unique = TRUE
+
+/obj/effect/decal/mecha_wreckage/graveyard_ripley
+ name = "Ripley wreckage"
+ desc = "Surprisingly well preserved."
+ icon_state = "ripley-broken"
+
+/obj/effect/decal/mecha_wreckage/graveyard_ripley/New()
+ ..()
+ var/list/parts = list(/obj/item/mecha_parts/part/ripley_torso,
+ /obj/item/mecha_parts/part/ripley_left_arm,
+ /obj/item/mecha_parts/part/ripley_right_arm,
+ /obj/item/mecha_parts/part/ripley_left_leg,
+ /obj/item/mecha_parts/part/ripley_right_leg)
+ welder_salvage += parts
+
+ if(prob(80))
+ add_salvagable_equipment(new /obj/item/mecha_parts/mecha_equipment/tool/drill,100)
+ else
+ add_salvagable_equipment(new /obj/item/mecha_parts/mecha_equipment/tool/drill/diamonddrill,100)
+ add_salvagable_equipment(new /obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp,100)
+ add_salvagable_equipment(new /obj/item/mecha_parts/mecha_equipment/jetpack,100)
+
+/obj/effect/decal/mecha_wreckage/graveyard_clarke
+ name = "Clarke wreckage"
+ desc = "Surprisingly well preserved."
+ icon_state = "clarke-broken"
+
+/obj/effect/decal/mecha_wreckage/graveyard_clarke/New()
+ ..()
+ var/list/parts = list(
+ /obj/item/mecha_parts/part/clarke_torso,
+ /obj/item/mecha_parts/part/clarke_head,
+ /obj/item/mecha_parts/part/clarke_left_arm,
+ /obj/item/mecha_parts/part/clarke_right_arm,
+ /obj/item/mecha_parts/part/clarke_left_tread,
+ /obj/item/mecha_parts/part/clarke_right_tread)
+ welder_salvage += parts
+
+ add_salvagable_equipment(new /obj/item/mecha_parts/mecha_equipment/tool/collector,100)
+ add_salvagable_equipment(new /obj/item/mecha_parts/mecha_equipment/tool/tiler,100)
+ add_salvagable_equipment(new /obj/item/mecha_parts/mecha_equipment/tool/switchtool,100)
+
+/obj/item/weapon/fakeposter_kit
+ name = "cargo cache kit"
+ desc = "Used to create a hidden cache behind what appears to be a cargo poster."
+ icon = 'icons/obj/barricade.dmi'
+ icon_state = "barricade_kit"
+ w_class = W_CLASS_MEDIUM
+ w_type = RECYK_WOOD
+ flammable = TRUE
+
+/obj/item/weapon/fakeposter_kit/preattack(atom/target, mob/user , proximity)
+ if(!proximity)
+ return
+ if(istype(target,/turf/simulated/wall))
+ playsound(user.loc, 'sound/effects/shieldbash.ogg', 50, 1)
+ if(do_after(user,target,4 SECONDS))
+ to_chat(user,"Using the kit, you hollow out the wall and hang the poster in front.")
+ var/obj/structure/fakecargoposter/FCP = new(target)
+ FCP.access_loc = get_turf(user)
+ qdel(src)
+ return 1
+ else
+ return ..()
+
+/obj/structure/fakecargoposter
+ icon = 'icons/obj/posters.dmi'
+ var/obj/item/weapon/storage/cargocache/cash
+ var/turf/access_loc
+
+/obj/structure/fakecargoposter/New()
+ ..()
+ var/datum/poster/type = pick(/datum/poster/special/cargoflag,/datum/poster/special/cargofull)
+ icon_state = initial(type.icon_state)
+ desc = initial(type.desc)
+ name = initial(type.name)
+ cash = new(src)
+
+/obj/structure/fakecargoposter/examine(mob/user)
+ ..()
+ if(user.loc == access_loc)
+ to_chat(user, "Upon closer inspection, there's a hidden cache behind it accessible with a free hand.")
+
+/obj/structure/fakecargoposter/Destroy()
+ for(var/atom/movable/A in cash.contents)
+ A.forceMove(loc)
+ QDEL_NULL(cash)
+ ..()
+
+/obj/structure/fakecargoposter/attackby(var/obj/item/weapon/W, mob/user)
+ if(iswelder(W))
+ visible_message("[user] is destroying the hidden cache disguised as a poster!")
+ var/obj/item/tool/weldingtool/WT=W
+ if(WT.do_weld(user, src, 10 SECONDS, 5))
+ visible_message("[user] destroyed the hidden cache!")
+ qdel(src)
+ else if(user.loc == access_loc)
+ cash.attackby(W,user)
+ else
+ ..()
+
+/obj/structure/fakecargoposter/attack_hand(mob/user)
+ if(user.loc == access_loc)
+ cash.AltClick(user)
+
+/obj/item/weapon/storage/cargocache
+ name = "cargo cache"
+ desc = "A large hidey hole for all your goodies."
+ icon = 'icons/obj/posters.dmi'
+ icon_state = "cargoposter-flag"
+ fits_max_w_class = W_CLASS_LARGE
+ max_combined_w_class = 28
+ slot_flags = 0
+
+/obj/item/weapon/storage/cargocache/distance_interact(mob/user)
+ if(istype(loc,/obj/structure/fakecargoposter) && user.Adjacent(loc))
+ return TRUE
+ return FALSE
+
+/obj/item/weapon/storage/bag/gibtonite
+ name = "gibtonite satchel"
+ desc = "A satchel specifically designed for the transport of gibtonite. It has deep, padded pockets to keep it safe. The gibtonite needs to be disarmed first, of course."
+ can_only_hold = list("/obj/item/weapon/gibtonite")
+ fits_max_w_class = W_CLASS_LARGE
+ icon_state = "satchel-gibtonite"
+ item_state = "engiepack"
+
+/obj/item/weapon/storage/bag/gibtonite/can_be_inserted(obj/item/W, stop_messages = 0)
+ if(!..())
+ return FALSE
+ var/obj/item/weapon/gibtonite/G = W
+ if(istype(G) && !G.primed)
+ return TRUE
+
+/obj/item/goliath_lure
+ name = "goliath lure"
+ desc = "Goliaths have a sophisticated set of eyes that can see infrared. This emits beams that will attract goliaths. After placing it on the ground, wrench it into place. Use meat on the lure to create bait."
+ var/pity = 0
+ icon = 'icons/obj/items_weird.dmi'
+ icon_state = "goliathlure"
+ w_class = W_CLASS_LARGE
+
+/obj/item/goliath_lure/attackby(obj/item/I, mob/user)
+ if(I.is_wrench() && do_after(user, src, 2 SECONDS))
+ if(!istype(loc,/turf/unsimulated/floor/asteroid))
+ to_chat(user, "\The [src] won't sink into anything but the soft sand of the asteroid.")
+ return
+ anchored = !anchored
+ if(anchored)
+ to_chat(user, "\The [src] thrums with activity after being anchored. It is running.")
+ processing_objects += src
+ else
+ to_chat(user, "\The [src] stills as you unanchor it.")
+ processing_objects -= src
+ if(istype(I, /obj/item/weapon/reagent_containers/food/snacks/meat))
+ to_chat(user, "You create some bait at the base of \the [src].")
+ new /mob/living/simple_animal/bait(loc)
+ qdel(I)
+
+/obj/item/goliath_lure/Destroy()
+ processing_objects -= src
+ ..()
+
+/obj/item/goliath_lure/process()
+ if(!anchored)
+ processing_objects -= src
+ return
+ pity++
+ if(prob(pity) && isturf(loc))
+ pity = 0
+ create_goliath()
+
+
+/obj/item/goliath_lure/proc/create_goliath()
+ var/turf/target_ground
+ var/list/mid_search_group = orange(7,src)
+ var/list/far_grounds = orange(12,src) - mid_search_group
+ var/list/near_grounds = orange(3,src)
+ //Create 3 oranges: 8 to 12, 4 to 7, and 1 to 3. Prefer the furthest.
+ //Needs to not be a space or dense turf, must have a valid path to the lure.
+
+ target_ground = check_turfs(shuffle(far_grounds)) //shuffle is necessary or else the goliath will always approach from the same direction
+
+ if(!target_ground)
+ var/list/mid_grounds = mid_search_group - near_grounds
+ target_ground = check_turfs(shuffle(mid_grounds))
+
+ if(!target_ground)
+ target_ground = check_turfs(shuffle(near_grounds))
+
+ if(!target_ground)
+ log_debug("Goliath lure could not find a spawn position.")
+ return
+ var/mob/living/simple_animal/hostile/asteroid/goliath/G = new (target_ground)
+ G.shake(1,3)
+ var/mob/bait = locate(/mob/living/simple_animal/bait) in view(2,loc)
+ if(bait)
+ G.GiveTarget(bait)
+ else
+ G.Goto(target_ground,G.move_to_delay,G.idle_vision_range) //Move toward the lure, but stop at idle vision range
+
+/obj/item/goliath_lure/proc/check_turfs(var/list/grounds)
+ for(var/turf/T in grounds)
+ if(!istype(T,/turf/unsimulated/floor/asteroid))
+ continue
+ if(T.density)
+ continue
+ if(locate(/mob) in T)
+ continue
+ if(!pathfind(T,loc))
+ continue
+ return T
+
+//Extremely primative pathfinding, only looks for a straight line
+/obj/item/goliath_lure/proc/pathfind(turf/A, turf/B)
+ var/turf/T = A
+ for(var/i = 1 to 12) //max range is 12
+ var/turf/Tx = get_step_towards(T, B) //Step toward B
+ if(Tx == B)
+ return TRUE
+ if(Tx.density)
+ return FALSE
+ for(var/obj/O in T)
+ if(O.density)
+ return FALSE
+ T = Tx
+
+/mob/living/simple_animal/bait
+ name = "bait"
+ desc = "This is bait. There isn't even a hook in this one!"
+ icon = 'icons/effects/blood.dmi'
+ icon_state = "gib2-old"
+ icon_living = "gib2-old"
+ pass_flags = PASSTABLE
+ maxHealth = 1
+ health = 1
+ response_help = "adjusts"
+ response_disarm = "prods"
+ response_harm = "beats"
+ faction = "neutral"
+ density = 0
+ minbodytemp = 0
+ maxbodytemp = INFINITY
+ min_oxy = 0
+ max_oxy = 0
+ min_tox = 0
+ max_tox = 0
+ min_co2 = 0
+ max_co2 = 0
+ min_n2 = 0
+ max_n2 = 0
+ treadmill_speed = 0
+ wander = 0
+ size = SIZE_TINY
+
+/mob/living/simple_animal/bait/New()
+ . = ..()
+ var/mob/living/simple_animal/hostile/asteroid/goliath/G = locate() in view(12,loc)
+ if(G)
+ G.GiveTarget(src)
+
+/mob/living/simple_animal/bait/death(gibbed)
+ ..(TRUE)
+ qdel(src)
+
+/mob/living/simple_animal/bait/can_be_pulled(mob/user)
+ return FALSE
+
+/obj/item/cosmic_grill
+ name = "cosmic grill"
+ desc = "A grilltop that uses stellar radiation to cook meals: just float it in space and the pan will heat up! This is the go-to for the miner that wants to cook some asteroid cuisine."
+ is_cooktop = TRUE
+ icon = 'icons/obj/items_weird.dmi'
+ icon_state = "cosmicgrill0"
+ w_class = W_CLASS_MEDIUM
+
+/obj/item/cosmic_grill/update_icon()
+ icon_state = "cosmicgrill[!isnull(cookvessel)]"
+ render_cookvessel()
+
+/obj/item/cosmic_grill/on_cook_start()
+ icon_state = "cosmicgrill1"
+
+/obj/item/cosmic_grill/on_cook_stop()
+ icon_state = "cosmicgrill0"
+
+/obj/item/cosmic_grill/can_cook()
+ return istype(loc, /turf/space)
+
+/obj/item/cosmic_grill/render_cookvessel(offset_x, offset_y = 6)
+ overlays.len = 0
+ ..()
+
+/obj/item/cosmic_grill/preloaded/New()
+ ..()
+ cookvessel = new /obj/item/weapon/reagent_containers/pan(src)
+ update_icon()
+
+/obj/item/device/digsite_depressor_modkit
+ name = "digsite depressor modification kit"
+ desc = "A kit containing all the needed tools and parts to make mining drills shove archaeological digsites into the ground beneath."
+ icon_state = "modkit"
+ inhand_states = list("left_hand" = 'icons/mob/in-hand/left/newsprites_lefthand.dmi', "right_hand" = 'icons/mob/in-hand/right/newsprites_righthand.dmi')
+ origin_tech = Tc_MATERIALS + "=2;" + Tc_ENGINEERING + "=2"
+ toolsounds = list('sound/items/Screwdriver.ogg')
+
+/obj/item/weapon/pickaxe
+ var/depresses_digsites = FALSE
+
+/obj/item/weapon/pickaxe/New()
+ . = ..()
+ update_icon()
+
+/obj/item/weapon/pickaxe/update_icon()
+ overlays.Cut()
+ if(depresses_digsites)
+ overlays += "digsite_depressor"
+ . = ..()
+
+/obj/item/weapon/pickaxe/drill/digdepress
+ depresses_digsites = TRUE
+
+/obj/item/weapon/pickaxe/drill/diamond/digdepress
+ depresses_digsites = TRUE
+
+/obj/item/weapon/pickaxe/examine(mob/user, size, show_name)
+ . = ..()
+ if(depresses_digsites)
+ to_chat(user, "\The [src] can depress digsites into the ground when drilling them.")
+
+/obj/item/device/digsite_depressor_modkit/afterattack(obj/O, mob/user as mob)
+ if(!istype(O,/obj/item/weapon/pickaxe/drill))
+ to_chat(user, "This only works on mining drills.")
+ return
+ if(!isturf(O.loc))
+ to_chat(user, "\The [O] must be safely placed on the ground for modification.")
+ return
+ var/obj/item/weapon/pickaxe/drill/D = O
+ if(D.depresses_digsites)
+ to_chat(user, "\The [O] is already modified to depress digsites.")
+ return
+ playtoolsound(user.loc, 100)
+ D.depresses_digsites = TRUE
+ user.visible_message("[user] opens \the [src] and modifies \the [O] to depress digsites.","You open \the [src] and modify \the [O] to depress digsites.")
+ D.overlays += "depressor_activate"
+ spawn(5)
+ D.update_icon()
+ qdel(src)
+
+/obj/item/device/mule_painter
+ name = "\improper MULEbot painter"
+ desc = "A device used to paint MULEbots in various colours and fashions."
+ icon = 'icons/obj/RCD.dmi'
+ icon_state = "rpd"//placeholder art, someone please sprite it
+ force = 0
+
+/obj/item/device/mule_painter/afterattack(var/obj/machinery/bot/mulebot/M, var/mob/user)
+ if(!istype(M))
+ return 0
+ if (!M.bot_sprites.len)
+ to_chat(user, "This MULEbot has no other paint-jobs. Some coder probably deleted them all, please report this.")
+ return 1
+
+ var/icontype = input("Select the paint-job!")in M.bot_sprites
+ icontype = "mulebot[icontype != "default" ? "_[icontype]" : ""]"
+ //Sanity checks because icontype can be selected at an arbitrary amount of time.
+ if(!user.Adjacent(M) || user.incapacitated() || user.lying)
+ return 1
+ if(icontype == M.icon_initial)
+ to_chat(user, "This mech is already painted in that style.")
+ return 1
+ if(icontype)
+ to_chat(user, "You paint the MULEbot.")
+ M.icon_initial = icontype
+ M.icon_state = icontype
+ playsound(src, 'sound/effects/spray3.ogg', 15, 1)
+ return 1
\ No newline at end of file
diff --git a/code/modules/trader/trade_datums.dm b/code/modules/trader/trade_datums.dm
index 3724cd0904db..ef8ea02ca381 100644
--- a/code/modules/trader/trade_datums.dm
+++ b/code/modules/trader/trade_datums.dm
@@ -71,6 +71,13 @@
maxunits = 3
sales_category = TRADE_VARIETY
+/datum/trade_product/lostlemuria
+ name = "Lost Crate of Lemuria"
+ path = /obj/structure/closet/crate/lemuria
+ baseprice = 160
+ maxunits = 2
+ sales_category = TRADE_VARIETY
+
/datum/trade_product/babel
name = "Library of Babel shipment"
path = /obj/structure/closet/crate/library
@@ -78,11 +85,6 @@
maxunits = 5
sales_category = TRADE_VARIETY
-/datum/trade_product/mechagy
- name = "Mecha Graveyard shuttle disk"
- path = /obj/item/weapon/disk/shuttle_coords/vault/mecha_graveyard
- baseprice = 100
-
/datum/trade_product/mechexpac
name = "exosuit expansion kit"
path = /obj/item/weapon/mech_expansion_kit
@@ -103,11 +105,6 @@
maxunits = 2
restocks_left = 3
-/datum/trade_product/fakeposter
- name = "cargo cache kit"
- path = /obj/item/weapon/fakeposter_kit
- baseprice = 50
-
/datum/trade_product/yantarcrate
name = "Yantar medical crate"
path = /obj/structure/closet/crate/medical/yantar
diff --git a/icons/obj/aibots.dmi b/icons/obj/aibots.dmi
index 7bafb6811086..675a0d1ec592 100644
Binary files a/icons/obj/aibots.dmi and b/icons/obj/aibots.dmi differ
diff --git a/icons/obj/items.dmi b/icons/obj/items.dmi
index 46c0a16fc211..1aab647c4ffa 100644
Binary files a/icons/obj/items.dmi and b/icons/obj/items.dmi differ
diff --git a/icons/obj/items_weird.dmi b/icons/obj/items_weird.dmi
index 6439960e2367..e866f33affc6 100644
Binary files a/icons/obj/items_weird.dmi and b/icons/obj/items_weird.dmi differ
diff --git a/icons/obj/storage/storage.dmi b/icons/obj/storage/storage.dmi
index aa136f10be06..38e5ef79bc0d 100644
Binary files a/icons/obj/storage/storage.dmi and b/icons/obj/storage/storage.dmi differ
diff --git a/vgstation13.dme b/vgstation13.dme
index aca0c862f865..bcb4e4b83a01 100644
--- a/vgstation13.dme
+++ b/vgstation13.dme
@@ -2664,6 +2664,7 @@
#include "code\modules\research\xenoarchaeology\artifact\triggers\unknown_trigger_visible.dm"
#include "code\modules\research\xenoarchaeology\finds\digsites.dm"
#include "code\modules\research\xenoarchaeology\finds\finds.dm"
+#include "code\modules\research\xenoarchaeology\finds\finds_container.dm"
#include "code\modules\research\xenoarchaeology\finds\finds_defines.dm"
#include "code\modules\research\xenoarchaeology\finds\finds_fossils.dm"
#include "code\modules\research\xenoarchaeology\finds\finds_guitar.dm"
@@ -2900,6 +2901,7 @@
#include "code\modules\trader\trade_window.dm"
#include "code\modules\trader\crates\alcatrazfour.dm"
#include "code\modules\trader\crates\cloudnine.dm"
+#include "code\modules\trader\crates\lostcrate.dm"
#include "code\modules\trader\crates\misc_variety.dm"
#include "code\modules\trader\crates\shoaljunk.dm"
#include "code\modules\trader\crates\yantar.dm"