diff --git a/code/__defines/materials.dm b/code/__defines/materials.dm index e9ec7a357a..90f6cb940c 100644 --- a/code/__defines/materials.dm +++ b/code/__defines/materials.dm @@ -56,6 +56,7 @@ #define MAT_DEUTERIUM "deuterium" #define MAT_CONCRETE "concrete" #define MAT_PLASTEELREBAR "plasteel rebar" +#define MAT_GRASS "grass" #define DEFAULT_TABLE_MATERIAL MAT_PLASTIC diff --git a/code/datums/autolathe/engineering.dm b/code/datums/autolathe/engineering.dm index d488642698..87dbe9d574 100644 --- a/code/datums/autolathe/engineering.dm +++ b/code/datums/autolathe/engineering.dm @@ -78,6 +78,10 @@ name = "request console electronics" path =/obj/item/weapon/circuitboard/request +/datum/category_item/autolathe/engineering/electrochromic + name = "electrochromic window control electronics" + path =/obj/item/weapon/circuitboard/electrochromic + /datum/category_item/autolathe/engineering/pipelayer name = "pipe layer electronics" path =/obj/item/weapon/circuitboard/pipelayer diff --git a/code/game/machinery/computer/arcade.dm b/code/game/machinery/computer/arcade.dm index 188fd356dc..9869c93f7d 100644 --- a/code/game/machinery/computer/arcade.dm +++ b/code/game/machinery/computer/arcade.dm @@ -1337,3 +1337,5 @@ O = T to_chat(user, "You turn in 2 tickets to the [src] and claim a prize!") return + else + ..() //You can now actually deconstruct these. \ No newline at end of file diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index b1c6b23b71..1c1a6f2252 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -256,8 +256,11 @@ explosion_resistance = 5 opacity = 0 glass = 1 +<<<<<<< HEAD open_sound_powered = 'sound/machines/hall1o.ogg' //CHOMPEdit close_sound_powered = 'sound/machines/hall1c.ogg' //CHOMPEdit +======= +>>>>>>> e047e89ba7... Merge pull request #14638 from VOREStation/upstream-merge-9002 /obj/machinery/door/airlock/centcom name = "Centcom Airlock" @@ -381,7 +384,11 @@ close_sound_powered = 'sound/machines/door/hall1c.ogg' // VOREStation Edit: Default door sounds for fancy, department-off. department_open_powered = 'sound/machines/door/sec1o.ogg' department_close_powered = 'sound/machines/door/sec1c.ogg' +<<<<<<< HEAD security_level = 2 //VOREStation Additio +======= + security_level = 2 //VOREStation Addition +>>>>>>> e047e89ba7... Merge pull request #14638 from VOREStation/upstream-merge-9002 /obj/machinery/door/airlock/glass_medical name = "Medical Airlock" @@ -1002,9 +1009,14 @@ About the new airlock wires panel: ..(user) return +<<<<<<< HEAD /* // CHOMPEDIT: disabling becaue alt-clicking to view a turf is pretty important. /obj/machinery/door/airlock/AltClick(mob/user as mob) +======= +/obj/machinery/door/airlock/AltClick(mob/user as mob) + . = ..() +>>>>>>> e047e89ba7... Merge pull request #14638 from VOREStation/upstream-merge-9002 user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) if(!Adjacent(user)) return @@ -1014,18 +1026,29 @@ About the new airlock wires panel: if(icon_state == "door_closed" && arePowerSystemsOn()) flick("door_deny", src) playsound(src, knock_hammer_sound, 50, 0, 3) +<<<<<<< HEAD else if(arePowerSystemsOn()) +======= + else if(arePowerSystemsOn() && user.a_intent == I_HELP) +>>>>>>> e047e89ba7... Merge pull request #14638 from VOREStation/upstream-merge-9002 src.visible_message("[user] presses the door bell on \the [src].", "\The [src]'s bell rings.") src.add_fingerprint(user) if(icon_state == "door_closed") flick("door_deny", src) playsound(src, knock_sound, 50, 0, 3) +<<<<<<< HEAD else +======= + else if(user.a_intent == I_HELP) +>>>>>>> e047e89ba7... Merge pull request #14638 from VOREStation/upstream-merge-9002 src.visible_message("[user] knocks on \the [src].", "Someone knocks on \the [src].") src.add_fingerprint(user) playsound(src, knock_unpowered_sound, 50, 0, 3) return +<<<<<<< HEAD */ +======= +>>>>>>> e047e89ba7... Merge pull request #14638 from VOREStation/upstream-merge-9002 /obj/machinery/door/airlock/tgui_act(action, params) if(..()) @@ -1161,12 +1184,24 @@ About the new airlock wires panel: if (stat & BROKEN) to_chat(usr, "The panel is broken and cannot be closed.") else +<<<<<<< HEAD src.p_open = 0 playsound(src, C.usesound, 50, 1) else src.p_open = 1 playsound(src, C.usesound, 50, 1) src.update_icon() +======= + src.p_open = FALSE + playsound(src, C.usesound, 50, 1) + src.update_icon() + return + else + src.p_open = TRUE + playsound(src, C.usesound, 50, 1) + src.update_icon() + return src.attack_hand(user) +>>>>>>> e047e89ba7... Merge pull request #14638 from VOREStation/upstream-merge-9002 else if(C.is_wirecutter()) return src.attack_hand(user) else if(istype(C, /obj/item/device/multitool)) @@ -1249,7 +1284,11 @@ About the new airlock wires panel: ..() /obj/machinery/door/airlock/set_broken() +<<<<<<< HEAD src.p_open = 1 +======= + src.p_open = TRUE +>>>>>>> e047e89ba7... Merge pull request #14638 from VOREStation/upstream-merge-9002 stat |= BROKEN if (secured_wires) lock() diff --git a/code/game/machinery/frame.dm b/code/game/machinery/frame.dm index c3fa1701fd..43fd737eaf 100644 --- a/code/game/machinery/frame.dm +++ b/code/game/machinery/frame.dm @@ -208,6 +208,14 @@ circuit = /obj/machinery/atmospheric_field_generator frame_size = 3 +/datum/frame/frame_types/electrochromic_button + name = "Electrochromic Window Button" + frame_class = FRAME_CLASS_ALARM + frame_size = 1 + frame_style = FRAME_STYLE_WALL + x_offset = 24 + y_offset = 24 + ////////////////////////////// // Frame Object (Structure) ////////////////////////////// diff --git a/code/game/objects/items/stacks/tiles/tile_types.dm b/code/game/objects/items/stacks/tiles/tile_types.dm index 28dd4425bd..4d50fa7800 100644 --- a/code/game/objects/items/stacks/tiles/tile_types.dm +++ b/code/game/objects/items/stacks/tiles/tile_types.dm @@ -21,14 +21,57 @@ drop_sound = 'sound/items/drop/axe.ogg' pickup_sound = 'sound/items/pickup/axe.ogg' +<<<<<<< HEAD var/datum/material/material //CHOMPEDIT: Start, To make tiles have material variables var/default_type = DEFAULT_WALL_MATERIAL var/perunit = SHEET_MATERIAL_AMOUNT var/apply_colour //CHOMPEDIT: End +======= +//crafting / welding vars + var/datum/material/material //*sigh* i guess this is how we're doing this. + var/craftable = FALSE //set to TRUE for tiles you can craft stuff from directly, like grass + var/can_weld = FALSE //set to TRUE for tiles you can reforge into their components via welding, like metal + var/welds_into = /obj/item/stack/material/steel //what you get from the welding. defaults to steel. + var/default_type = DEFAULT_WALL_MATERIAL + + +>>>>>>> e047e89ba7... Merge pull request #14638 from VOREStation/upstream-merge-9002 /obj/item/stack/tile/Initialize() . = ..() randpixel_xy() + if(craftable) + material = get_material_by_name("[default_type]") + if(!material) + return INITIALIZE_HINT_QDEL + if(material) //sanity check + recipes = material.get_recipes() + stacktype = material.stack_type + +/obj/item/stack/tile/attackby(obj/item/W as obj, mob/user as mob) + if (istype(W, /obj/item/weapon/weldingtool)) + var/obj/item/weapon/weldingtool/WT = W + + if(can_weld == FALSE) + to_chat("You can't reform these into their original components.") + return + + if(get_amount() < 4) + to_chat(user, "You need at least four tiles to do this.") + return + + if(WT.remove_fuel(0,user)) + new welds_into(usr.loc) + usr.update_icon() + visible_message("\The [src] is shaped by [user.name] with the welding tool.","You hear welding.") + var/obj/item/stack/tile/T = src + src = null + var/replace = (user.get_inactive_hand()==T) + T.use(4) + if (!T && replace) + user.put_in_hands(welds_into) + return TRUE + return ..() /* * Grass @@ -38,6 +81,7 @@ singular_name = "grass floor tile" desc = "A patch of grass like they often use on golf courses." icon_state = "tile_grass" + default_type = "grass" force = 1.0 throwforce = 1.0 throw_speed = 5 @@ -47,6 +91,7 @@ no_variants = FALSE drop_sound = 'sound/items/drop/herb.ogg' pickup_sound = 'sound/items/pickup/herb.ogg' + craftable = TRUE /obj/item/stack/tile/grass/sif name = "sivian grass tile" @@ -203,6 +248,7 @@ throw_speed = 5 throw_range = 20 no_variants = FALSE + can_weld = TRUE /obj/item/stack/tile/floor/red name = "red floor tile" @@ -234,6 +280,7 @@ singular_name = "steel floor tile" icon_state = "tile_steel" matter = list(MAT_PLASTEEL = SHEET_MATERIAL_AMOUNT / 4) + welds_into = /obj/item/stack/material/plasteel no_variants = FALSE /obj/item/stack/tile/floor/steel @@ -241,6 +288,7 @@ singular_name = "steel floor tile" icon_state = "tile_steel" matter = list(MAT_PLASTEEL = SHEET_MATERIAL_AMOUNT / 4) + welds_into = /obj/item/stack/material/plasteel no_variants = FALSE /obj/item/stack/tile/floor/white @@ -248,6 +296,7 @@ singular_name = "white floor tile" icon_state = "tile_white" matter = list(MAT_PLASTIC = SHEET_MATERIAL_AMOUNT / 4) + welds_into = /obj/item/stack/material/plastic no_variants = FALSE /obj/item/stack/tile/floor/yellow @@ -262,6 +311,7 @@ singular_name = "dark floor tile" icon_state = "tile_steel" matter = list(MAT_PLASTEEL = SHEET_MATERIAL_AMOUNT / 4) + welds_into = /obj/item/stack/material/plasteel no_variants = FALSE /obj/item/stack/tile/floor/freezer @@ -269,6 +319,7 @@ singular_name = "freezer floor tile" icon_state = "tile_freezer" matter = list(MAT_PLASTIC = SHEET_MATERIAL_AMOUNT / 4) + welds_into = /obj/item/stack/material/plastic no_variants = FALSE /obj/item/stack/tile/floor/cyborg @@ -280,6 +331,7 @@ charge_costs = list(250) stacktype = /obj/item/stack/tile/floor build_type = /obj/item/stack/tile/floor + can_weld = FALSE //we're not going there /obj/item/stack/tile/linoleum name = "linoleum" @@ -292,6 +344,7 @@ throw_range = 20 flags = 0 no_variants = FALSE + can_weld = FALSE /obj/item/stack/tile/wmarble name = "light marble tile" @@ -304,6 +357,8 @@ throw_range = 20 flags = 0 no_variants = FALSE + can_weld = TRUE + welds_into = /obj/item/stack/material/marble /obj/item/stack/tile/bmarble name = "dark marble tile" @@ -316,12 +371,15 @@ throw_range = 20 flags = 0 no_variants = FALSE + can_weld = TRUE + welds_into = /obj/item/stack/material/marble /obj/item/stack/tile/roofing name = "roofing" singular_name = "roofing" desc = "A section of roofing material. You can use it to repair the ceiling, or expand it." icon_state = "techtile_grid" + can_weld = FALSE //roofing can also be made from wood, so let's not open that can of worms today /obj/item/stack/tile/roofing/cyborg name = "roofing synthesizer" @@ -330,3 +388,7 @@ charge_costs = list(250) stacktype = /obj/item/stack/tile/roofing build_type = /obj/item/stack/tile/roofing +<<<<<<< HEAD +======= + can_weld = FALSE +>>>>>>> e047e89ba7... Merge pull request #14638 from VOREStation/upstream-merge-9002 diff --git a/code/game/objects/items/weapons/circuitboards/frame.dm b/code/game/objects/items/weapons/circuitboards/frame.dm index 3d0e3d9cd2..73e7629f5d 100644 --- a/code/game/objects/items/weapons/circuitboards/frame.dm +++ b/code/game/objects/items/weapons/circuitboards/frame.dm @@ -74,6 +74,12 @@ board_type = new /datum/frame/frame_types/geiger matter = list(MAT_STEEL = 50, MAT_GLASS = 50) +/obj/item/weapon/circuitboard/electrochromic + name = T_BOARD("electrochromic button") + build_path = /obj/machinery/button/windowtint + board_type = new /datum/frame/frame_types/electrochromic_button + matter = list(MAT_STEEL = 50, "glass" = 50) + //Computer /obj/item/weapon/circuitboard/holopad diff --git a/code/game/objects/structures/lattice.dm b/code/game/objects/structures/lattice.dm index 30999cd3d6..d5fcf7e8d1 100644 --- a/code/game/objects/structures/lattice.dm +++ b/code/game/objects/structures/lattice.dm @@ -69,9 +69,12 @@ return if (istype(C, /obj/item/stack/rods)) var/obj/item/stack/rods/R = C - if(R.use(2)) + if(R.get_amount() < 2) + to_chat(user, "You need at least two rods to form a catwalk here.") + else to_chat(user, "You start connecting \the [R.name] to \the [src.name] ...") if(do_after(user, 5 SECONDS)) + R.use(2) //2023-02-27 bugfix to prevent rods being used without catwalk creation src.alpha = 0 // Note: I don't know why this is set, Eris did it, just trusting for now. ~Leshana new /obj/structure/catwalk(src.loc) qdel(src) diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index af89f9a47a..a32da6aea1 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -1,3 +1,4 @@ +<<<<<<< HEAD /obj/structure/window name = "window" desc = "A window." @@ -696,3 +697,709 @@ qdel(src) return TRUE return FALSE +======= +/obj/structure/window + name = "window" + desc = "A window." + icon = 'icons/obj/structures_vr.dmi' // VOREStation Edit - New icons + density = TRUE + can_atmos_pass = ATMOS_PASS_PROC + w_class = ITEMSIZE_NORMAL + + layer = WINDOW_LAYER + pressure_resistance = 4*ONE_ATMOSPHERE + anchored = TRUE + flags = ON_BORDER + var/maxhealth = 14.0 + var/maximal_heat = T0C + 100 // Maximal heat before this window begins taking damage from fire + var/damage_per_fire_tick = 2.0 // Amount of damage per fire tick. Regular windows are not fireproof so they might as well break quickly. + var/health + var/force_threshold = 0 + var/ini_dir = null + var/state = 2 + var/reinf = 0 + var/basestate + var/shardtype = /obj/item/weapon/material/shard + var/glasstype = null // Set this in subtypes. Null is assumed strange or otherwise impossible to dismantle, such as for shuttle glass. + var/silicate = 0 // number of units of silicate + var/fulltile = FALSE // Set to true on full-tile variants. + +/obj/structure/window/examine(mob/user) + . = ..() + + if(health == maxhealth) + . += "It looks fully intact." + else + var/perc = health / maxhealth + if(perc > 0.75) + . += "It has a few cracks." + else if(perc > 0.5) + . += "It looks slightly damaged." + else if(perc > 0.25) + . += "It looks moderately damaged." + else + . += "It looks heavily damaged." + if(silicate) + if (silicate < 30) + . += "It has a thin layer of silicate." + else if (silicate < 70) + . += "It is covered in silicate." + else + . += "There is a thick layer of silicate covering it." + +/obj/structure/window/examine_icon() + return icon(icon=initial(icon),icon_state=initial(icon_state)) + +/obj/structure/window/take_damage(var/damage = 0, var/sound_effect = 1) + var/initialhealth = health + + if(silicate) + damage = damage * (1 - silicate / 200) + + health = max(0, health - damage) + + if(health <= 0) + shatter() + else + if(sound_effect) + playsound(src, 'sound/effects/Glasshit.ogg', 100, 1) + if(health < maxhealth / 4 && initialhealth >= maxhealth / 4) + visible_message("[src] looks like it's about to shatter!" ) + update_icon() + else if(health < maxhealth / 2 && initialhealth >= maxhealth / 2) + visible_message("[src] looks seriously damaged!" ) + update_icon() + else if(health < maxhealth * 3/4 && initialhealth >= maxhealth * 3/4) + visible_message("Cracks begin to appear in [src]!" ) + update_icon() + return + +/obj/structure/window/proc/apply_silicate(var/amount) + if(health < maxhealth) // Mend the damage + health = min(health + amount * 3, maxhealth) + if(health == maxhealth) + visible_message("[src] looks fully repaired." ) + else // Reinforce + silicate = min(silicate + amount, 100) + updateSilicate() + +/obj/structure/window/proc/updateSilicate() + cut_overlays() + update_icon() + + var/image/img = image(src) + img.color = "#ffffff" + img.alpha = silicate * 255 / 100 + add_overlay(img) + +/obj/structure/window/proc/shatter(var/display_message = 1) + playsound(src, "shatter", 70, 1) + if(display_message) + visible_message("[src] shatters!") + new shardtype(loc) + if(reinf) + new /obj/item/stack/rods(loc) + if(is_fulltile()) + new shardtype(loc) //todo pooling? + if(reinf) + new /obj/item/stack/rods(loc) + qdel(src) + return + + +/obj/structure/window/bullet_act(var/obj/item/projectile/Proj) + + var/proj_damage = Proj.get_structure_damage() + if(!proj_damage) return + + ..() + take_damage(proj_damage) + return + + +/obj/structure/window/ex_act(severity) + switch(severity) + if(1.0) + qdel(src) + return + if(2.0) + shatter(0) + return + if(3.0) + if(prob(50)) + shatter(0) + return + +/obj/structure/window/blob_act() + take_damage(50) + +/obj/structure/window/CanPass(atom/movable/mover, turf/target) + if(istype(mover) && mover.checkpass(PASSGLASS)) + return TRUE + if(is_fulltile()) + return FALSE //full tile window, you can't move into it! + if(get_dir(mover, target) == reverse_dir[dir]) // From elsewhere to here, can't move against our dir + return !density + else + return TRUE + +/obj/structure/window/Uncross(atom/movable/mover, turf/target) + if(istype(mover) && mover.checkpass(PASSGLASS)) + return TRUE + if(get_dir(mover, target) == dir) // From here to elsewhere, can't move in our dir + return !density + else + return TRUE + +/obj/structure/window/CanZASPass(turf/T, is_zone) + if(is_fulltile() || get_dir(T, loc) == turn(dir, 180)) // Make sure we're handling the border correctly. + return !anchored // If it's anchored, it'll block air. + return TRUE // Don't stop airflow from the other sides. + +/obj/structure/window/hitby(AM as mob|obj) + ..() + visible_message("[src] was hit by [AM].") + var/tforce = 0 + if(ismob(AM)) + tforce = 40 + else if(isobj(AM)) + var/obj/item/I = AM + tforce = I.throwforce + if(reinf) tforce *= 0.25 + if(health - tforce <= 7 && !reinf) + anchored = FALSE + update_verbs() + update_nearby_icons() + step(src, get_dir(AM, src)) + take_damage(tforce) + +/obj/structure/window/attack_tk(mob/user as mob) + user.visible_message("Something knocks on [src].") + playsound(src, 'sound/effects/Glasshit.ogg', 50, 1) + +/obj/structure/window/attack_hand(mob/user as mob) + user.setClickCooldown(user.get_attack_speed()) + if(HULK in user.mutations) + user.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!")) + user.visible_message("[user] smashes through [src]!") + user.do_attack_animation(src) + shatter() + + else if (usr.a_intent == I_HURT) + + if (istype(usr,/mob/living/carbon/human)) + var/mob/living/carbon/human/H = usr + if(H.species.can_shred(H)) + attack_generic(H,25) + return + + playsound(src, 'sound/effects/glassknock.ogg', 80, 1) + user.do_attack_animation(src) + usr.visible_message("\The [usr] bangs against \the [src]!", + "You bang against \the [src]!", + "You hear a banging sound.") + else + playsound(src, 'sound/effects/glassknock.ogg', 80, 1) + usr.visible_message("[usr.name] knocks on the [src.name].", + "You knock on the [src.name].", + "You hear a knocking sound.") + return + +/obj/structure/window/attack_generic(var/mob/user, var/damage) + user.setClickCooldown(user.get_attack_speed()) + if(!damage) + return + if(damage >= STRUCTURE_MIN_DAMAGE_THRESHOLD) + visible_message("[user] smashes into [src]!") + if(reinf) + damage = damage / 2 + take_damage(damage) + else + visible_message("\The [user] bonks \the [src] harmlessly.") + user.do_attack_animation(src) + return 1 + +/obj/structure/window/attackby(obj/item/W as obj, mob/user as mob) + if(!istype(W)) return//I really wish I did not need this + + // Fixing. + if(istype(W, /obj/item/weapon/weldingtool) && user.a_intent == I_HELP) + var/obj/item/weapon/weldingtool/WT = W + if(health < maxhealth) + if(WT.remove_fuel(1 ,user)) + to_chat(user, "You begin repairing [src]...") + playsound(src, WT.usesound, 50, 1) + if(do_after(user, 40 * WT.toolspeed, target = src)) + health = maxhealth + // playsound(src, 'sound/items/Welder.ogg', 50, 1) + update_icon() + to_chat(user, "You repair [src].") + else + to_chat(user, "[src] is already in good condition!") + return + + // Slamming. + if (istype(W, /obj/item/weapon/grab) && get_dist(src,user)<2) + var/obj/item/weapon/grab/G = W + if(istype(G.affecting,/mob/living)) + var/mob/living/M = G.affecting + var/state = G.state + qdel(W) //gotta delete it here because if window breaks, it won't get deleted + switch (state) + if(1) + M.visible_message("[user] slams [M] against \the [src]!") + M.apply_damage(7) + hit(10) + if(2) + M.visible_message("[user] bashes [M] against \the [src]!") + if (prob(50)) + M.Weaken(1) + M.apply_damage(10) + hit(25) + if(3) + M.visible_message("[user] crushes [M] against \the [src]!") + M.Weaken(5) + M.apply_damage(20) + hit(50) + return + + if(W.flags & NOBLUDGEON) return + + if(W.is_screwdriver()) + if(reinf && state >= 1) + state = 3 - state + update_nearby_icons() + playsound(src, W.usesound, 75, 1) + to_chat(user, "You have [state == 1 ? "un" : ""]fastened the window [state ? "from" : "to"] the frame.") + else if(reinf && state == 0) + anchored = !anchored + update_nearby_tiles(need_rebuild=1) + update_nearby_icons() + update_verbs() + playsound(src, W.usesound, 75, 1) + to_chat(user, "You have [anchored ? "" : "un"]fastened the frame [anchored ? "to" : "from"] the floor.") + else if(!reinf) + anchored = !anchored + update_nearby_tiles(need_rebuild=1) + update_nearby_icons() + update_verbs() + playsound(src, W.usesound, 75, 1) + to_chat(user, "You have [anchored ? "" : "un"]fastened the window [anchored ? "to" : "from"] the floor.") + else if(W.is_crowbar() && reinf && state <= 1) + state = 1 - state + playsound(src, W.usesound, 75, 1) + to_chat(user, "You have pried the window [state ? "into" : "out of"] the frame.") + else if(W.is_wrench() && !anchored && (!state || !reinf)) + if(!glasstype) + to_chat(user, "You're not sure how to dismantle \the [src] properly.") + else + playsound(src, W.usesound, 75, 1) + visible_message("[user] dismantles \the [src].") + var/obj/item/stack/material/mats = new glasstype(loc) + if(is_fulltile()) + mats.set_amount(4) + qdel(src) + else if(istype(W, /obj/item/stack/cable_coil) && reinf && state == 0 && !istype(src, /obj/structure/window/reinforced/polarized)) + var/obj/item/stack/cable_coil/C = W + if (C.use(1)) + playsound(src, 'sound/effects/sparks1.ogg', 75, 1) + user.visible_message( \ + "\The [user] begins to wire \the [src] for electrochromic tinting.", \ + "You begin to wire \the [src] for electrochromic tinting.", \ + "You hear sparks.") + if(do_after(user, 20 * C.toolspeed, src) && state == 0) + playsound(src, 'sound/items/Deconstruct.ogg', 50, 1) + var/obj/structure/window/reinforced/polarized/P = new(loc, dir) + if(is_fulltile()) + P.fulltile = TRUE + P.icon_state = "fwindow" + P.maxhealth = maxhealth + P.health = health + P.state = state + P.anchored = anchored + qdel(src) + else if(istype(W,/obj/item/frame) && anchored) + var/obj/item/frame/F = W + F.try_build(src, user) + else + user.setClickCooldown(user.get_attack_speed(W)) + if(W.damtype == BRUTE || W.damtype == BURN) + user.do_attack_animation(src) + hit(W.force) + if(health <= 7) + anchored = FALSE + update_nearby_icons() + step(src, get_dir(user, src)) + else + playsound(src, 'sound/effects/Glasshit.ogg', 75, 1) + ..() + return + +/obj/structure/window/proc/hit(var/damage, var/sound_effect = 1) + if(damage < force_threshold || force_threshold < 0) + return + if(reinf) damage *= 0.5 + take_damage(damage) + return + + +/obj/structure/window/verb/rotate_counterclockwise() + set name = "Rotate Window Counterclockwise" + set category = "Object" + set src in oview(1) + + if(usr.incapacitated()) + return 0 + + if(is_fulltile()) + return 0 + + if(anchored) + to_chat(usr, "It is fastened to the floor therefore you can't rotate it!") + return 0 + + update_nearby_tiles(need_rebuild=1) //Compel updates before + src.set_dir(turn(src.dir, 90)) + updateSilicate() + update_nearby_tiles(need_rebuild=1) + return + + +/obj/structure/window/verb/rotate_clockwise() + set name = "Rotate Window Clockwise" + set category = "Object" + set src in oview(1) + + if(usr.incapacitated()) + return 0 + + if(is_fulltile()) + return 0 + + if(anchored) + to_chat(usr, "It is fastened to the floor therefore you can't rotate it!") + return 0 + + update_nearby_tiles(need_rebuild=1) //Compel updates before + src.set_dir(turn(src.dir, 270)) + updateSilicate() + update_nearby_tiles(need_rebuild=1) + return + +/obj/structure/window/New(Loc, start_dir=null, constructed=0) + ..() + + if (start_dir) + set_dir(start_dir) + + //player-constructed windows + if (constructed) + anchored = FALSE + state = 0 + update_verbs() + + health = maxhealth + + ini_dir = dir + + update_nearby_tiles(need_rebuild=1) + update_nearby_icons() + + +/obj/structure/window/Destroy() + density = FALSE + update_nearby_tiles() + var/turf/location = loc + . = ..() + for(var/obj/structure/window/W in orange(location, 1)) + W.update_icon() + +/obj/structure/window/Move() + var/ini_dir = dir + update_nearby_tiles(need_rebuild=1) + . = ..() + set_dir(ini_dir) + update_nearby_tiles(need_rebuild=1) + +//checks if this window is full-tile one +/obj/structure/window/proc/is_fulltile() + return fulltile + +/obj/structure/window/is_between_turfs(var/turf/origin, var/turf/target) + if(is_fulltile()) + return TRUE + return ..() + +//This proc is used to update the icons of nearby windows. It should not be confused with update_nearby_tiles(), which is an atmos proc! +/obj/structure/window/proc/update_nearby_icons() + update_icon() + for(var/obj/structure/window/W in orange(src, 1)) + W.update_icon() + +//Updates the availabiliy of the rotation verbs +/obj/structure/window/proc/update_verbs() + if(anchored || is_fulltile()) + verbs -= /obj/structure/window/verb/rotate_counterclockwise + verbs -= /obj/structure/window/verb/rotate_clockwise + else if(!is_fulltile()) + verbs += /obj/structure/window/verb/rotate_counterclockwise + verbs += /obj/structure/window/verb/rotate_clockwise + +//merges adjacent full-tile windows into one (blatant ripoff from game/smoothwall.dm) +/obj/structure/window/update_icon() + //A little cludge here, since I don't know how it will work with slim windows. Most likely VERY wrong. + //this way it will only update full-tile ones + cut_overlays() + if(!is_fulltile()) + // Rotate the sprite somewhat so non-fulltiled windows can be seen as needing repair. + var/full_tilt_degrees = 15 + var/tilt_to_apply = abs((health / maxhealth) - 1) + if(tilt_to_apply && prob(50)) + tilt_to_apply = -tilt_to_apply + adjust_rotation(LERP(0, full_tilt_degrees, tilt_to_apply)) + + icon_state = "[basestate]" + return + else + flags = 0 // Removes ON_BORDER and OPPOSITE_OPACITY + var/list/dirs = list() + if(anchored) + for(var/obj/structure/window/W in orange(src,1)) + if(W.anchored && W.density && W.glasstype == src.glasstype && W.is_fulltile()) //Only counts anchored, not-destroyed fill-tile windows. + dirs += get_dir(src, W) + + var/list/connections = dirs_to_corner_states(dirs) + + icon_state = "" + for(var/i = 1 to 4) + var/image/I = image(icon, "[basestate][connections[i]]", dir = 1<<(i-1)) + add_overlay(I) + + // Damage overlays. + var/ratio = health / maxhealth + ratio = CEILING(ratio * 4, 1) * 25 + + if(ratio > 75) + return + var/image/I = image(icon, "damage[ratio]", layer = layer + 0.1) + add_overlay(I) + + return + +/obj/structure/window/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) + if(exposed_temperature > maximal_heat) + hit(damage_per_fire_tick, 0) + ..() + + + +/obj/structure/window/basic + desc = "It looks thin and flimsy. A few knocks with... almost anything, really should shatter it." + icon_state = "window" + basestate = "window" + glasstype = /obj/item/stack/material/glass + maximal_heat = T0C + 100 + damage_per_fire_tick = 2.0 + maxhealth = 12.0 + force_threshold = 3 + +/obj/structure/window/basic/full + icon_state = "window-full" + maxhealth = 24 + fulltile = TRUE + flags = 0 + +/obj/structure/window/phoronbasic + name = "phoron window" + desc = "A borosilicate alloy window. It seems to be quite strong." + basestate = "phoronwindow" + icon_state = "phoronwindow" + shardtype = /obj/item/weapon/material/shard/phoron + glasstype = /obj/item/stack/material/glass/phoronglass + maximal_heat = T0C + 2000 + damage_per_fire_tick = 1.0 + maxhealth = 40.0 + force_threshold = 5 + +/obj/structure/window/phoronbasic/full + icon_state = "phoronwindow-full" + maxhealth = 80 + fulltile = TRUE + flags = 0 + +/obj/structure/window/phoronreinforced + name = "reinforced borosilicate window" + desc = "A borosilicate alloy window, with rods supporting it. It seems to be very strong." + basestate = "phoronrwindow" + icon_state = "phoronrwindow" + shardtype = /obj/item/weapon/material/shard/phoron + glasstype = /obj/item/stack/material/glass/phoronrglass + reinf = 1 + maximal_heat = T0C + 4000 + damage_per_fire_tick = 1.0 // This should last for 80 fire ticks if the window is not damaged at all. The idea is that borosilicate windows have something like ablative layer that protects them for a while. + maxhealth = 80.0 + force_threshold = 10 + +/obj/structure/window/phoronreinforced/full + icon_state = "phoronrwindow-full" + maxhealth = 160 + fulltile = TRUE + flags = 0 + +/obj/structure/window/reinforced + name = "reinforced window" + desc = "It looks rather strong. Might take a few good hits to shatter it." + icon_state = "rwindow" + basestate = "rwindow" + maxhealth = 40.0 + reinf = 1 + maximal_heat = T0C + 750 + damage_per_fire_tick = 2.0 + glasstype = /obj/item/stack/material/glass/reinforced + force_threshold = 6 + +/obj/structure/window/reinforced/full + icon_state = "rwindow-full" + maxhealth = 80 + fulltile = TRUE + flags = 0 + +/obj/structure/window/reinforced/tinted + name = "tinted window" + desc = "It looks rather strong and opaque. Might take a few good hits to shatter it." + icon_state = "twindow" + basestate = "twindow" + opacity = 1 + +/obj/structure/window/reinforced/tinted/frosted + name = "frosted window" + desc = "It looks rather strong and frosted over. Looks like it might take a few less hits then a normal reinforced window." + icon_state = "fwindow" + basestate = "fwindow" + maxhealth = 30 + force_threshold = 5 + +/obj/structure/window/shuttle + name = "shuttle window" + desc = "It looks rather strong. Might take a few good hits to shatter it." + icon = 'icons/obj/podwindows.dmi' + icon_state = "window" + basestate = "window" + maxhealth = 40 + reinf = 1 + basestate = "w" + dir = 5 + force_threshold = 7 + +/obj/structure/window/reinforced/polarized + name = "electrochromic window" + desc = "Adjusts its tint with voltage. Might take a few good hits to shatter it." + var/id + +/obj/structure/window/reinforced/polarized/full + icon_state = "rwindow-full" + maxhealth = 80 + fulltile = TRUE + flags = 0 + +/obj/structure/window/reinforced/polarized/attackby(obj/item/W as obj, mob/user as mob) + if(istype(W, /obj/item/device/multitool) && !anchored) // Only allow programming if unanchored! + var/obj/item/device/multitool/MT = W + // First check if they have a windowtint button buffered + if(istype(MT.connectable, /obj/machinery/button/windowtint)) + var/obj/machinery/button/windowtint/buffered_button = MT.connectable + src.id = buffered_button.id + to_chat(user, "\The [src] is linked to \the [buffered_button] with ID '[id]'.") + return TRUE + // Otherwise fall back to asking them... and remind them what the current ID is. + if(id) + to_chat(user, "The window's current ID is [id].") + var/t = sanitizeSafe(input(user, "Enter the new ID for the window.", src.name, null), MAX_NAME_LEN) + if(t && in_range(src, user)) + src.id = t + to_chat(user, "The new ID of \the [src] is '[id]'.") + return TRUE + . = ..() + +/obj/structure/window/reinforced/polarized/proc/toggle() + if(opacity) + animate(src, color="#FFFFFF", time=5) + set_opacity(0) + else + animate(src, color="#222222", time=5) + set_opacity(1) + var/turf/T = get_turf(src) + T.recalculate_directional_opacity() + +/obj/machinery/button/windowtint + name = "window tint control" + icon = 'icons/obj/stationobjs_vr.dmi' // VOREStation Edit - New icons + icon_state = "light0" + desc = "A remote control switch for polarized windows." + var/range = 7 + circuit = /obj/item/weapon/circuitboard/electrochromic + +/obj/machinery/button/windowtint/attack_hand(mob/user as mob) + if(..()) + return 1 + + toggle_tint() + +/obj/machinery/button/windowtint/proc/toggle_tint() + use_power(5) + + active = !active + update_icon() + + for(var/obj/structure/window/reinforced/polarized/W in range(src,range)) + if (W.id == src.id || !W.id) + spawn(0) + W.toggle() + return + +/obj/machinery/button/windowtint/power_change() + ..() + if(active && !powered(power_channel)) + toggle_tint() + +/obj/machinery/button/windowtint/update_icon() + icon_state = "light[active]" + +/obj/machinery/button/windowtint/attackby(obj/item/W as obj, mob/user as mob) + if(default_deconstruction_screwdriver(user, W)) + return + else if(alarm_deconstruction_wirecutters(user, W)) + return + else if(istype(W, /obj/item/device/multitool)) + var/obj/item/device/multitool/MT = W + if(!id) + // If no ID is set yet (newly built button?) let them select an ID for first-time use! + var/t = sanitizeSafe(tgui_input_text(user, "Enter an ID for \the [src].", src.name, null, MAX_NAME_LEN), MAX_NAME_LEN) + if (t && in_range(src, user)) + src.id = t + to_chat(user, "The new ID of \the [src] is '[id]'. To reset this, rebuild the control.") + if(id) + // It already has an ID (or they just set one), buffer it for copying to windows. + to_chat(user, "You store \the [src] ID ('[id]') in \the [MT]'s buffer!") + MT.connectable = src + MT.update_icon() + return TRUE + . = ..() + +/obj/structure/window/rcd_values(mob/living/user, obj/item/weapon/rcd/the_rcd, passed_mode) + switch(passed_mode) + if(RCD_DECONSTRUCT) + return list( + RCD_VALUE_MODE = RCD_DECONSTRUCT, + RCD_VALUE_DELAY = 5 SECONDS, + RCD_VALUE_COST = RCD_SHEETS_PER_MATTER_UNIT * 5 + ) + +/obj/structure/window/rcd_act(mob/living/user, obj/item/weapon/rcd/the_rcd, passed_mode) + switch(passed_mode) + if(RCD_DECONSTRUCT) + to_chat(user, span("notice", "You deconstruct \the [src].")) + qdel(src) + return TRUE + return FALSE +>>>>>>> e047e89ba7... Merge pull request #14638 from VOREStation/upstream-merge-9002 diff --git a/code/modules/materials/materials/organic/grass.dm b/code/modules/materials/materials/organic/grass.dm new file mode 100644 index 0000000000..4f2af4541e --- /dev/null +++ b/code/modules/materials/materials/organic/grass.dm @@ -0,0 +1,31 @@ +/datum/material/grass + name = MAT_GRASS + display_name = "grass" + stack_type = /obj/item/stack/tile/grass + ignition_point = T0C+300 + melting_point = T0C+300 + protectiveness = 0 + conductive = 0 + integrity = 10 + supply_conversion_value = 1 + +/datum/material/grass/generate_recipes() + recipes = list( + new /datum/stack_recipe_list("bushes and flowers",list( + new /datum/stack_recipe("bush", /obj/structure/flora/ausbushes, 3, one_per_turf = 0, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("reed bush", /obj/structure/flora/ausbushes/reedbush, 3, one_per_turf = 0, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("leafy bush", /obj/structure/flora/ausbushes/leafybush, 3, one_per_turf = 0, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("pale bush", /obj/structure/flora/ausbushes/palebush, 3, one_per_turf = 0, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("stalky bush", /obj/structure/flora/ausbushes/stalkybush, 3, one_per_turf = 0, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("grassy bush", /obj/structure/flora/ausbushes/grassybush, 3, one_per_turf = 0, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("ferny bush", /obj/structure/flora/ausbushes/fernybush, 3, one_per_turf = 0, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("sunny bush", /obj/structure/flora/ausbushes/sunnybush, 3, one_per_turf = 0, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("pointy bush", /obj/structure/flora/ausbushes/pointybush, 3, one_per_turf = 0, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("lavender grass", /obj/structure/flora/ausbushes/lavendergrass, 3, one_per_turf = 0, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("yellow-and-white flowers", /obj/structure/flora/ausbushes/ywflowers, 3, one_per_turf = 0, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("blue-and-red flowers", /obj/structure/flora/ausbushes/brflowers, 3, one_per_turf = 0, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("pink-and-purple flowers", /obj/structure/flora/ausbushes/ppflowers, 3, one_per_turf = 0, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("sparse grass", /obj/structure/flora/ausbushes/sparsegrass, 3, one_per_turf = 0, on_floor = 1, recycle_material = "[name]"), + new /datum/stack_recipe("full grass", /obj/structure/flora/ausbushes/fullgrass, 3, one_per_turf = 0, on_floor = 1, recycle_material = "[name]") + )) + ) \ No newline at end of file diff --git a/icons/obj/stock_parts.dmi b/icons/obj/stock_parts.dmi index 1f58fb9330..30baa36e3c 100644 Binary files a/icons/obj/stock_parts.dmi and b/icons/obj/stock_parts.dmi differ diff --git a/icons/obj/stock_parts_vr.dmi b/icons/obj/stock_parts_vr.dmi index 7b078871a7..8e48a4c0a3 100644 Binary files a/icons/obj/stock_parts_vr.dmi and b/icons/obj/stock_parts_vr.dmi differ diff --git a/vorestation.dme b/vorestation.dme index a7bb4de2cb..ac875c6288 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -2800,7 +2800,11 @@ #include "code\modules\materials\materials\metals\steel_vr.dm" #include "code\modules\materials\materials\organic\animal_products.dm" #include "code\modules\materials\materials\organic\cloth.dm" +<<<<<<< HEAD #include "code\modules\materials\materials\organic\cloth_ch.dm" +======= +#include "code\modules\materials\materials\organic\grass.dm" +>>>>>>> e047e89ba7... Merge pull request #14638 from VOREStation/upstream-merge-9002 #include "code\modules\materials\materials\organic\leather.dm" #include "code\modules\materials\materials\organic\resin.dm" #include "code\modules\materials\materials\organic\wood.dm"