diff --git a/baystation12.dme b/baystation12.dme index 15f91784c95..c64e3dae698 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -193,6 +193,7 @@ #include "code\game\atoms.dm" #include "code\game\atoms_movable.dm" #include "code\game\communications.dm" +#include "code\game\mining_surprise.dm" #include "code\game\response_team.dm" #include "code\game\shuttle_engines.dm" #include "code\game\skincmd.dm" diff --git a/code/game/asteroid.dm b/code/game/asteroid.dm index 05fc66d2d40..a37ac4c2ce4 100644 --- a/code/game/asteroid.dm +++ b/code/game/asteroid.dm @@ -161,3 +161,30 @@ proc/make_mining_asteroid_secret(var/size = 5) return 1 + +proc/check_complex_placement(var/turf/T,var/size_x,var/size_y,var/ignore_walls=0) + var/list/surroundings = list() + + surroundings |= range(7, locate(T.x,T.y,T.z)) + surroundings |= range(7, locate(T.x+size_x,T.y,T.z)) + surroundings |= range(7, locate(T.x,T.y+size_y,T.z)) + surroundings |= range(7, locate(T.x+size_x,T.y+size_y,T.z)) + + if(locate(/area/mine/explored) in surroundings) // +5s are for view range + return 0 + + if(locate(/turf/space) in surroundings) + return 0 + + /* /vg/: Allow combining rooms. + if(locate(/area/asteroid/artifactroom) in surroundings) + return 0 + + if(locate(/turf/unsimulated/floor/asteroid) in surroundings) + return 0 + */ + + // /vg/: Stop spawning shit inside of the vox hideout + if(locate(/turf/simulated/wall) in surroundings && !ignore_walls) + return 0 + return 1 \ No newline at end of file diff --git a/code/game/mining_surprise.dm b/code/game/mining_surprise.dm new file mode 100644 index 00000000000..0fa9dce0b3a --- /dev/null +++ b/code/game/mining_surprise.dm @@ -0,0 +1,433 @@ +#define CONTIGUOUS_WALLS 1 +#define CONTIGUOUS_FLOORS 2 + + +var/global/list/mining_surprises = typesof(/mining_surprise)-/mining_surprise + +/surprise_room + var/list/floors[0] + var/list/walls[0] + + var/size_x=0 + var/size_y=0 + +/mining_surprise + var/name = "Hidden Complex" + + //: Types of floor to use + var/list/floortypes[0] + var/list/walltypes[0] + var/list/spawntypes[0] + var/list/fluffitems[0] + + var/max_richness=2 + + //: How many rooms? + var/complex_max_size=1 + + var/room_size_max=5 + + var/flags=0 + + var/list/rooms=list() + var/list/goodies=list() + var/list/candidates=list() + + var/area/asteroid/artifactroom/complex_area + + proc/spawn_complex(var/atom/start_loc) + name = "[initial(name)] #[rand(100,999)]" + complex_area = new + complex_area.name = name + var/atom/pos=start_loc + var/nrooms=complex_max_size + var/maxtries=50 + var/l_size_x=0 + var/l_size_y=0 + while(nrooms && maxtries) + var/sx=rand(3,room_size_max) + var/sy=rand(3,room_size_max) + var/o_x=l_size_x?rand(0,l_size_x):0 + var/o_y=l_size_y?rand(0,l_size_y):0 + var/atom/npos + switch(pick(cardinal)) + if(NORTH) + npos=locate(pos.x+o_x, pos.y+sy-1, pos.z) + if(SOUTH) + npos=locate(pos.x+o_x, pos.y-sy+1, pos.z) + if(WEST) + npos=locate(pos.x-sx-1, pos.y+o_y, pos.z) + if(EAST) + npos=locate(pos.x+sx+1, pos.y+o_y, pos.z) + if(spawn_room(npos,sx,sy,1)) + pos=npos + l_size_x=sx + l_size_y=sy + else if(complex_max_size==nrooms) + // Failed to make first room, abort. + del(complex_area) + return 0 + else + maxtries-- + continue + nrooms-- + postProcessComplex() + message_admins("Complex spawned at [formatJumpTo(start_loc)]") + return 1 + + proc/postProcessRoom(var/surprise_room/room) + for(var/turf/floor in room.floors) + for(var/turf/T in floor.AdjacentTurfs()) + if(T in room.floors) + candidates|=T + break + + proc/postProcessComplex() + for(var/i=0;i<=rand(1,max_richness);i++) + if(!candidates.len) + return + var/turf/T = pick(candidates) + var/thing = pickweight(spawntypes) + if(thing==null) + continue + new thing(T) + candidates -= T + message_admins("Goodie [thing] spawned at [formatJumpTo(T)]") + + for(var/i=0;i<=rand(5,10);i++) + if(!candidates.len) + return + var/turf/T = pick(candidates) + var/thing = pickweight(fluffitems) + if(thing==null) + continue + new thing(T) + + proc/spawn_room(var/atom/start_loc, var/x_size, var/y_size, var/clean=0) + if(!check_complex_placement(start_loc,x_size,y_size)) + return 0 + + // If walls/floors are contiguous, pick them out. + var/wall_type + if(flags & CONTIGUOUS_WALLS) + wall_type = pickweight(walltypes) + + var/floor_type + if(flags & CONTIGUOUS_FLOORS) + floor_type = pickweight(floortypes) + + + var/list/walls[0] + var/list/floors[0] + for(var/x = 0,x[src.name] is too cumbersome to carry with anything but your hands!" + return 0 + return ..() + +/obj/item/weapon/twohanded/required/attack_hand(mob/user)//Can't even pick it up without both hands empty + var/obj/item/weapon/twohanded/required/H = user.get_inactive_hand() + if(H != null) + user.visible_message("[src.name] is too cumbersome to carry in one hand!") + return + var/obj/item/weapon/twohanded/offhand/O = new(user) + user.put_in_inactive_hand(O) + ..() + wielded = 1 + + +obj/item/weapon/twohanded/ /* * Fireaxe diff --git a/code/modules/mining/mine_turfs.dm b/code/modules/mining/mine_turfs.dm index b767cae3fd5..db9fc4b98fa 100644 --- a/code/modules/mining/mine_turfs.dm +++ b/code/modules/mining/mine_turfs.dm @@ -363,7 +363,7 @@ var/list/artifact_spawn = list() // Runtime fix for geometry loading before cont /turf/simulated/mineral/random name = "Mineral deposit" - var/mineralSpawnChanceList = list("Uranium" = 5, "Iron" = 50, "Diamond" = 1, "Gold" = 5, "Silver" = 5, "Plasma" = 25)//Currently, Adamantine won't spawn as it has no uses. -Durandan + var/mineralSpawnChanceList = list("Uranium" = 5, "Iron" = 50, "Diamond" = 1, "Gold" = 5, "Silver" = 5, "Plasma" = 25, "Gibtonite" = 5, "Cave" = 1)//Currently, Adamantine won't spawn as it has no uses. -Durandan var/mineralChance = 10 //means 10% chance of this plot changing to a mineral deposit New() @@ -560,3 +560,154 @@ var/list/artifact_spawn = list() // Runtime fix for geometry loading before cont attackby(R.module_state_3,R) else return + + +////////////////////////////////Gibtonite +/turf/simulated/mineral/gibtonite + name = "Diamond deposit" //honk + icon_state = "rock_Diamond" + mineral = new /mineral/gibtonite + + var/det_time = 8 //Countdown till explosion, but also rewards the player for how close you were to detonation when you defuse it + var/stage = 0 //How far into the lifecycle of gibtonite we are, 0 is untouched, 1 is active and attempting to detonate, 2 is benign and ready for extraction + var/activated_ckey = null //These are to track who triggered the gibtonite deposit for logging purposes + var/activated_name = null + +/turf/simulated/mineral/gibtonite/New() + det_time = rand(8,10) //So you don't know exactly when the hot potato will explode + ..() + +/turf/simulated/mineral/gibtonite/attackby(obj/item/I, mob/user) + if(istype(I, /obj/item/device/analyzer) && stage == 1) + user.visible_message("You use the analyzer to locate where to cut off the chain reaction and attempt to stop it...") + defuse() + if(istype(I, /obj/item/weapon/pickaxe)) + src.activated_ckey = "[user.ckey]" + src.activated_name = "[user.name]" + ..() + +/turf/simulated/mineral/gibtonite/proc/explosive_reaction() + if(stage == 0) + icon_state = "rock_Gibtonite_active" + name = "Gibtonite deposit" + desc = "An active gibtonite reserve. Run!" + stage = 1 + visible_message("There was gibtonite inside! It's going to explode!") + var/turf/bombturf = get_turf(src) + var/area/A = get_area(bombturf) + var/log_str = "[src.activated_ckey]? [src.activated_name] has triggered a gibtonite deposit reaction [A.name] (JMP)." + log_game(log_str) + countdown() + +/turf/simulated/mineral/gibtonite/proc/countdown() + spawn(0) + while(stage == 1 && det_time > 0 && mineral.result_amount >= 1) + det_time-- + sleep(5) + if(stage == 1 && det_time <= 0 && mineral.result_amount >= 1) + var/turf/bombturf = get_turf(src) + mineral.result_amount = 0 + explosion(bombturf,1,3,5, adminlog = 0) + if(stage == 0 || stage == 2) + return + +/turf/simulated/mineral/gibtonite/proc/defuse() + if(stage == 1) + icon_state = "rock_Gibtonite" + desc = "An inactive gibtonite reserve. The ore can be extracted." + stage = 2 + if(det_time < 0) + det_time = 0 + visible_message("The chain reaction was stopped! The gibtonite had [src.det_time] reactions left till the explosion!") + +/turf/simulated/mineral/gibtonite/GetDrilled() + if(stage == 0 && mineral.result_amount >= 1) //Gibtonite deposit is activated + playsound(src,'sound/effects/hit_on_shattered_glass.ogg',50,1) + explosive_reaction() + return + if(stage == 1 && mineral.result_amount >= 1) //Gibtonite deposit goes kaboom + var/turf/bombturf = get_turf(src) + mineral.result_amount = 0 + explosion(bombturf,1,2,5, adminlog = 0) + if(stage == 2) //Gibtonite deposit is now benign and extractable. Depending on how close you were to it blowing up before defusing, you get better quality ore. + var/obj/item/weapon/twohanded/required/gibtonite/G = new /obj/item/weapon/twohanded/required/gibtonite/(src) + if(det_time <= 0) + G.quality = 3 + G.icon_state = "Gibtonite ore 3" + if(det_time >= 1 && det_time <= 2) + G.quality = 2 + G.icon_state = "Gibtonite ore 2" + var/turf/simulated/floor/plating/airless/asteroid/gibtonite_remains/G = ChangeTurf(/turf/simulated/floor/plating/airless/asteroid/gibtonite_remains) + G.fullUpdateMineralOverlays() + +/turf/simulated/floor/plating/airless/asteroid/gibtonite_remains + var/det_time = 0 + var/stage = 0 + +////////////////////////////////End Gibtonite + +/turf/simulated/floor/plating/airless/asteroid/cave + var/length = 100 + +/turf/simulated/floor/plating/airless/asteroid/cave/New(loc, var/length, var/go_backwards = 1, var/exclude_dir = -1) + + // If length (arg2) isn't defined, get a random length; otherwise assign our length to the length arg. + if(!length) + src.length = rand(25, 50) + else + src.length = length + + // Get our directiosn + var/forward_cave_dir = pick(alldirs - exclude_dir) + // Get the opposite direction of our facing direction + var/backward_cave_dir = angle2dir(dir2angle(forward_cave_dir) + 180) + + // Make our tunnels + make_tunnel(forward_cave_dir) + if(go_backwards) + make_tunnel(backward_cave_dir) + // Kill ourselves by replacing ourselves with a normal floor. + SpawnFloor(src) + ..() + +/turf/simulated/floor/plating/airless/asteroid/cave/proc/make_tunnel(var/dir) + + var/turf/simulated/mineral/tunnel = src + var/next_angle = pick(45, -45) + + for(var/i = 0; i < length; i++) + + var/list/L = list(45) + if(IsOdd(dir2angle(dir))) // We're going at an angle and we want thick angled tunnels. + L += -45 + + // Expand the edges of our tunnel + for(var/edge_angle in L) + var/turf/simulated/mineral/edge = get_step(tunnel, angle2dir(dir2angle(dir) + edge_angle)) + if(istype(edge)) + SpawnFloor(edge) + + // Move our tunnel forward + tunnel = get_step(tunnel, dir) + + if(istype(tunnel)) + // Small chance to have forks in our tunnel; otherwise dig our tunnel. + if(i > 3 && prob(20)) + new src.type(tunnel, rand(10, 15), 0, dir) + else + SpawnFloor(tunnel) + else //if(!istype(tunnel, src.parent)) // We hit space/normal/wall, stop our tunnel. + break + + // Chance to change our direction left or right. + if(i > 2 && prob(33)) + // We can't go a full loop though + next_angle = -next_angle + dir = angle2dir(dir2angle(dir) + next_angle) + + +/turf/simulated/floor/plating/airless/asteroid/cave/proc/SpawnFloor(var/turf/T) + //var/turf/simulated/floor/t = + new /turf/simulated/floor/plating/airless/asteroid(T) + //spawn(2) + // t.fullUpdateMineralOverlays() \ No newline at end of file diff --git a/code/modules/mining/minerals.dm b/code/modules/mining/minerals.dm index 8d14f2352d4..e4486e559a7 100644 --- a/code/modules/mining/minerals.dm +++ b/code/modules/mining/minerals.dm @@ -28,6 +28,9 @@ mineral if(!display_name) display_name = name + proc/UpdateTurf(var/turf/simulated/mineral/T) + T.UpdateMineral() + mineral/uranium name = "Uranium" result_amount = 5 @@ -69,4 +72,29 @@ mineral/clown name = "Clown" result_amount = 3 spread = 0 - ore = /obj/item/weapon/ore/clown \ No newline at end of file + ore = /obj/item/weapon/ore/clown + +mineral/gibtonite + display_name = "Gibtonite" + name = "Gibtonite" + result_amount = 1 + spread_chance = 10 + ore = /obj/item/weapon/twohanded/required/gibtonite + UpdateTurf(var/turf/T) + if(!istype(T,/turf/simulated/mineral/gibtonite)) + T.ChangeTurf(/turf/simulated/mineral/gibtonite) + else + ..() + +mineral/cave + display_name = "Cave" + name = "Cave" + result_amount = 1 + spread_chance = 10 + ore = null + UpdateTurf(var/turf/T) + if(!istype(T,/turf/simulated/floor/plating/airless/asteroid/cave)) + T.ChangeTurf(/turf/simulated/floor/plating/airless/asteroid/cave) + else + ..() + diff --git a/code/modules/mining/ores_coins.dm b/code/modules/mining/ores_coins.dm index 22024b54aad..af78b9ec397 100644 --- a/code/modules/mining/ores_coins.dm +++ b/code/modules/mining/ores_coins.dm @@ -59,6 +59,49 @@ desc = "Completely useless" icon_state = "slag" +/obj/item/weapon/twohanded/required/gibtonite + name = "Gibtonite ore" + desc = "Extremely explosive if struck with mining equipment, Gibtonite is often used by miners to speed up their work by using it as a mining charge. This material is illegal to possess by unauthorized personnel under space law." + icon = 'icons/obj/mining.dmi' + icon_state = "Gibtonite ore" + item_state = "Gibtonite ore" + w_class = 4 + throw_range = 0 + anchored = 1 //Forces people to carry it by hand, no pulling! + var/primed = 0 + var/det_time = 100 + var/quality = 1 //How pure this gibtonite is, determines the explosion produced by it and is derived from the det_time of the rock wall it was taken from, higher value = better + +/obj/item/weapon/twohanded/required/gibtonite/attackby(obj/item/I, mob/user) + if(istype(I, /obj/item/weapon/pickaxe) && !primed) + playsound(src,'sound/effects/hit_on_shattered_glass.ogg',50,1) + primed = 1 + icon_state = "Gibtonite active" + user.visible_message("[user] strikes the [src], causing a chain reaction!") + var/turf/bombturf = get_turf(src) + var/area/A = get_area(bombturf) + var/notify_admins = 0 + if(z != 5)//Only annoy the admins ingame if we're triggered off the mining zlevel + notify_admins = 1 + if(notify_admins) + message_admins("[key_name(usr)]? has triggered a [name] to detonate at [A.name] (JMP).") + log_game("[key_name(usr)] has primed a [name] for detonation at [A.name]([bombturf.x],[bombturf.y],[bombturf.z])") + spawn(det_time) + if(primed) + if(quality == 3) + explosion(src.loc,2,4,9,adminlog = notify_admins) + if(quality == 2) + explosion(src.loc,1,2,5,adminlog = notify_admins) + if(quality == 1) + explosion(src.loc,-1,1,3,adminlog = notify_admins) + del(src) + if(istype(I, /obj/item/device/analyzer) && primed) + primed = 0 + user.visible_message("The chain reaction was stopped! ...The ore's quality went down.") + icon_state = "Gibtonite ore" + quality = 1 + ..() + /obj/item/weapon/ore/New() pixel_x = rand(0,16)-8 pixel_y = rand(0,8)-8 diff --git a/icons/obj/mining.dmi b/icons/obj/mining.dmi index e984d192e82..9c54cb32715 100644 Binary files a/icons/obj/mining.dmi and b/icons/obj/mining.dmi differ diff --git a/icons/turf/walls.dmi b/icons/turf/walls.dmi index 01a744ecbd4..7b03bf5fc64 100644 Binary files a/icons/turf/walls.dmi and b/icons/turf/walls.dmi differ