mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-30 03:22:41 +00:00
* Fix compilation on older BYOND versions (#72633) ## About The Pull Request Fix compilation on certain BYOND versions, among them 514.1582. This line currently causes an error as floor_designs is already defined earlier Co-authored-by: oranges <email@ oranges.net.nz> * Fix compilation on older BYOND versions Co-authored-by: Cyprex <35031555+Cyprex@users.noreply.github.com> Co-authored-by: oranges <email@ oranges.net.nz>
366 lines
12 KiB
Plaintext
366 lines
12 KiB
Plaintext
/// time taken to create tile
|
|
#define CONSTRUCTION_TIME 0.4 SECONDS
|
|
/// time taken to destroy a tile
|
|
#define DECONSTRUCTION_TIME 0.2 SECONDS
|
|
|
|
/**
|
|
* An tool used to create, destroy, and copy & clear decals of floor tiles
|
|
* Great for janitor but can be made only in engineering
|
|
* Supports silo link upgrade and refill with glass, plasteel & iron
|
|
*/
|
|
/obj/item/construction/rtd
|
|
name = "rapid-tiling-device (RTD)"
|
|
desc = "Used for fast placement & destruction of floor tiles."
|
|
icon = 'icons/obj/tools.dmi'
|
|
icon_state = "rtd"
|
|
worn_icon_state = "RCD"
|
|
lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
|
|
righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
|
|
custom_premium_price = PAYCHECK_COMMAND * 3
|
|
max_matter = 350
|
|
slot_flags = ITEM_SLOT_BELT
|
|
item_flags = NO_MAT_REDEMPTION | NOBLUDGEON
|
|
has_ammobar = TRUE
|
|
banned_upgrades = RCD_UPGRADE_FRAMES | RCD_UPGRADE_SIMPLE_CIRCUITS | RCD_UPGRADE_FURNISHING
|
|
|
|
/// main category for tile design
|
|
var/root_category = "Conventional"
|
|
/// sub category for tile design
|
|
var/design_category = "Standard"
|
|
/// design selected by player
|
|
var/datum/tile_info/selected_design
|
|
/// temp var to store an single design from GLOB.floor_design while iterating through this list
|
|
var/datum/tile_info/tile_design
|
|
/// overlays on a tile
|
|
var/list/design_overlays = list()
|
|
|
|
/// stores the name, type, icon & cost for each tile type
|
|
/datum/tile_info
|
|
/// name of this tile design for ui
|
|
var/name
|
|
/// path to create this tile type
|
|
var/obj/item/stack/tile/tile_type
|
|
/// icon for this tile to display for ui
|
|
var/icon_state
|
|
/// rcd units to consume for this tile creation
|
|
var/cost
|
|
|
|
///directions this tile can be placed on the turf
|
|
var/list/tile_directions
|
|
/// user friendly names of the tile_directions to be sent to ui
|
|
var/list/ui_directional_data
|
|
/// current direction this tile should be rotated in before being placed on the plating
|
|
var/selected_direction
|
|
|
|
/// decompress a single tile design list element from GLOB.floor_designs into its individual variables
|
|
/datum/tile_info/proc/set_info(list/design)
|
|
name = design["name"]
|
|
tile_type = design["type"]
|
|
icon_state = initial(tile_type.icon_state)
|
|
cost = design["tile_cost"]
|
|
|
|
tile_directions = design["tile_rotate_dirs"]
|
|
if(!tile_directions)
|
|
selected_direction = null
|
|
ui_directional_data = null
|
|
return
|
|
|
|
ui_directional_data = list()
|
|
for(var/tile_direction in tile_directions)
|
|
ui_directional_data += dir2text(tile_direction)
|
|
selected_direction = tile_directions[1]
|
|
|
|
/// fill all information to be sent to the UI
|
|
/datum/tile_info/proc/fill_ui_data(list/data)
|
|
data["selected_recipe"] = name
|
|
data["selected_icon"] = get_icon_state()
|
|
|
|
if(!tile_directions)
|
|
data["selected_direction"] = null
|
|
return
|
|
|
|
data["tile_dirs"] = ui_directional_data
|
|
data["selected_direction"] = dir2text(selected_direction)
|
|
|
|
/// change the direction the tile is laid on the turf
|
|
/datum/tile_info/proc/set_direction(direction)
|
|
if(tile_directions == null || !(direction in tile_directions))
|
|
return
|
|
selected_direction = direction
|
|
|
|
/**
|
|
* retrive the icon for this tile design based on its direction
|
|
* for complex directions like NORTHSOUTH etc we create an seperated blended icon in the asset file for example floor-northsouth
|
|
* so we check which icons we want to retrive based on its direction
|
|
* for basic directions its rotated with CSS so there is no need for icon
|
|
*/
|
|
/datum/tile_info/proc/get_icon_state()
|
|
var/prefix = ""
|
|
if(selected_direction)
|
|
prefix = (selected_direction in GLOB.tile_dont_rotate) ? "" : "-[dir2text(selected_direction)]"
|
|
return icon_state + prefix
|
|
|
|
///convinience proc to quickly convert the tile design into an physical tile to lay on the plating
|
|
/datum/tile_info/proc/new_tile(loc)
|
|
var/obj/item/stack/tile/final_tile = new tile_type(loc, 1)
|
|
final_tile.turf_dir = selected_direction
|
|
return final_tile
|
|
|
|
/**
|
|
* Stores the decal & overlays on the floor to preserve texture of the design
|
|
* in short its just an wrapper for mutable appearance where we retrive the nessassary information
|
|
* to recreate an mutable appearance
|
|
*/
|
|
/datum/overlay_info
|
|
/// icon var of the mutable appearance
|
|
var/icon/icon
|
|
/// icon_state var of the mutable appearance
|
|
var/icon_state
|
|
/// direction var of the mutable appearance
|
|
var/direction
|
|
/// alpha var of the mutable appearance
|
|
var/alpha
|
|
/// color var of the mutable appearance
|
|
var/color
|
|
|
|
//decompressing nessasary information required to re-create an mutable appearance
|
|
/datum/overlay_info/New(mutable_appearance/appearance)
|
|
icon = appearance.icon
|
|
icon_state = appearance.icon_state
|
|
alpha = appearance.alpha
|
|
direction = appearance.dir
|
|
color = appearance.color
|
|
|
|
/// re create the appearance
|
|
/datum/overlay_info/proc/add_decal(turf/the_turf)
|
|
the_turf.AddElement(/datum/element/decal, icon, icon_state, direction, null, null, alpha, color, null, FALSE, null)
|
|
|
|
/obj/item/construction/rtd/Initialize(mapload)
|
|
. = ..()
|
|
selected_design = new
|
|
tile_design = new
|
|
|
|
selected_design.set_info(GLOB.floor_designs[root_category][design_category][1])
|
|
update_appearance()
|
|
|
|
/obj/item/construction/rtd/Destroy()
|
|
QDEL_NULL(selected_design)
|
|
QDEL_NULL(tile_design)
|
|
QDEL_LIST(design_overlays)
|
|
. = ..()
|
|
|
|
/obj/item/construction/rtd/ui_interact(mob/user, datum/tgui/ui)
|
|
ui = SStgui.try_update_ui(user, src, ui)
|
|
if(!ui)
|
|
ui = new(user, src, "RapidTilingDevice", name)
|
|
ui.open()
|
|
|
|
|
|
/obj/item/construction/rtd/ui_assets(mob/user)
|
|
return list(
|
|
get_asset_datum(/datum/asset/spritesheet/rtd),
|
|
)
|
|
|
|
/obj/item/construction/rtd/attack_self(mob/user)
|
|
. = ..()
|
|
ui_interact(user)
|
|
|
|
/obj/item/construction/rtd/ui_data(mob/user)
|
|
var/list/data = ..()
|
|
var/floor_designs = GLOB.floor_designs
|
|
|
|
data["selected_root"] = root_category
|
|
data["root_categories"] = list()
|
|
for(var/category in floor_designs)
|
|
data["root_categories"] += category
|
|
data["selected_category"] = design_category
|
|
|
|
selected_design.fill_ui_data(data)
|
|
|
|
data["categories"] = list()
|
|
for(var/sub_category as anything in floor_designs[root_category])
|
|
var/list/target_category = floor_designs[root_category][sub_category]
|
|
|
|
var/list/designs = list() //initialize all designs under this category
|
|
for(var/list/design as anything in target_category)
|
|
tile_design.set_info(design)
|
|
designs += list(list("name" = tile_design.name, "icon" = tile_design.get_icon_state()))
|
|
|
|
data["categories"] += list(list("category_name" = sub_category, "recipes" = designs))
|
|
|
|
return data
|
|
|
|
/obj/item/construction/rtd/ui_act(action, params)
|
|
. = ..()
|
|
if(.)
|
|
return
|
|
|
|
var/floor_designs = GLOB.floor_designs
|
|
switch(action)
|
|
if("root_category")
|
|
var/new_root = params["root_category"]
|
|
if(floor_designs[new_root] != null) //is a valid category
|
|
root_category = new_root
|
|
|
|
if("set_dir")
|
|
var/direction = text2dir(params["dir"])
|
|
if(!direction)
|
|
return TRUE
|
|
selected_design.set_direction(direction)
|
|
|
|
if("recipe")
|
|
var/list/main_root = floor_designs[root_category]
|
|
if(main_root == null)
|
|
return TRUE
|
|
var/list/sub_category = main_root[params["category_name"]]
|
|
if(sub_category == null)
|
|
return TRUE
|
|
var/list/target_design = sub_category[text2num(params["id"])]
|
|
if(target_design == null)
|
|
return
|
|
|
|
QDEL_LIST(design_overlays)
|
|
design_category = params["category_name"]
|
|
selected_design.set_info(target_design)
|
|
|
|
return TRUE
|
|
|
|
/// RTD can lay floor tiles only on these 2 types of platings. this procs checks for that
|
|
/obj/item/construction/rtd/proc/is_valid_plating(turf/open/floor)
|
|
return floor.type == /turf/open/floor/plating || floor.type == /turf/open/floor/plating/reinforced
|
|
|
|
/obj/item/construction/rtd/afterattack(turf/open/floor/floor, mob/user)
|
|
. = ..()
|
|
if(!istype(floor) || !range_check(floor,user))
|
|
return TRUE
|
|
|
|
var/floor_designs = GLOB.floor_designs
|
|
if(!is_valid_plating(floor)) //we infer what floor type it is if its not the usual plating
|
|
user.Beam(floor, icon_state = "light_beam", time = 5)
|
|
for(var/main_root in floor_designs)
|
|
for(var/sub_category in floor_designs[main_root])
|
|
for(var/list/design_info in floor_designs[main_root][sub_category])
|
|
var/obj/item/stack/tile/tile_type = design_info["type"]
|
|
if(initial(tile_type.turf_type) != floor.type)
|
|
continue
|
|
|
|
//infer available overlays on the floor to recreate them to the best extent
|
|
QDEL_LIST(design_overlays)
|
|
var/floor_overlays = floor.managed_overlays
|
|
if(isnull(floor_overlays))
|
|
floor_overlays = list()
|
|
else if(!islist(floor_overlays))
|
|
floor_overlays = list(floor.managed_overlays)
|
|
for(var/mutable_appearance/appearance as anything in floor_overlays)
|
|
design_overlays += new /datum/overlay_info(appearance)
|
|
|
|
//store all information about this tile
|
|
root_category = main_root
|
|
design_category = sub_category
|
|
selected_design.set_info(design_info)
|
|
selected_design.set_direction(floor.dir)
|
|
balloon_alert(user, "tile changed to [selected_design.name]")
|
|
|
|
return TRUE
|
|
|
|
//can't infer floor type!
|
|
balloon_alert(user, "design not supported!")
|
|
return TRUE
|
|
|
|
if(!checkResource(selected_design.cost, user))
|
|
return TRUE
|
|
|
|
//All special effect stuff
|
|
user.Beam(floor, icon_state = "light_beam", time = CONSTRUCTION_TIME)
|
|
var/obj/effect/constructing_effect/rcd_effect = new(floor, CONSTRUCTION_TIME, RCD_FLOORWALL)
|
|
if(!do_after(user, CONSTRUCTION_TIME, target = floor))
|
|
rcd_effect.end_animation()
|
|
return TRUE
|
|
|
|
//consume resource only if tile was placed successfully
|
|
var/obj/item/stack/tile/final_tile = selected_design.new_tile(user.drop_location())
|
|
if(QDELETED(final_tile)) //if you were standing on a stack of tiles this newly spawned tile could get merged with it cause its spawned on your location
|
|
rcd_effect.end_animation()
|
|
balloon_alert(user, "tile got merged with the stack beneath you!")
|
|
return TRUE
|
|
|
|
var/turf/open/new_turf = final_tile.place_tile(floor, user)
|
|
if(new_turf)
|
|
//apply infered overlays
|
|
for(var/datum/overlay_info/info in design_overlays)
|
|
info.add_decal(new_turf)
|
|
//use material
|
|
useResource(selected_design.cost, user)
|
|
rcd_effect.end_animation()
|
|
|
|
return TRUE
|
|
|
|
/obj/item/construction/rtd/afterattack_secondary(turf/open/floor/floor, mob/user, proximity_flag, click_parameters)
|
|
..()
|
|
if(!istype(floor) || !range_check(floor,user))
|
|
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
|
|
|
if(is_valid_plating(floor)) //cant deconstruct normal plating thats the RCD's job
|
|
balloon_alert(user, "nothing to deconstruct!")
|
|
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
|
|
|
var/floor_designs = GLOB.floor_designs
|
|
|
|
//we only deconstruct floors which are supported by the RTD
|
|
var/can_deconstruct = FALSE
|
|
var/cost
|
|
for(var/main_root in floor_designs)
|
|
if(can_deconstruct)
|
|
break
|
|
for(var/sub_category in floor_designs[main_root])
|
|
if(can_deconstruct)
|
|
break
|
|
for(var/list/design_info in floor_designs[main_root][sub_category])
|
|
var/obj/item/stack/tile/tile_type = design_info["type"]
|
|
if(initial(tile_type.turf_type) == floor.type)
|
|
cost = tile_design.cost
|
|
can_deconstruct = TRUE
|
|
break
|
|
if(!can_deconstruct || !checkResource(cost * 0.7, user)) //no ballon alert for checkResource as it already spans an alert to chat
|
|
if(!can_deconstruct)
|
|
balloon_alert(user, "can't deconstruct this type!")
|
|
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
|
|
|
//find & collect all decals
|
|
var/list/all_decals = list()
|
|
for(var/obj/effect/decal in floor.contents)
|
|
all_decals += decal
|
|
//delete all decals
|
|
for(var/obj/effect/decal in all_decals)
|
|
floor.contents -= decal
|
|
qdel(decal)
|
|
|
|
//All special effect stuff
|
|
user.Beam(floor, icon_state = "light_beam", time = DECONSTRUCTION_TIME)
|
|
var/obj/effect/constructing_effect/rcd_effect = new(floor, DECONSTRUCTION_TIME, RCD_FLOORWALL)
|
|
if(!do_after(user, DECONSTRUCTION_TIME, target = floor))
|
|
rcd_effect.end_animation()
|
|
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
|
|
|
var/turf/new_turf = null
|
|
if(floor.baseturf_at_depth(1) == /turf/baseturf_bottom) //for turfs whose base is open space we put regular plating in its place else everyone dies
|
|
new_turf = floor.ChangeTurf(/turf/open/floor/plating, flags = CHANGETURF_INHERIT_AIR)
|
|
else // for every other turf we scarp away exposing base turf underneath
|
|
new_turf = floor.ScrapeAway(flags = CHANGETURF_INHERIT_AIR)
|
|
if(new_turf)
|
|
useResource(cost * 0.7, user)
|
|
rcd_effect.end_animation()
|
|
|
|
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
|
|
|
/obj/item/construction/rtd/loaded
|
|
matter = 350
|
|
|
|
/obj/item/construction/rtd/admin
|
|
name = "admin RTD"
|
|
max_matter = INFINITY
|
|
matter = INFINITY
|
|
|
|
#undef CONSTRUCTION_TIME
|
|
#undef DECONSTRUCTION_TIME
|