From 4b877990725631c3d768e7a3dc9ccd9e93389695 Mon Sep 17 00:00:00 2001 From: GinjaNinja32 Date: Wed, 13 May 2015 19:08:39 +0100 Subject: [PATCH] New tables, code section. Changelog entry soon. --- baystation12.dme | 8 +- code/game/gamemodes/cult/cultify/obj.dm | 12 +- .../game/objects/items/stacks/sheets/glass.dm | 1 + .../objects/items/stacks/sheets/mineral.dm | 1 + .../items/stacks/sheets/sheet_types.dm | 5 +- .../objects/items/weapons/table_rack_parts.dm | 101 ---- code/game/objects/structures/tables_racks.dm | 558 ------------------ code/modules/holodeck/HolodeckObjects.dm | 49 +- code/modules/materials/materials.dm | 10 +- .../living/silicon/robot/drone/drone_items.dm | 2 - .../living/simple_animal/hostile/hostile.dm | 2 +- code/modules/tables/flipping.dm | 116 ++++ code/modules/tables/interactions.dm | 122 ++++ code/modules/tables/presets.dm | 110 ++++ code/modules/tables/rack.dm | 26 + code/modules/tables/tables.dm | 337 +++++++++++ code/modules/tables/update_triggers.dm | 22 + icons/obj/tables.dmi | Bin 0 -> 22339 bytes 18 files changed, 765 insertions(+), 717 deletions(-) delete mode 100644 code/game/objects/items/weapons/table_rack_parts.dm delete mode 100644 code/game/objects/structures/tables_racks.dm create mode 100644 code/modules/tables/flipping.dm create mode 100644 code/modules/tables/interactions.dm create mode 100644 code/modules/tables/presets.dm create mode 100644 code/modules/tables/rack.dm create mode 100644 code/modules/tables/tables.dm create mode 100644 code/modules/tables/update_triggers.dm create mode 100644 icons/obj/tables.dmi diff --git a/baystation12.dme b/baystation12.dme index a1074dc190..42f98251f3 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -629,7 +629,6 @@ #include "code\game\objects\items\weapons\stunbaton.dm" #include "code\game\objects\items\weapons\surgery_tools.dm" #include "code\game\objects\items\weapons\swords_axes_etc.dm" -#include "code\game\objects\items\weapons\table_rack_parts.dm" #include "code\game\objects\items\weapons\tape.dm" #include "code\game\objects\items\weapons\teleportation.dm" #include "code\game\objects\items\weapons\tools.dm" @@ -718,7 +717,6 @@ #include "code\game\objects\structures\noticeboard.dm" #include "code\game\objects\structures\safe.dm" #include "code\game\objects\structures\signs.dm" -#include "code\game\objects\structures\tables_racks.dm" #include "code\game\objects\structures\tank_dispenser.dm" #include "code\game\objects\structures\target_stake.dm" #include "code\game\objects\structures\transit_tubes.dm" @@ -1646,6 +1644,12 @@ #include "code\modules\surgery\robolimbs.dm" #include "code\modules\surgery\slimes.dm" #include "code\modules\surgery\surgery.dm" +#include "code\modules\tables\flipping.dm" +#include "code\modules\tables\interactions.dm" +#include "code\modules\tables\presets.dm" +#include "code\modules\tables\rack.dm" +#include "code\modules\tables\tables.dm" +#include "code\modules\tables\update_triggers.dm" #include "code\modules\vehicles\cargo_train.dm" #include "code\modules\vehicles\train.dm" #include "code\modules\vehicles\vehicle.dm" diff --git a/code/game/gamemodes/cult/cultify/obj.dm b/code/game/gamemodes/cult/cultify/obj.dm index 630877eb11..fd239df50f 100644 --- a/code/game/gamemodes/cult/cultify/obj.dm +++ b/code/game/gamemodes/cult/cultify/obj.dm @@ -149,8 +149,12 @@ ..() /obj/structure/table/cultify() - new /obj/structure/table/woodentable(loc) - ..() + // Make it a wood-reinforced wooden table. + // There are cult materials available, but it'd make the table non-deconstructable with how holotables work. + // Could possibly use a new material var for holographic-ness? + material = name_to_material["wood"] + reinforced = name_to_material["wood"] + update_desc() + update_connections(1) + update_icon() -/obj/structure/table/woodentable/cultify() - return diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm index a4d9e631e8..bbb8e32736 100644 --- a/code/game/objects/items/stacks/sheets/glass.dm +++ b/code/game/objects/items/stacks/sheets/glass.dm @@ -20,6 +20,7 @@ var/created_window = /obj/structure/window/basic var/is_reinforced = 0 var/list/construction_options = list("One Direction", "Full Window") + sheettype = "glass" /obj/item/stack/sheet/glass/cyborg name = "glass synthesizer" diff --git a/code/game/objects/items/stacks/sheets/mineral.dm b/code/game/objects/items/stacks/sheets/mineral.dm index 46415bb8af..1e6fd887f5 100644 --- a/code/game/objects/items/stacks/sheets/mineral.dm +++ b/code/game/objects/items/stacks/sheets/mineral.dm @@ -134,6 +134,7 @@ obj/item/stack/sheet/mineral/iron/New() icon_state = "sheet-plastic" origin_tech = "materials=3" perunit = 2000 + sheettype = "plastic" /obj/item/stack/sheet/mineral/plastic/New() ..() diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index 1fefeca1ab..bf35253b08 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -31,8 +31,8 @@ var/global/list/datum/stack_recipe/metal_recipes = list ( \ new/datum/stack_recipe("green comfy chair", /obj/structure/bed/chair/comfy/green, 2, one_per_turf = 1, on_floor = 1), \ ), 2), \ null, \ - new/datum/stack_recipe("table parts", /obj/item/weapon/table_parts, 2), \ - new/datum/stack_recipe("rack parts", /obj/item/weapon/table_parts/rack), \ + new/datum/stack_recipe("table frame", /obj/structure/table, 1, time = 10, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("rack", /obj/structure/table/rack, 1, time = 5, one_per_turf = 1, on_floor = 1), \ new/datum/stack_recipe("metal baseball bat", /obj/item/weapon/twohanded/baseballbat/metal, 10, time = 20, one_per_turf = 0, on_floor = 1), \ new/datum/stack_recipe("closet", /obj/structure/closet, 2, time = 15, one_per_turf = 1, on_floor = 1), \ null, \ @@ -163,6 +163,7 @@ var/global/list/datum/stack_recipe/wood_recipes = list ( \ singular_name = "wood plank" icon_state = "sheet-wood" origin_tech = "materials=1;biotech=1" + sheettype = "wood" /obj/item/stack/sheet/wood/cyborg name = "wood synthesizer" diff --git a/code/game/objects/items/weapons/table_rack_parts.dm b/code/game/objects/items/weapons/table_rack_parts.dm deleted file mode 100644 index 8437a5e29f..0000000000 --- a/code/game/objects/items/weapons/table_rack_parts.dm +++ /dev/null @@ -1,101 +0,0 @@ -// Table parts and rack parts - -/obj/item/weapon/table_parts - name = "table parts" - desc = "Parts of a table. Poor table." - gender = PLURAL - icon = 'icons/obj/items.dmi' - icon_state = "table_parts" - matter = list(DEFAULT_WALL_MATERIAL = 3750) - flags = CONDUCT - attack_verb = list("slammed", "bashed", "battered", "bludgeoned", "thrashed", "whacked") - - var/build_type = /obj/structure/table - var/alter_type = /obj/item/weapon/table_parts/reinforced - var/alter_with = /obj/item/stack/rods - var/alter_cost = 4 - var/list/stack_types = list(/obj/item/stack/sheet/metal) - -/obj/item/weapon/table_parts/attackby(obj/item/weapon/W as obj, mob/user as mob) - if (istype(W, /obj/item/weapon/wrench)) - for(var/material_type in stack_types) - new material_type(get_turf(user)) - qdel(src) - return - else - if(alter_type && alter_with && istype(W,alter_with)) - var/obj/item/stack/R = W - if (R.use(alter_cost)) - var/obj/item/new_parts = new alter_type (get_turf(loc)) - user << "You modify \the [name] into \a [new_parts]." - qdel(src) - else - user << "You need at least [alter_cost] sheets to reinforce the [name]." - return - ..() - -/obj/item/weapon/table_parts/attack_self(mob/user as mob) - if(locate(/obj/structure/table) in user.loc) - user << "There is already a table here." - return - - new build_type( user.loc ) - user.drop_item() - qdel(src) - return - -/obj/item/weapon/table_parts/reinforced - name = "reinforced table parts" - desc = "Hard table parts. Well... harder." - icon = 'icons/obj/items.dmi' - icon_state = "reinf_tableparts" - matter = list(DEFAULT_WALL_MATERIAL = 7500) - flags = CONDUCT - - stack_types = list(/obj/item/stack/sheet/metal, /obj/item/stack/rods) - build_type = /obj/structure/table/reinforced - alter_type = null - alter_with = null - alter_cost = null - -/obj/item/weapon/table_parts/wood - name = "wooden table parts" - desc = "Keep away from fire." - icon_state = "wood_tableparts" - flags = null - - stack_types = list(/obj/item/stack/sheet/wood) - build_type = /obj/structure/table/woodentable - alter_type = /obj/item/weapon/table_parts/gambling - alter_with = /obj/item/stack/tile/carpet - alter_cost = 1 - -/obj/item/weapon/table_parts/gambling - name = "gambling table parts" - desc = "Keep away from security." - icon_state = "gamble_tableparts" - flags = null - - stack_types = list(/obj/item/stack/tile/carpet,/obj/item/stack/sheet/wood) - build_type = /obj/structure/table/gamblingtable - alter_type = null - alter_with = null - alter_cost = null - -/obj/item/weapon/table_parts/gambling/attackby(obj/item/weapon/W as obj, mob/user as mob) - if (istype(W, /obj/item/weapon/crowbar)) - new /obj/item/stack/tile/carpet( get_turf(loc) ) - new /obj/item/weapon/table_parts/wood( get_turf(loc) ) - user << "You pry the carpet out of the table." - qdel(src) - ..() - -/obj/item/weapon/table_parts/rack - name = "rack parts" - desc = "Parts of a rack." - icon_state = "rack_parts" - stack_types = list(/obj/item/stack/sheet/metal) - build_type = /obj/structure/table/rack - alter_type = null - alter_with = null - alter_cost = null \ No newline at end of file diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm deleted file mode 100644 index f206bfc11f..0000000000 --- a/code/game/objects/structures/tables_racks.dm +++ /dev/null @@ -1,558 +0,0 @@ -// Tables and racks. - -/obj/structure/table - name = "table" - desc = "A square piece of metal standing on four metal legs. It can not move." - icon = 'icons/obj/structures.dmi' - icon_state = "table" - density = 1 - anchored = 1 - layer = 2.8 - throwpass = 1 - climbable = 1 - breakable = 1 - parts = /obj/item/weapon/table_parts - - var/flipped = 0 - var/health = 100 - -/obj/structure/table/woodentable - name = "wooden table" - desc = "Do not apply fire to this. Rumour says it burns easily." - icon_state = "wood_table" - parts = /obj/item/weapon/table_parts/wood - health = 50 - -/obj/structure/table/gamblingtable - name = "gambling table" - desc = "A curved wooden table with a thin carpet of green fabric." - icon_state = "gamble_table" - parts = /obj/item/weapon/table_parts/gambling - health = 50 - -/obj/structure/table/reinforced - icon_state = "reinf_table" - health = 200 - parts = /obj/item/weapon/table_parts/reinforced - -/obj/structure/table/rack - name = "rack" - desc = "Different from the Middle Ages version." - icon = 'icons/obj/objects.dmi' - icon_state = "rack" - health = 100 - parts = /obj/item/weapon/table_parts/rack - flipped = -1 //Cannot flip. - -/obj/structure/table/examine() - ..() - if(health > 100) - usr << "This one looks like it has been reinforced." - -/obj/structure/table/proc/update_adjacent() - for(var/direction in list(1,2,4,8,5,6,9,10)) - if(locate(/obj/structure/table,get_step(src,direction))) - var/obj/structure/table/T = locate(/obj/structure/table,get_step(src,direction)) - T.update_icon() - -/obj/structure/table/New() - ..() - for(var/obj/structure/table/T in src.loc) - if(T != src) - qdel(T) - update_icon() - update_adjacent() - -/obj/structure/table/Destroy() - update_adjacent() - ..() - -/obj/structure/table/update_icon() - - if(health > 100) - name = "reinforced [initial(name)]" - - spawn(2) //So it properly updates when deleting - - if(flipped == 1) - var/type = 0 - var/tabledirs = 0 - for(var/direction in list(turn(dir,90), turn(dir,-90)) ) - var/obj/structure/table/T = locate(/obj/structure/table,get_step(src,direction)) - if (T && T.flipped == 1 && T.dir == src.dir) - type++ - tabledirs |= direction - var/base = "table" - if (istype(src, /obj/structure/table/woodentable)) - base = "wood" - if (istype(src, /obj/structure/table/reinforced)) - base = "rtable" - - icon_state = "[base]flip[type]" - if (type==1) - if (tabledirs & turn(dir,90)) - icon_state = icon_state+"-" - if (tabledirs & turn(dir,-90)) - icon_state = icon_state+"+" - return 1 - - var/dir_sum = 0 - for(var/direction in list(1,2,4,8,5,6,9,10)) - var/skip_sum = 0 - for(var/obj/structure/window/W in src.loc) - if(W.dir == direction) //So smooth tables don't go smooth through windows - skip_sum = 1 - continue - var/inv_direction //inverse direction - switch(direction) - if(1) - inv_direction = 2 - if(2) - inv_direction = 1 - if(4) - inv_direction = 8 - if(8) - inv_direction = 4 - if(5) - inv_direction = 10 - if(6) - inv_direction = 9 - if(9) - inv_direction = 6 - if(10) - inv_direction = 5 - for(var/obj/structure/window/W in get_step(src,direction)) - if(W.dir == inv_direction) //So smooth tables don't go smooth through windows when the window is on the other table's tile - skip_sum = 1 - continue - if(!skip_sum) //means there is a window between the two tiles in this direction - var/obj/structure/table/T = locate(/obj/structure/table,get_step(src,direction)) - if(T && T.flipped == 0) // This should let us ignore racks for table icons/flipping. Should. - if(direction <5) - dir_sum += direction - else - if(direction == 5) //This permits the use of all table directions. (Set up so clockwise around the central table is a higher value, from north) - dir_sum += 16 - if(direction == 6) - dir_sum += 32 - if(direction == 8) //Aherp and Aderp. Jezes I am stupid. -- SkyMarshal - dir_sum += 8 - if(direction == 10) - dir_sum += 64 - if(direction == 9) - dir_sum += 128 - - var/table_type = 0 //stand_alone table - if(dir_sum%16 in cardinal) - table_type = 1 //endtable - dir_sum %= 16 - if(dir_sum%16 in list(3,12)) - table_type = 2 //1 tile thick, streight table - if(dir_sum%16 == 3) //3 doesn't exist as a dir - dir_sum = 2 - if(dir_sum%16 == 12) //12 doesn't exist as a dir. - dir_sum = 4 - if(dir_sum%16 in list(5,6,9,10)) - if(locate(/obj/structure/table,get_step(src.loc,dir_sum%16))) - table_type = 3 //full table (not the 1 tile thick one, but one of the 'tabledir' tables) - else - table_type = 2 //1 tile thick, corner table (treated the same as streight tables in code later on) - dir_sum %= 16 - if(dir_sum%16 in list(13,14,7,11)) //Three-way intersection - table_type = 5 //full table as three-way intersections are not sprited, would require 64 sprites to handle all combinations. TOO BAD -- SkyMarshal - switch(dir_sum%16) //Begin computation of the special type tables. --SkyMarshal - if(7) - if(dir_sum == 23) - table_type = 6 - dir_sum = 8 - else if(dir_sum == 39) - dir_sum = 4 - table_type = 6 - else if(dir_sum == 55 || dir_sum == 119 || dir_sum == 247 || dir_sum == 183) - dir_sum = 4 - table_type = 3 - else - dir_sum = 4 - if(11) - if(dir_sum == 75) - dir_sum = 5 - table_type = 6 - else if(dir_sum == 139) - dir_sum = 9 - table_type = 6 - else if(dir_sum == 203 || dir_sum == 219 || dir_sum == 251 || dir_sum == 235) - dir_sum = 8 - table_type = 3 - else - dir_sum = 8 - if(13) - if(dir_sum == 29) - dir_sum = 10 - table_type = 6 - else if(dir_sum == 141) - dir_sum = 6 - table_type = 6 - else if(dir_sum == 189 || dir_sum == 221 || dir_sum == 253 || dir_sum == 157) - dir_sum = 1 - table_type = 3 - else - dir_sum = 1 - if(14) - if(dir_sum == 46) - dir_sum = 1 - table_type = 6 - else if(dir_sum == 78) - dir_sum = 2 - table_type = 6 - else if(dir_sum == 110 || dir_sum == 254 || dir_sum == 238 || dir_sum == 126) - dir_sum = 2 - table_type = 3 - else - dir_sum = 2 //These translate the dir_sum to the correct dirs from the 'tabledir' icon_state. - if(dir_sum%16 == 15) - table_type = 4 //4-way intersection, the 'middle' table sprites will be used. - - if(istype(src,/obj/structure/table/reinforced)) - switch(table_type) - if(0) - icon_state = "reinf_table" - if(1) - icon_state = "reinf_1tileendtable" - if(2) - icon_state = "reinf_1tilethick" - if(3) - icon_state = "reinf_tabledir" - if(4) - icon_state = "reinf_middle" - if(5) - icon_state = "reinf_tabledir2" - if(6) - icon_state = "reinf_tabledir3" - else if(istype(src,/obj/structure/table/woodentable)) - switch(table_type) - if(0) - icon_state = "wood_table" - if(1) - icon_state = "wood_1tileendtable" - if(2) - icon_state = "wood_1tilethick" - if(3) - icon_state = "wood_tabledir" - if(4) - icon_state = "wood_middle" - if(5) - icon_state = "wood_tabledir2" - if(6) - icon_state = "wood_tabledir3" - else if(istype(src,/obj/structure/table/gamblingtable)) - switch(table_type) - if(0) - icon_state = "gamble_table" - if(1) - icon_state = "gamble_1tileendtable" - if(2) - icon_state = "gamble_1tilethick" - if(3) - icon_state = "gamble_tabledir" - if(4) - icon_state = "gamble_middle" - if(5) - icon_state = "gamble_tabledir2" - if(6) - icon_state = "gamble_tabledir3" - else - switch(table_type) - if(0) - icon_state = "table" - if(1) - icon_state = "table_1tileendtable" - if(2) - icon_state = "table_1tilethick" - if(3) - icon_state = "tabledir" - if(4) - icon_state = "table_middle" - if(5) - icon_state = "tabledir2" - if(6) - icon_state = "tabledir3" - if (dir_sum in list(1,2,4,8,5,6,9,10)) - set_dir(dir_sum) - else - set_dir(2) - -/obj/structure/table/attack_tk() // no telehulk sorry - return - -/obj/structure/table/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) - if(air_group || (height==0)) return 1 - if(istype(mover,/obj/item/projectile)) - return (check_cover(mover,target)) - if(istype(mover) && mover.checkpass(PASSTABLE)) - return 1 - if(locate(/obj/structure/table) in get_turf(mover)) - return 1 - if (flipped == 1) - if (get_dir(loc, target) == dir) - return !density - else - return 1 - return 0 - -//checks if projectile 'P' from turf 'from' can hit whatever is behind the table. Returns 1 if it can, 0 if bullet stops. -/obj/structure/table/proc/check_cover(obj/item/projectile/P, turf/from) - var/turf/cover - if(flipped==1) - cover = get_turf(src) - else if(flipped==0) - cover = get_step(loc, get_dir(from, loc)) - if(!cover) - return 1 - if (get_dist(P.starting, loc) <= 1) //Tables won't help you if people are THIS close - return 1 - if (get_turf(P.original) == cover) - var/chance = 20 - if (ismob(P.original)) - var/mob/M = P.original - if (M.lying) - chance += 20 //Lying down lets you catch less bullets - if(flipped==1) - if(get_dir(loc, from) == dir) //Flipped tables catch mroe bullets - chance += 20 - else - return 1 //But only from one side - if(prob(chance)) - health -= P.damage/2 - if (health > 0) - visible_message("[P] hits \the [src]!") - return 0 - else - visible_message("[src] breaks down!") - qdel(src) - return 1 - return 1 - -/obj/structure/table/CheckExit(atom/movable/O as mob|obj, target as turf) - if(istype(O) && O.checkpass(PASSTABLE)) - return 1 - if (flipped==1) - if (get_dir(loc, target) == dir) - return !density - else - return 1 - return 1 - -/obj/structure/table/MouseDrop_T(obj/O as obj, mob/user as mob) - - if ((!( istype(O, /obj/item/weapon) ) || user.get_active_hand() != O)) - return ..() - if(isrobot(user)) - return - user.drop_item() - if (O.loc != src.loc) - step(O, get_dir(O, src)) - return - - -/obj/structure/table/attackby(obj/item/W as obj, mob/user as mob) - if (!W) return - - // Handle harm intent grabbing/tabling. - 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 - if (G.state < 2) - if(user.a_intent == I_HURT) - if (prob(15)) M.Weaken(5) - M.apply_damage(8,def_zone = "head") - visible_message("[G.assailant] slams [G.affecting]'s face against \the [src]!") - playsound(src.loc, 'sound/weapons/tablehit1.ogg', 50, 1) - else - user << "You need a better grip to do that!" - return - else - G.affecting.loc = src.loc - G.affecting.Weaken(5) - visible_message("[G.assailant] puts [G.affecting] on \the [src].") - qdel(W) - return - - // Handle dissembly. - if (istype(W, /obj/item/weapon/wrench)) - if(health > 100) - user << "\The [src] is too well constructed to be collapsed. Weaken it first." - return - user << "You locate the bolts and begin disassembling \the [src]..." - playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) - if(do_after(user,50)) - qdel(src) - return - - // Handle weakening. - if (istype(W, /obj/item/weapon/weldingtool)) - var/obj/item/weapon/weldingtool/WT = W - if(WT.isOn()) - if(initial(health)>100) - if(WT.remove_fuel(0, user)) - if(src.health>100) - user << "You start weakening \the [src]..." - playsound(src.loc, 'sound/items/Welder.ogg', 50, 1) - if(!do_after(user, 50) || !src || health<100 || !WT.isOn()) - return - user << "You have weakened \the [src]." - health -= 100 - else if(src.health <= 100) - user << "You start strengthening \the [src]..." - playsound(src.loc, 'sound/items/Welder.ogg', 50, 1) - if(!do_after(user, 50) || !src || health > 100 || !WT.isOn()) - return - user << "You have strengthened \the [src]." - health += 100 - update_icon() - else - user << "\The [src] is too flimsy to be reinforced or weakened." - return - - - // Handle dismantling or placing things on the table from here on. - if(isrobot(user)) - return - - if(W.loc != user) // This should stop mounted modules ending up outside the module. - return - - if(istype(W, /obj/item/weapon/melee/energy/blade)) - var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() - spark_system.set_up(5, 0, src.loc) - spark_system.start() - playsound(src.loc, 'sound/weapons/blade1.ogg', 50, 1) - playsound(src.loc, "sparks", 50, 1) - user.visible_message("The [src] was sliced apart by [user]!") - qdel(src) - - user.drop_item(src.loc) - return - -/obj/structure/table/proc/straight_table_check(var/direction) - var/obj/structure/table/T - for(var/angle in list(-90,90)) - T = locate() in get_step(src.loc,turn(direction,angle)) - if(T && T.flipped == 0) - return 0 - T = locate() in get_step(src.loc,direction) - if (!T || T.flipped == 1) - return 1 - if (istype(T,/obj/structure/table/reinforced/)) - var/obj/structure/table/reinforced/R = T - if (R.health > 100) - return 0 - return T.straight_table_check(direction) - -/obj/structure/table/verb/do_flip() - set name = "Flip table" - set desc = "Flips a non-reinforced table" - set category = "Object" - set src in oview(1) - - if (!can_touch(usr) || ismouse(usr)) - return - - if(flipped < 0 || !flip(get_cardinal_dir(usr,src))) - usr << "It won't budge." - return - - usr.visible_message("[usr] flips \the [src]!") - - if(climbable) - structure_shaken() - - return - -/obj/structure/table/proc/unflipping_check(var/direction) - - for(var/mob/M in oview(src,0)) - return 0 - - var/obj/occupied = turf_is_crowded() - if(occupied) - usr << "There's \a [occupied] in the way." - return 0 - - var/list/L = list() - if(direction) - L.Add(direction) - else - L.Add(turn(src.dir,-90)) - L.Add(turn(src.dir,90)) - for(var/new_dir in L) - var/obj/structure/table/T = locate() in get_step(src.loc,new_dir) - if(T) - if(T.flipped == 1 && T.dir == src.dir && !T.unflipping_check(new_dir)) - return 0 - return 1 - -/obj/structure/table/proc/do_put() - set name = "Put table back" - set desc = "Puts flipped table back" - set category = "Object" - set src in oview(1) - - if (!can_touch(usr)) - return - - if (!unflipping_check()) - usr << "It won't budge." - return - unflip() - -/obj/structure/table/proc/flip(var/direction) - if( !straight_table_check(turn(direction,90)) || !straight_table_check(turn(direction,-90)) ) - return 0 - - verbs -=/obj/structure/table/verb/do_flip - verbs +=/obj/structure/table/proc/do_put - - var/list/targets = list(get_step(src,dir),get_step(src,turn(dir, 45)),get_step(src,turn(dir, -45))) - for (var/atom/movable/A in get_turf(src)) - if (!A.anchored) - spawn(0) - A.throw_at(pick(targets),1,1) - - set_dir(direction) - if(dir != NORTH) - layer = 5 - climbable = 0 //flipping tables allows them to be used as makeshift barriers - flipped = 1 - flags |= ON_BORDER - for(var/D in list(turn(direction, 90), turn(direction, -90))) - var/obj/structure/table/T = locate() in get_step(src,D) - if(T && T.flipped == 0) - T.flip(direction) - update_icon() - update_adjacent() - - return 1 - -/obj/structure/table/proc/unflip() - verbs -=/obj/structure/table/proc/do_put - verbs +=/obj/structure/table/verb/do_flip - - layer = initial(layer) - flipped = 0 - climbable = initial(climbable) - flags &= ~ON_BORDER - for(var/D in list(turn(dir, 90), turn(dir, -90))) - var/obj/structure/table/T = locate() in get_step(src.loc,D) - if(T && T.flipped == 1 && T.dir == src.dir) - T.unflip() - update_icon() - update_adjacent() - - return 1 - -// No need to handle any of this, racks are not contiguous.. -/obj/structure/table/rack/update_icon() - return -/obj/structure/table/rack/update_adjacent() - return \ No newline at end of file diff --git a/code/modules/holodeck/HolodeckObjects.dm b/code/modules/holodeck/HolodeckObjects.dm index b463ec4209..6e5c4c4c5a 100644 --- a/code/modules/holodeck/HolodeckObjects.dm +++ b/code/modules/holodeck/HolodeckObjects.dm @@ -1,5 +1,8 @@ // Holographic Items! +// Holographic tables are in code/modules/tables/presets.dm +// Holographic racks are in code/modules/tables/rack.dm + /turf/simulated/floor/holofloor/ thermal_conductivity = 0 @@ -40,36 +43,6 @@ return // HOLOFLOOR DOES NOT GIVE A FUCK -/obj/structure/table/holotable - name = "table" - desc = "A square piece of metal standing on four metal legs. It can not move." - icon = 'icons/obj/structures.dmi' - icon_state = "table" - density = 1 - anchored = 1.0 - layer = 2.8 - throwpass = 1 //You can throw objects over this, despite it's density. - -/obj/structure/table/holotable/attack_hand(mob/user as mob) - return // HOLOTABLE DOES NOT GIVE A FUCK - - -/obj/structure/table/holotable/attackby(obj/item/weapon/W as obj, mob/user as mob) - if (istype(W, /obj/item/weapon/wrench)) - user << "It's a holotable! There are no bolts!" - return - - if(isrobot(user)) - return - - ..() - -/obj/structure/table/woodentable/holotable - name = "table" - desc = "A square piece of wood standing on four wooden legs. It can not move." - icon = 'icons/obj/structures.dmi' - icon_state = "wood_table" - /obj/structure/holostool name = "stool" desc = "Apply butt." @@ -371,22 +344,6 @@ for(var/mob/M in currentarea) M << "FIGHT!" -//Holorack - -/obj/structure/table/rack/holorack - name = "rack" - desc = "Different from the Middle Ages version." - icon = 'icons/obj/objects.dmi' - icon_state = "rack" - -/obj/structure/table/rack/holorack/attack_hand(mob/user as mob) - return - -/obj/structure/table/rack/holorack/attackby(obj/item/weapon/W as obj, mob/user as mob) - if (istype(W, /obj/item/weapon/wrench)) - user << "It's a holorack! You can't unwrench it!" - return - //Holocarp /mob/living/simple_animal/hostile/carp/holodeck diff --git a/code/modules/materials/materials.dm b/code/modules/materials/materials.dm index 04e8d485ba..55d51c772f 100644 --- a/code/modules/materials/materials.dm +++ b/code/modules/materials/materials.dm @@ -149,6 +149,14 @@ var/list/name_to_material stack_type = /obj/item/stack/sheet/mineral/iron icon_colour = "#5C5454" +/material/wood + name = "wood" + stack_type = /obj/item/stack/sheet/wood + icon_colour = "#824B28" + integrity = 25 + icon_base = "solid" + explosion_resistance = 2 + /material/cult name = "cult" display_name = "disturbing stone" @@ -167,4 +175,4 @@ var/list/name_to_material display_name = "human remains" /material/cult/reinf/place_dismantled_product(var/turf/target) - new /obj/effect/decal/remains/human(target) + new /obj/effect/decal/remains/human(target) \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/drone/drone_items.dm b/code/modules/mob/living/silicon/robot/drone/drone_items.dm index 5634cda9b6..7452514f17 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone_items.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone_items.dm @@ -17,8 +17,6 @@ /obj/item/weapon/module/power_control, /obj/item/weapon/stock_parts, /obj/item/frame, - /obj/item/weapon/table_parts, - /obj/item/weapon/table_parts/rack, /obj/item/weapon/camera_assembly, /obj/item/weapon/tank, /obj/item/weapon/circuitboard, diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm index cc58a7ce1c..c04857e972 100644 --- a/code/modules/mob/living/simple_animal/hostile/hostile.dm +++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm @@ -238,7 +238,7 @@ D.Open() else if(istype(A,/obj/structure/cult/pylon)) A.attack_generic(src, rand(melee_damage_lower, melee_damage_upper)) - else if(istype(A, /obj/structure/window) || istype(A, /obj/structure/closet) || istype(A, /obj/structure/table) || istype(A, /obj/structure/grille) || istype(A, /obj/structure/table/rack)) + else if(istype(A, /obj/structure/window) || istype(A, /obj/structure/closet) || istype(A, /obj/structure/table) || istype(A, /obj/structure/grille)) A.attack_generic(src, rand(melee_damage_lower, melee_damage_upper)) Move(T) FindTarget() diff --git a/code/modules/tables/flipping.dm b/code/modules/tables/flipping.dm new file mode 100644 index 0000000000..1714d390b4 --- /dev/null +++ b/code/modules/tables/flipping.dm @@ -0,0 +1,116 @@ + +/obj/structure/table/proc/straight_table_check(var/direction) + var/obj/structure/table/T + for(var/angle in list(-90,90)) + T = locate() in get_step(src.loc,turn(direction,angle)) + if(T && T.flipped == 0 && T.material == material) + return 0 + T = locate() in get_step(src.loc,direction) + if (!T || T.flipped == 1 || T.material != material) + return 1 + if(T.health > 100) + return 0 + return T.straight_table_check(direction) + +/obj/structure/table/verb/do_flip() + set name = "Flip table" + set desc = "Flips a non-reinforced table" + set category = "Object" + set src in oview(1) + + if (!can_touch(usr) || ismouse(usr)) + return + + if(flipped < 0 || !flip(get_cardinal_dir(usr,src))) + usr << "It won't budge." + return + + usr.visible_message("[usr] flips \the [src]!") + + if(climbable) + structure_shaken() + + return + +/obj/structure/table/proc/unflipping_check(var/direction) + + for(var/mob/M in oview(src,0)) + return 0 + + var/obj/occupied = turf_is_crowded() + if(occupied) + usr << "There's \a [occupied] in the way." + return 0 + + var/list/L = list() + if(direction) + L.Add(direction) + else + L.Add(turn(src.dir,-90)) + L.Add(turn(src.dir,90)) + for(var/new_dir in L) + var/obj/structure/table/T = locate() in get_step(src.loc,new_dir) + if(T && T.material == material) + if(T.flipped == 1 && T.dir == src.dir && !T.unflipping_check(new_dir)) + return 0 + return 1 + +/obj/structure/table/proc/do_put() + set name = "Put table back" + set desc = "Puts flipped table back" + set category = "Object" + set src in oview(1) + + if (!can_touch(usr)) + return + + if (!unflipping_check()) + usr << "It won't budge." + return + unflip() + +/obj/structure/table/proc/flip(var/direction) + if( !straight_table_check(turn(direction,90)) || !straight_table_check(turn(direction,-90)) ) + return 0 + + verbs -=/obj/structure/table/verb/do_flip + verbs +=/obj/structure/table/proc/do_put + + var/list/targets = list(get_step(src,dir),get_step(src,turn(dir, 45)),get_step(src,turn(dir, -45))) + for (var/atom/movable/A in get_turf(src)) + if (!A.anchored) + spawn(0) + A.throw_at(pick(targets),1,1) + + set_dir(direction) + if(dir != NORTH) + layer = 5 + climbable = 0 //flipping tables allows them to be used as makeshift barriers + flipped = 1 + flags |= ON_BORDER + for(var/D in list(turn(direction, 90), turn(direction, -90))) + var/obj/structure/table/T = locate() in get_step(src,D) + if(T && T.flipped == 0 && T.material == material && material) + T.flip(direction) + update_connections(1) + update_icon() + + return 1 + +/obj/structure/table/proc/unflip() + verbs -=/obj/structure/table/proc/do_put + verbs +=/obj/structure/table/verb/do_flip + + layer = initial(layer) + flipped = 0 + climbable = initial(climbable) + flags &= ~ON_BORDER + for(var/D in list(turn(dir, 90), turn(dir, -90))) + var/obj/structure/table/T = locate() in get_step(src.loc,D) + if(T && T.flipped == 1 && T.dir == src.dir && T.material == material && material) + T.unflip() + + update_connections(1) + update_icon() + + return 1 \ No newline at end of file diff --git a/code/modules/tables/interactions.dm b/code/modules/tables/interactions.dm new file mode 100644 index 0000000000..4ada40596e --- /dev/null +++ b/code/modules/tables/interactions.dm @@ -0,0 +1,122 @@ + +/obj/structure/table/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) + if(air_group || (height==0)) return 1 + if(istype(mover,/obj/item/projectile)) + return (check_cover(mover,target)) + if(istype(mover) && mover.checkpass(PASSTABLE)) + return 1 + if(locate(/obj/structure/table) in get_turf(mover)) + return 1 + if (flipped == 1) + if (get_dir(loc, target) == dir) + return !density + else + return 1 + return 0 + +//checks if projectile 'P' from turf 'from' can hit whatever is behind the table. Returns 1 if it can, 0 if bullet stops. +/obj/structure/table/proc/check_cover(obj/item/projectile/P, turf/from) + var/turf/cover + if(flipped==1) + cover = get_turf(src) + else if(flipped==0) + cover = get_step(loc, get_dir(from, loc)) + if(!cover) + return 1 + if (get_dist(P.starting, loc) <= 1) //Tables won't help you if people are THIS close + return 1 + if (get_turf(P.original) == cover) + var/chance = 20 + if (ismob(P.original)) + var/mob/M = P.original + if (M.lying) + chance += 20 //Lying down lets you catch less bullets + if(flipped==1) + if(get_dir(loc, from) == dir) //Flipped tables catch mroe bullets + chance += 20 + else + return 1 //But only from one side + if(prob(chance)) + health -= P.damage/2 + if (health > 0) + visible_message("[P] hits \the [src]!") + return 0 + else + visible_message("[src] breaks down!") + break_to_parts() + return 1 + return 1 + +/obj/structure/table/CheckExit(atom/movable/O as mob|obj, target as turf) + if(istype(O) && O.checkpass(PASSTABLE)) + return 1 + if (flipped==1) + if (get_dir(loc, target) == dir) + return !density + else + return 1 + return 1 + + +/obj/structure/table/MouseDrop_T(obj/O as obj, mob/user as mob) + + if ((!( istype(O, /obj/item/weapon) ) || user.get_active_hand() != O)) + return ..() + if(isrobot(user)) + return + user.drop_item() + if (O.loc != src.loc) + step(O, get_dir(O, src)) + return + + +/obj/structure/table/attackby(obj/item/W as obj, mob/user as mob) + if (!W) return + + // Handle harm intent grabbing/tabling. + 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 + if (G.state < 2) + if(user.a_intent == I_HURT) + if (prob(15)) M.Weaken(5) + M.apply_damage(8,def_zone = "head") + visible_message("[G.assailant] slams [G.affecting]'s face against \the [src]!") + playsound(src.loc, 'sound/weapons/tablehit1.ogg', 50, 1) + else + user << "You need a better grip to do that!" + return + else + G.affecting.loc = src.loc + G.affecting.Weaken(5) + visible_message("[G.assailant] puts [G.affecting] on \the [src].") + qdel(W) + return + + // Handle dismantling or placing things on the table from here on. + if(isrobot(user)) + return + + if(W.loc != user) // This should stop mounted modules ending up outside the module. + return + + if(istype(W, /obj/item/weapon/melee/energy/blade)) + var/datum/effect/effect/system/spark_spread/spark_system = new /datum/effect/effect/system/spark_spread() + spark_system.set_up(5, 0, src.loc) + spark_system.start() + playsound(src.loc, 'sound/weapons/blade1.ogg', 50, 1) + playsound(src.loc, "sparks", 50, 1) + user.visible_message("\The [src] was sliced apart by [user]!") + break_to_parts() + return + + if(!material) + user << "There's nothing to put \the [W] on! Try adding plating to \the [src] first." + return + + user.drop_item(src.loc) + return + +/obj/structure/table/attack_tk() // no telehulk sorry + return diff --git a/code/modules/tables/presets.dm b/code/modules/tables/presets.dm new file mode 100644 index 0000000000..481897c48d --- /dev/null +++ b/code/modules/tables/presets.dm @@ -0,0 +1,110 @@ +var/global/material/material_holographic_steel = null +var/global/material/material_holographic_wood = null + +/obj/structure/table + + standard + icon_state = "plain_preview" + color = "#666666" + New() + material = name_to_material[DEFAULT_WALL_MATERIAL] + ..() + + reinforced + icon_state = "reinf_preview" + color = "#666666" + New() + material = name_to_material[DEFAULT_WALL_MATERIAL] + reinforced = name_to_material[DEFAULT_WALL_MATERIAL] + ..() + + woodentable + icon_state = "plain_preview" + color = "#824B28" + New() + material = name_to_material["wood"] + ..() + + gamblingtable + icon_state = "gamble_preview" + New() + material = name_to_material["wood"] + carpeted = 1 + ..() + + glass + icon_state = "plain_preview" + color = "#00E1FF" + alpha = 77 // 0.3 * 255 + New() + material = name_to_material["glass"] + ..() + + holotable + icon_state = "holo_preview" + color = "#666666" + New() + if(!material_holographic_steel) + material_holographic_steel = new /material/steel + material_holographic_steel.stack_type = null // Tables with null-stacktype materials cannot be deconstructed + material = material_holographic_steel + ..() + + woodentable/holotable + icon_state = "holo_preview" + New() + if(!material_holographic_wood) + material_holographic_wood = new /material/wood + material_holographic_wood.stack_type = null // Tables with null-stacktype materials cannot be deconstructed + material = material_holographic_wood + ..() + +/* + +/obj/structure/table/holotable + name = "table" + desc = "A square piece of metal standing on four metal legs. It can not move." + icon = 'icons/obj/structures.dmi' + icon_state = "table" + density = 1 + anchored = 1.0 + layer = 2.8 + throwpass = 1 //You can throw objects over this, despite it's density. + +/obj/structure/table/holotable/attack_hand(mob/user as mob) + return // HOLOTABLE DOES NOT GIVE A FUCK + + +/obj/structure/table/holotable/attackby(obj/item/weapon/W as obj, mob/user as mob) + if (istype(W, /obj/item/weapon/wrench)) + user << "It's a holotable! There are no bolts!" + return + + if(isrobot(user)) + return + + ..() + +/obj/structure/table/woodentable/holotable + name = "table" + desc = "A square piece of wood standing on four wooden legs. It can not move." + icon = 'icons/obj/structures.dmi' + icon_state = "wood_table" + + +/obj/structure/table/rack/holorack + name = "rack" + desc = "Different from the Middle Ages version." + icon = 'icons/obj/objects.dmi' + icon_state = "rack" + +/obj/structure/table/rack/holorack/attack_hand(mob/user as mob) + return + +/obj/structure/table/rack/holorack/attackby(obj/item/weapon/W as obj, mob/user as mob) + if (istype(W, /obj/item/weapon/wrench)) + user << "It's a holorack! You can't unwrench it!" + return + + +*/ diff --git a/code/modules/tables/rack.dm b/code/modules/tables/rack.dm new file mode 100644 index 0000000000..bd3ee6ce55 --- /dev/null +++ b/code/modules/tables/rack.dm @@ -0,0 +1,26 @@ +/obj/structure/table/rack + name = "rack" + desc = "Different from the Middle Ages version." + icon = 'icons/obj/objects.dmi' + icon_state = "rack" + can_plate = 0 + can_reinforce = 0 + flipped = -1 + +/obj/structure/table/rack/New() + ..() + verbs -= /obj/structure/table/verb/do_flip + verbs -= /obj/structure/table/proc/do_put + +/obj/structure/table/rack/update_connections() + return + +/obj/structure/table/rack/update_desc() + return + +/obj/structure/table/rack/update_icon() + return + +/obj/structure/table/rack/holorack/dismantle(obj/item/weapon/wrench/W, mob/user) + user << "You cannot dismantle \the [src]." + return diff --git a/code/modules/tables/tables.dm b/code/modules/tables/tables.dm new file mode 100644 index 0000000000..1b389323f9 --- /dev/null +++ b/code/modules/tables/tables.dm @@ -0,0 +1,337 @@ + + +/obj/structure/table + name = "table frame" + icon = 'icons/obj/tables.dmi' + icon_state = "frame" + desc = "It's a table, for putting things on. Or standing on, if you really want to." + density = 1 + anchored = 1 + climbable = 1 + var/flipped = 0 + var/maxhealth = 10 + var/health = 10 + + // For racks. + var/can_reinforce = 1 + var/can_plate = 1 + + var/material/material = null + var/material/reinforced = null + + // Gambling tables. I'd prefer reinforced with carpet/felt/cloth/whatever, but AFAIK it's either harder or impossible to get /obj/item/stack/sheet of those. + // Convert if/when you can easily get stacks of these. + var/carpeted = 0 + + var/list/connections = list("nw0", "ne0", "sw0", "se0") + +/obj/structure/table/proc/update_material() + var/old_maxhealth = maxhealth + if(!material) + maxhealth = 10 + else + maxhealth = material.integrity / 2 + + if(reinforced) + maxhealth += reinforced.integrity / 2 + + health += maxhealth - old_maxhealth + +/obj/structure/table/New() + ..() + // One table per turf. + for(var/obj/structure/table/T in loc) + if(T != src) + // There's another table here that's not us, break to metal. + // break_to_parts calls qdel(src) + break_to_parts(full_return = 1) + return + +/obj/structure/table/initialize() + ..() + // reset color/alpha, since they're set for nice map previews + color = "#ffffff" + alpha = 255 + update_connections(1) + update_icon() + update_desc() + +/obj/structure/table/Destroy() + material = null + update_connections(1) // Update tables around us to ignore us (material=null forces no connections) + for(var/obj/structure/table/T in oview(src, 1)) + T.update_icon() + ..() + +/obj/structure/table/attackby(obj/item/weapon/W, mob/user) + + if(reinforced && istype(W, /obj/item/weapon/screwdriver)) + remove_reinforced(W, user) + if(!reinforced) + update_desc() + update_icon() + return 1 + + if(!reinforced && material && istype(W, /obj/item/weapon/wrench)) + remove_material(W, user) + if(!material) + update_connections(1) + update_icon() + return 1 + + if(!reinforced && !material && istype(W, /obj/item/weapon/wrench)) + dismantle(W, user) + return 1 + + if(!material && can_plate && istype(W, /obj/item/stack/sheet)) + material = common_material_add(W, user, "plat") + if(material) + update_connections(1) + update_icon() + return 1 + + return ..() + +/obj/structure/table/MouseDrop_T(obj/item/stack/sheet/what) + if(can_reinforce && isliving(usr) && (!usr.stat) && istype(what) && usr.get_active_hand() == what && Adjacent(usr)) + reinforce_table(what, usr) + else + return ..() + +/obj/structure/table/proc/reinforce_table(obj/item/stack/sheet/S, mob/user) + if(reinforced) + user << "\The [src] is already reinforced!" + return + + if(!can_reinforce) + user << "\The [src] cannot be reinforced!" + + reinforced = common_material_add(S, user, "reinforc") + if(reinforced) + update_desc() + update_icon() + +/obj/structure/table/proc/update_desc() + if(material) + name = "[material.display_name] table" + else + name = "table frame" + + if(reinforced) + name = "reinforced [name]" + desc = "[initial(desc)] This one seems to be reinforced with [reinforced.display_name]." + else + desc = initial(desc) + +// Returns the material to set the table to. +/obj/structure/table/proc/common_material_add(obj/item/stack/sheet/S, mob/user, verb) // Verb is actually verb without 'e' or 'ing', which is added. Works for 'plate'/'plating' and 'reinforce'/'reinforcing'. + var/material/M = name_to_material[S.sheettype] + if(!istype(M)) + user << "You cannot [verb]e \the [src] with \the [S]." + return null + user << "You begin [verb]ing \the [src] with [M.display_name]." + if(!do_after(user, 20) || !S.use(1)) + return null + user.visible_message("\The [user] [verb]es \the [src] with [M.display_name].", "You finish [verb]ing \the [src].") + return M + +// Returns the material to set the table to. +/obj/structure/table/proc/common_material_remove(mob/user, material/M, delay, what, type_holding) + if(!M.stack_type) + user << "You are unable to remove the [what] from this table!" + return M + + user.visible_message("\The [user] begins removing the [type_holding] holding \the [src]'s [M.display_name] [what] in place.", + "You begin removing the [type_holding] holding \the [src]'s [M.display_name] [what] in place.") + if(!do_after(user, 40)) + return M + user.visible_message("\The [user] removes the [M.display_name] [what] from \the [src].", + "You remove the [M.display_name] [what] from \the [src].") + new M.stack_type(src.loc) + return null + +/obj/structure/table/proc/remove_reinforced(obj/item/weapon/screwdriver/S, mob/user) + reinforced = common_material_remove(user, reinforced, 40, "reinforcements", "screws") + +/obj/structure/table/proc/remove_material(obj/item/weapon/wrench/W, mob/user) + material = common_material_remove(user, material, 20, "plating", "bolts") + +/obj/structure/table/proc/dismantle(obj/item/weapon/wrench/W, mob/user) + user.visible_message("\The [user] begins dismantling \the [src].", + "You begin dismantling \the [src].") + if(!do_after(user, 20)) + return + user.visible_message("\The [user] dismantles \the [src].", + "You dismantle \the [src].") + new /obj/item/stack/sheet/metal(src.loc) + +/obj/structure/table/proc/break_to_parts(full_return = 0) + if(reinforced && reinforced.stack_type && (full_return || prob(25))) + new reinforced.stack_type(src.loc) + if(material && material.stack_type && (full_return || prob(50))) + new material.stack_type(src.loc) + if(full_return || prob(50)) + new /obj/item/stack/sheet/metal(src.loc) + qdel(src) + return + +/obj/structure/table/update_icon() + if(flipped != 1) + icon_state = "blank" + overlays.Cut() + + // Base frame shape. Mostly done for glass/diamond tables, where this is visible. + for(var/n in connections) + overlays += n + + // Standard table image + if(material) + for(var/n in connections) + var/image/I = image(icon, "[material.icon_base]_[n]") + I.color = material.icon_colour + I.alpha = 255 * material.opacity + overlays += I + + // Reinforcements + if(reinforced) + for(var/n in connections) + var/image/I = image(icon, "[reinforced.icon_reinf]_[n]") + I.color = reinforced.icon_colour + I.alpha = 255 * reinforced.opacity + overlays += I + + if(carpeted) + for(var/n in connections) + overlays += "carpet_[n]" + else + overlays.Cut() + var/type = 0 + var/tabledirs = 0 + for(var/direction in list(turn(dir,90), turn(dir,-90)) ) + var/obj/structure/table/T = locate(/obj/structure/table ,get_step(src,direction)) + if (T && T.flipped == 1 && T.dir == src.dir && T.material == material) + type++ + tabledirs |= direction + + type = "[type]" + if (type=="1") + if (tabledirs & turn(dir,90)) + type += "-" + if (tabledirs & turn(dir,-90)) + type += "+" + + icon_state = "flip[type]" + if(material) + var/image/I = image(icon, "[material.icon_base]_flip[type]") + I.color = material.icon_colour + I.alpha = 255 * material.opacity + overlays += I + name = "[material.display_name] table" + else + name = "table frame" + + if(reinforced) + var/image/I = image(icon, "[reinforced.icon_reinf]_flip[type]") + I.color = reinforced.icon_colour + I.alpha = 255 * reinforced.opacity + overlays += I + + if(carpeted) + for(var/n in connections) + overlays += "carpet_flip[type]" + +// set propagate if you're updating a table that should update tables around it too, for example if it's a new table or something important has changed (like material). +/obj/structure/table/proc/update_connections(propagate=0) + if(!material) + connections = list("nw0", "ne0", "sw0", "se0") + + if(propagate) + for(var/obj/structure/table/T in oview(src, 1)) + T.update_connections() + return + + var/list/blocked_dirs = list() + for(var/obj/structure/window/W in get_turf(src)) + if(W.is_fulltile()) + connections = list("nw0", "ne0", "sw0", "se0") + return + blocked_dirs |= W.dir + + for(var/D in list(NORTH, SOUTH, EAST, WEST) - blocked_dirs) + var/turf/T = get_step(src, D) + for(var/obj/structure/window/W in T) + if(W.is_fulltile() || W.dir == reverse_dir[D]) + blocked_dirs |= D + break + else + if(W.dir != D) // it's off to the side + blocked_dirs |= W.dir|D // blocks the diagonal + + for(var/D in list(NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST) - blocked_dirs) + var/turf/T = get_step(src, D) + + for(var/obj/structure/window/W in T) + if(W.is_fulltile() || W.dir & reverse_dir[D]) + blocked_dirs |= D + break + + // Blocked cardinals block the adjacent diagonals too. Prevents weirdness with tables. + for(var/x in list(NORTH, SOUTH)) + for(var/y in list(EAST, WEST)) + if((x in blocked_dirs) || (y in blocked_dirs)) + blocked_dirs |= x|y + + var/list/connection_dirs = list() + + for(var/obj/structure/table/T in oview(src, 1)) + var/T_dir = get_dir(src, T) + if(T_dir in blocked_dirs) continue + if(material == T.material && flipped == T.flipped) + connection_dirs |= T_dir + if(propagate) + spawn(0) + T.update_connections() + T.update_icon() + + connections = dirs_to_corner_states(connection_dirs) + +#define CORNER_NONE 0 +#define CORNER_EASTWEST 1 +#define CORNER_DIAGONAL 2 +#define CORNER_NORTHSOUTH 4 + +/proc/dirs_to_corner_states(list/dirs) + if(!istype(dirs)) return + + var/NE = CORNER_NONE + var/NW = CORNER_NONE + var/SE = CORNER_NONE + var/SW = CORNER_NONE + + if(NORTH in dirs) + NE |= CORNER_NORTHSOUTH + NW |= CORNER_NORTHSOUTH + if(SOUTH in dirs) + SW |= CORNER_NORTHSOUTH + SE |= CORNER_NORTHSOUTH + if(EAST in dirs) + SE |= CORNER_EASTWEST + NE |= CORNER_EASTWEST + if(WEST in dirs) + NW |= CORNER_EASTWEST + SW |= CORNER_EASTWEST + if(NORTHWEST in dirs) + NW |= CORNER_DIAGONAL + if(NORTHEAST in dirs) + NE |= CORNER_DIAGONAL + if(SOUTHEAST in dirs) + SE |= CORNER_DIAGONAL + if(SOUTHWEST in dirs) + SW |= CORNER_DIAGONAL + + return list("ne[NE]", "se[SE]", "sw[SW]", "nw[NW]") + +#undef CORNER_NONE +#undef CORNER_EASTWEST +#undef CORNER_DIAGONAL +#undef CORNER_NORTHSOUTH \ No newline at end of file diff --git a/code/modules/tables/update_triggers.dm b/code/modules/tables/update_triggers.dm new file mode 100644 index 0000000000..a90e3eeb8a --- /dev/null +++ b/code/modules/tables/update_triggers.dm @@ -0,0 +1,22 @@ +/obj/structure/window/New() + ..() + for(var/obj/structure/table/T in view(src, 1)) + T.update_connections() + T.update_icon() + +/obj/structure/window/Destroy() + var/oldloc = loc + loc=null + for(var/obj/structure/table/T in view(oldloc, 1)) + T.update_connections() + T.update_icon() + loc=oldloc + ..() + +/obj/structure/window/Move() + var/oldloc = loc + . = ..() + if(loc != oldloc) + for(var/obj/structure/table/T in view(oldloc, 1) | view(loc, 1)) + T.update_connections() + T.update_icon() \ No newline at end of file diff --git a/icons/obj/tables.dmi b/icons/obj/tables.dmi new file mode 100644 index 0000000000000000000000000000000000000000..429969fc86234b2db96ea21c7d10196b9d4eead3 GIT binary patch literal 22339 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 literal 0 HcmV?d00001