var/list/mining_overlay_cache = list() /**********************Mineral deposits**************************/ /turf/unsimulated/mineral name = "impassable rock" icon = 'icons/turf/walls.dmi' icon_state = "rock-dark" density = 1 opacity = 1 // YW edit. Stops all my unsimulated tiles from being seethrough. /turf/unsimulated/mineral/ice name = "Ice wall" desc = "Frigid Ice that seems to be stronger then most manmade structures" icon = 'icons/turf/snow_new.dmi' icon_state = "Icerock" /turf/simulated/mineral //wall piece name = "rock" icon = 'icons/turf/walls.dmi' icon_state = "rock" var/rock_side_icon_state = "rock_side" var/sand_icon_state = "asteroid" var/rock_icon_state = "rock" var/random_icon = 0 oxygen = 0 nitrogen = 0 opacity = 1 density = 1 blocks_air = 1 temperature = T0C can_dirty = FALSE var/ore/mineral var/sand_dug var/mined_ore = 0 var/last_act = 0 var/overlay_detail var/datum/geosample/geologic_data var/excavation_level = 0 var/list/finds var/next_rock = 0 var/archaeo_overlay = "" var/excav_overlay = "" var/obj/item/weapon/last_find var/datum/artifact_find/artifact_find var/ignore_mapgen var/ore_types = list( "hematite" = /obj/item/weapon/ore/iron, "uranium" = /obj/item/weapon/ore/uranium, "gold" = /obj/item/weapon/ore/gold, "silver" = /obj/item/weapon/ore/silver, "diamond" = /obj/item/weapon/ore/diamond, "phoron" = /obj/item/weapon/ore/phoron, "osmium" = /obj/item/weapon/ore/osmium, "hydrogen" = /obj/item/weapon/ore/hydrogen, "silicates" = /obj/item/weapon/ore/glass, "carbon" = /obj/item/weapon/ore/coal, "verdantium" = /obj/item/weapon/ore/verdantium, "marble" = /obj/item/weapon/ore/marble, "lead" = /obj/item/weapon/ore/lead ) has_resources = 1 // Alternative rock wall sprites. /turf/simulated/mineral/light icon_state = "rock-light" rock_side_icon_state = "rock_side-light" sand_icon_state = "sand-light" rock_icon_state = "rock-light" random_icon = 1 /turf/simulated/mineral/ignore_mapgen ignore_mapgen = 1 /turf/simulated/mineral/floor name = "sand" icon = 'icons/turf/flooring/asteroid.dmi' icon_state = "asteroid" density = 0 opacity = 0 blocks_air = 0 can_build_into_floor = TRUE //Alternative sand floor sprite. turf/simulated/mineral/floor/light icon_state = "sand-light" sand_icon_state = "sand-light" turf/simulated/mineral/floor/light_border icon_state = "sand-light-border" sand_icon_state = "sand-light-border" turf/simulated/mineral/floor/light_nub icon_state = "sand-light-nub" sand_icon_state = "sand-light-nub" turf/simulated/mineral/floor/light_corner icon_state = "sand-light-corner" sand_icon_state = "sand-light-corner" /turf/simulated/mineral/floor/ignore_mapgen ignore_mapgen = 1 /turf/simulated/mineral/proc/make_floor() if(!density && !opacity) return density = 0 opacity = 0 blocks_air = 0 can_build_into_floor = TRUE update_general() /turf/simulated/mineral/proc/make_wall() if(density && opacity) return density = 1 opacity = 1 blocks_air = 1 can_build_into_floor = FALSE update_general() /turf/simulated/mineral/proc/update_general() update_icon(1) recalc_atom_opacity() if(ticker && ticker.current_state == GAME_STATE_PLAYING) reconsider_lights() if(air_master) air_master.mark_for_update(src) /turf/simulated/mineral/Entered(atom/movable/M as mob|obj) . = ..() if(istype(M,/mob/living/silicon/robot)) var/mob/living/silicon/robot/R = M if(R.module) for(var/obj/item/weapon/storage/bag/ore/O in list(R.module_state_1, R.module_state_2, R.module_state_3)) attackby(O, R) return /turf/simulated/mineral/proc/get_cached_border(var/cache_id, var/direction, var/icon_file, var/icon_state, var/offset = 32) //Cache miss if(!mining_overlay_cache["[cache_id]_[direction]"]) var/image/new_cached_image = image(icon_state, dir = direction, layer = ABOVE_TURF_LAYER) switch(direction) if(NORTH) new_cached_image.pixel_y = offset if(SOUTH) new_cached_image.pixel_y = -offset if(EAST) new_cached_image.pixel_x = offset if(WEST) new_cached_image.pixel_x = -offset mining_overlay_cache["[cache_id]_[direction]"] = new_cached_image return new_cached_image //Cache hit return mining_overlay_cache["[cache_id]_[direction]"] /turf/simulated/mineral/Initialize() . = ..() if(prob(20)) overlay_detail = "asteroid[rand(0,9)]" update_icon(1) if(density && mineral) . = INITIALIZE_HINT_LATELOAD if(random_icon) dir = pick(alldirs) . = INITIALIZE_HINT_LATELOAD /turf/simulated/mineral/LateInitialize() if(density && mineral) MineralSpread() /turf/simulated/mineral/update_icon(var/update_neighbors) cut_overlays() //We are a wall (why does this system work like this??) if(density) if(mineral) name = "[mineral.display_name] deposit" else name = "rock" icon = 'icons/turf/walls.dmi' icon_state = rock_icon_state //Apply overlays if we should have borders for(var/direction in cardinal) var/turf/T = get_step(src,direction) if(istype(T) && !T.density) add_overlay(get_cached_border(rock_side_icon_state,direction,icon,rock_side_icon_state)) if(archaeo_overlay) add_overlay(archaeo_overlay) if(excav_overlay) add_overlay(excav_overlay) //We are a sand floor else name = "sand" icon = 'icons/turf/flooring/asteroid.dmi' icon_state = sand_icon_state if(sand_dug) add_overlay("dug_overlay") //Apply overlays if there's space for(var/direction in cardinal) if(istype(get_step(src, direction), /turf/space) && !istype(get_step(src, direction), /turf/space/cracked_asteroid)) add_overlay(get_cached_border("asteroid_edge",direction,icon,"asteroid_edges", 0)) //Or any time else var/turf/T = get_step(src, direction) if(istype(T) && T.density) add_overlay(get_cached_border(rock_side_icon_state,direction,'icons/turf/walls.dmi',rock_side_icon_state)) if(overlay_detail) add_overlay('icons/turf/flooring/decals.dmi',overlay_detail) if(update_neighbors) for(var/direction in alldirs) if(istype(get_step(src, direction), /turf/simulated/mineral)) var/turf/simulated/mineral/M = get_step(src, direction) M.update_icon() /turf/simulated/mineral/ex_act(severity) switch(severity) if(2.0) if (prob(70)) mined_ore = 1 //some of the stuff gets blown up GetDrilled() if(1.0) mined_ore = 2 //some of the stuff gets blown up GetDrilled() if(severity <= 2) // Now to expose the ore lying under the sand. spawn(1) // Otherwise most of the ore is lost to the explosion, which makes this rather moot. for(var/ore in resources) var/amount_to_give = rand(CEILING(resources[ore]/2, 1), resources[ore]) // Should result in at least one piece of ore. for(var/i=1, i <= amount_to_give, i++) var/oretype = ore_types[ore] new oretype(src) resources[ore] = 0 /turf/simulated/mineral/bullet_act(var/obj/item/projectile/Proj) // only emitters for now if(Proj.excavation_amount) var/newDepth = excavation_level + Proj.excavation_amount // Used commonly below if(newDepth >= 200) // first, if the turf is completely drilled then don't bother checking for finds and just drill it GetDrilled(0) //destroy any archaeological finds if(finds && finds.len) var/datum/find/F = finds[1] if(newDepth > F.excavation_required) // Digging too deep with something as clumsy or random as a blaster will destroy artefacts finds.Remove(finds[1]) if(prob(50)) artifact_debris() excavation_level += Proj.excavation_amount update_archeo_overlays(Proj.excavation_amount) /turf/simulated/mineral/Bumped(AM) . = ..() if(!density) return . if(istype(AM,/mob/living/carbon/human)) var/mob/living/carbon/human/H = AM var/obj/item/weapon/pickaxe/P = H.get_inactive_hand() if(istype(P)) src.attackby(P, H) else if(istype(AM,/mob/living/silicon/robot)) var/mob/living/silicon/robot/R = AM if(istype(R.module_active,/obj/item/weapon/pickaxe)) attackby(R.module_active,R) else if(istype(AM,/obj/mecha)) var/obj/mecha/M = AM if(istype(M.selected,/obj/item/mecha_parts/mecha_equipment/tool/drill)) M.selected.action(src) /turf/simulated/mineral/proc/MineralSpread() if(mineral && mineral.spread) for(var/trydir in cardinal) if(prob(mineral.spread_chance)) var/turf/simulated/mineral/target_turf = get_step(src, trydir) if(istype(target_turf) && target_turf.density && !target_turf.mineral) target_turf.mineral = mineral target_turf.UpdateMineral() target_turf.MineralSpread() /turf/simulated/mineral/proc/UpdateMineral() clear_ore_effects() if(mineral) new /obj/effect/mineral(src, mineral) update_icon() //Not even going to touch this pile of spaghetti /turf/simulated/mineral/attackby(obj/item/weapon/W as obj, mob/user as mob) if (!(istype(usr, /mob/living/carbon/human) || ticker) && ticker.mode.name != "monkey") to_chat(user, "You don't have the dexterity to do this!") return if(!density) var/list/usable_tools = list( /obj/item/weapon/shovel, /obj/item/weapon/pickaxe/diamonddrill, /obj/item/weapon/pickaxe/drill, /obj/item/weapon/pickaxe/borgdrill ) var/valid_tool for(var/valid_type in usable_tools) if(istype(W,valid_type)) valid_tool = 1 break if(valid_tool) if (sand_dug) to_chat(user, "This area has already been dug.") return var/turf/T = user.loc if (!(istype(T))) return to_chat(user, "You start digging.") playsound(user.loc, 'sound/effects/rustle1.ogg', 50, 1) if(!do_after(user,30)) return //YAWN change. 30 from 40 to_chat(user, "You dug a hole.") GetDrilled() else if(istype(W,/obj/item/weapon/storage/bag/ore)) var/obj/item/weapon/storage/bag/ore/S = W if(S.collection_mode) for(var/obj/item/weapon/ore/O in contents) O.attackby(W,user) return else if(istype(W,/obj/item/weapon/storage/bag/fossils)) var/obj/item/weapon/storage/bag/fossils/S = W if(S.collection_mode) for(var/obj/item/weapon/fossil/F in contents) F.attackby(W,user) return else if(istype(W, /obj/item/stack/rods)) var/obj/structure/lattice/L = locate(/obj/structure/lattice, src) if(L) return var/obj/item/stack/rods/R = W if (R.use(1)) to_chat(user, "Constructing support lattice ...") playsound(src, 'sound/weapons/Genhit.ogg', 50, 1) new /obj/structure/lattice(get_turf(src)) else if(istype(W, /obj/item/stack/tile/floor)) var/obj/structure/lattice/L = locate(/obj/structure/lattice, src) if(L) var/obj/item/stack/tile/floor/S = W if (S.get_amount() < 1) return qdel(L) playsound(src, 'sound/weapons/Genhit.ogg', 50, 1) ChangeTurf(/turf/simulated/floor) S.use(1) return else to_chat(user, "The plating is going to need some support.") return else if (istype(W, /obj/item/device/core_sampler)) 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("\The [user] extends \a [P] towards \the [src].","You extend \the [P] towards \the [src].") if(do_after(user, 15)) to_chat(user, "\The [src] has been excavated to a depth of [excavation_level]cm.") return if(istype(W, /obj/item/device/xenoarch_multi_tool)) var/obj/item/device/xenoarch_multi_tool/C = W if(C.mode) //Mode means scanning C.depth_scanner.scan_atom(user, src) else user.visible_message("\The [user] extends \the [C] over \the [src], a flurry of red beams scanning \the [src]'s surface!", "You extend \the [C] over \the [src], a flurry of red beams scanning \the [src]'s surface!") if(do_after(user, 15)) to_chat(user, "\The [src] has been excavated to a depth of [excavation_level]cm.") return if (istype(W, /obj/item/weapon/pickaxe)) if(!istype(user.loc, /turf)) return var/obj/item/weapon/pickaxe/P = W if(last_act + P.digspeed > world.time)//prevents message spam return last_act = world.time playsound(user, P.drill_sound, 20, 1) var/newDepth = excavation_level + P.excavation_amount // Used commonly below //handle any archaeological finds we might uncover var/fail_message = "" if(finds && finds.len) var/datum/find/F = finds[1] if(newDepth > F.excavation_required) // Digging too deep can break the item. At least you won't summon a Balrog (probably) 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]")]" wreckfinds(P.destroy_artefacts) to_chat(user, "You start [P.drill_verb][fail_message].") if(do_after(user,P.digspeed)) if(finds && finds.len) var/datum/find/F = finds[1] if(newDepth == F.excavation_required) // When the pick hits that edge just right, you extract your find perfectly, it's never confined in a rock excavate_find(1, F) else if(newDepth > F.excavation_required - F.clearance_range) // Not quite right but you still extract your find, the closer to the bottom the better, but not above 80% excavate_find(prob(80 * (F.excavation_required - newDepth) / F.clearance_range), F) to_chat(user, "You finish [P.drill_verb] \the [src].") if(newDepth >= 200) // This means the rock is mined out fully if(P.destroy_artefacts) GetDrilled(0) else excavate_turf() return excavation_level += P.excavation_amount update_archeo_overlays(P.excavation_amount) //drop some rocks next_rock += P.excavation_amount while(next_rock > 50) next_rock -= 50 var/obj/item/weapon/ore/O = new(src) geologic_data.UpdateNearbyArtifactInfo(src) O.geologic_data = geologic_data return return attack_hand(user) /turf/simulated/mineral/proc/wreckfinds(var/destroy = FALSE) if(!destroy && prob(90)) //nondestructive methods have a chance of letting you step away to not trash things if(prob(25)) excavate_find(prob(5), finds[1]) else if(prob(50) || destroy) //destructive methods will always destroy finds, no bowls menacing with spikes for you finds.Remove(finds[1]) if(prob(50)) artifact_debris() /turf/simulated/mineral/proc/update_archeo_overlays(var/excavation_amount = 0) var/updateIcon = 0 //archaeo overlays if(!archaeo_overlay && finds && finds.len) var/datum/find/F = finds[1] if(F.excavation_required <= excavation_level + F.view_range) cut_overlay(archaeo_overlay) archaeo_overlay = "overlay_archaeo[rand(1,3)]" add_overlay(archaeo_overlay) else if(archaeo_overlay && (!finds || !finds.len)) cut_overlay(archaeo_overlay) archaeo_overlay = null //there's got to be a better way to do this var/update_excav_overlay = 0 if(excavation_level >= 150) if(excavation_level - excavation_amount < 150) update_excav_overlay = 1 else if(excavation_level >= 100) if(excavation_level - excavation_amount < 100) update_excav_overlay = 1 else if(excavation_level >= 50) if(excavation_level - excavation_amount < 50) 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 if(excav_quadrant > 5) excav_quadrant = 5 cut_overlay(excav_overlay) excav_overlay = "overlay_excv[excav_quadrant]_[rand(1,3)]" add_overlay(excav_overlay) if(updateIcon) update_icon() /turf/simulated/mineral/proc/clear_ore_effects() for(var/obj/effect/mineral/M in contents) qdel(M) /turf/simulated/mineral/proc/DropMineral() if(!mineral) return clear_ore_effects() var/obj/item/weapon/ore/O = new mineral.ore (src) if(istype(O)) geologic_data.UpdateNearbyArtifactInfo(src) O.geologic_data = geologic_data return O /turf/simulated/mineral/proc/excavate_turf() var/obj/structure/boulder/B if(artifact_find) if( excavation_level > 0 || prob(15) ) //boulder with an artifact inside B = new(src) if(artifact_find) B.artifact_find = artifact_find else artifact_debris(1) else if(prob(5)) //empty boulder B = new(src) if(B) GetDrilled(0) else GetDrilled(1) return /turf/simulated/mineral/proc/GetDrilled(var/artifact_fail = 0) if(!density) if(!sand_dug) sand_dug = 1 for(var/i=0;i<(rand(3)+2);i++) new/obj/item/weapon/ore/glass(src) update_icon() return if (mineral && mineral.result_amount) //if the turf has already been excavated, some of it's ore has been removed for (var/i = 1 to mineral.result_amount - mined_ore) DropMineral() GLOB.rocks_drilled_roundstat++ //destroyed artifacts have weird, unpleasant effects //make sure to destroy them before changing the turf though if(artifact_find && artifact_fail) var/pain = 0 if(prob(50)) pain = 1 for(var/mob/living/M in range(src, 200)) to_chat(M, "[pick("A high-pitched [pick("keening","wailing","whistle")]","A rumbling noise like [pick("thunder","heavy machinery")]")] somehow penetrates your mind before fading away!") if(pain) flick("pain",M.pain) if(prob(50)) M.adjustBruteLoss(5) else M.flash_eyes() if(prob(50)) M.Stun(5) SSradiation.flat_radiate(src, 25, 100) if(prob(25)) excavate_find(prob(5), finds[1]) else if(rand(1,500) == 1) visible_message("An old dusty crate was buried within!") new /obj/structure/closet/crate/secure/loot(src) make_floor() update_icon(1) /turf/simulated/mineral/proc/excavate_find(var/is_clean = 0, var/datum/find/F) //with skill and luck, players can cleanly extract finds //otherwise, they come out inside a chunk of rock var/obj/item/weapon/X if(is_clean) X = new /obj/item/weapon/archaeological_find(src, new_item_type = F.find_type) else X = new /obj/item/weapon/strangerock(src, inside_item_type = F.find_type) geologic_data.UpdateNearbyArtifactInfo(src) var/obj/item/weapon/strangerock/SR = X SR.geologic_data = geologic_data //some find types delete the /obj/item/weapon/archaeological_find and replace it with something else, this handles when that happens //yuck var/display_name = "Something" if(!X) X = last_find if(X) display_name = X.name //many finds are ancient and thus very delicate - luckily there is a specialised energy suspension field which protects them when they're being extracted if(prob(F.prob_delicate)) var/obj/effect/suspension_field/S = locate() in src if(!S) if(X) visible_message("\The [pick("[display_name] crumbles away into dust","[display_name] breaks apart")].") qdel(X) finds.Remove(F) /turf/simulated/mineral/proc/artifact_debris(var/severity = 0) //cael's patented random limited drop componentized loot system! //sky's patented not-fucking-retarded overhaul! //Give a random amount of loot from 1 to 3 or 5, varying on severity. for(var/j in 1 to rand(1, 3 + max(min(severity, 1), 0) * 2)) switch(rand(1,7)) if(1) new /obj/item/stack/rods(src, rand(5,25)) if(2) new /obj/item/stack/material/plasteel(src, rand(5,25)) if(3) new /obj/item/stack/material/steel(src, rand(5,25)) if(4) new /obj/item/stack/material/plasteel(src, rand(5,25)) if(5) for(var/i=1 to rand(1,3)) new /obj/item/weapon/material/shard(src) if(6) for(var/i=1 to rand(1,3)) new /obj/item/weapon/material/shard/phoron(src) if(7) new /obj/item/stack/material/uranium(src, rand(5,25)) /turf/simulated/mineral/proc/make_ore(var/rare_ore) if(mineral || ignore_mapgen || ignore_oregen) //VOREStation Edit - Makes sense, doesn't it? return var/mineral_name if(rare_ore) mineral_name = pickweight(list("marble" = 5, "uranium" = 10, "platinum" = 10, "hematite" = 20, "carbon" = 20, "diamond" = 2, "gold" = 10, "silver" = 10, "phoron" = 20, "lead" = 5, "verdantium" = 1)) else mineral_name = pickweight(list("marble" = 3, "uranium" = 10, "platinum" = 10, "hematite" = 70, "carbon" = 70, "diamond" = 2, "gold" = 10, "silver" = 10, "phoron" = 20, "lead" = 2, "verdantium" = 1)) if(mineral_name && (mineral_name in ore_data)) mineral = ore_data[mineral_name] UpdateMineral() update_icon()