mirror of
https://github.com/Citadel-Station-13/Citadel-Station-13-RP.git
synced 2026-08-28 00:57:12 +01:00
small poster rewrite (#6884)
adds persistence support kinda adds /preset's of everything
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
/obj/structure/poster
|
||||
prototype_id = "Poster"
|
||||
name = "poster"
|
||||
desc = "A large piece of space-resistant printed paper."
|
||||
icon = 'icons/modules/artwork/posters/poster.dmi'
|
||||
anchored = TRUE
|
||||
|
||||
/// random poster design tag or tags no [poster_design_id] is filled out
|
||||
///
|
||||
/// * null = pick all possible
|
||||
/// * accepts null, POSTER_TAG_* enum, or list of POSTER_TAG_* enum's
|
||||
var/poster_random_tag
|
||||
/// our poster design id or type.
|
||||
var/poster_design_id
|
||||
/// were we macro-defined? lets us skip a few things.
|
||||
var/macro_defined = FALSE
|
||||
|
||||
var/ruined = 0
|
||||
var/roll_type
|
||||
|
||||
/obj/structure/poster/Initialize(mapload, placement_dir, poster_design_id)
|
||||
. = ..()
|
||||
switch (placement_dir)
|
||||
if (NORTH)
|
||||
pixel_x = 0
|
||||
pixel_y = 32
|
||||
if (SOUTH)
|
||||
pixel_x = 0
|
||||
pixel_y = -32
|
||||
if (EAST)
|
||||
pixel_x = 32
|
||||
pixel_y = 0
|
||||
if (WEST)
|
||||
pixel_x = -32
|
||||
pixel_y = 0
|
||||
|
||||
if(macro_defined)
|
||||
return
|
||||
poster_design_id = poster_design_id || src.poster_design_id
|
||||
if(!poster_design_id)
|
||||
poster_design_id = pick(RSposter_designs.fetch_by_tag_mutable(poster_random_tag))
|
||||
if(poster_design_id != src.poster_design_id)
|
||||
src.poster_design_id = poster_design_id
|
||||
set_poster_design(RSposter_designs.fetch(poster_design_id))
|
||||
|
||||
/obj/structure/poster/proc/set_poster_design(datum/prototype/poster_design/design)
|
||||
src.name = "rolled-up-poster - [design.name]"
|
||||
src.desc = "[initial(src.desc)] [design.desc]"
|
||||
src.poster_design_id = design.id
|
||||
src.icon = design.icon
|
||||
src.icon_state = design.icon_state
|
||||
|
||||
/obj/structure/poster/attackby(obj/item/W as obj, mob/user as mob)
|
||||
if(W.is_wirecutter())
|
||||
playsound(src.loc, W.tool_sound, 100, 1)
|
||||
if(ruined)
|
||||
to_chat(user, "<span class='notice'>You remove the remnants of the poster.</span>")
|
||||
qdel(src)
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You carefully remove the poster from the wall.</span>")
|
||||
roll_and_drop(user.loc)
|
||||
|
||||
/obj/structure/poster/attack_hand(mob/user, datum/event_args/actor/clickchain/e_args)
|
||||
if(ruined)
|
||||
return
|
||||
|
||||
if(alert("Do I want to rip the poster from the wall?","You think...","Yes","No") == "Yes")
|
||||
|
||||
if(ruined || !user.Adjacent(src))
|
||||
return
|
||||
|
||||
visible_message("<span class='warning'>[user] rips [src] in a single, decisive motion!</span>" )
|
||||
playsound(src.loc, 'sound/items/poster_ripped.ogg', 100, 1)
|
||||
ruined = TRUE
|
||||
icon = initial(icon)
|
||||
icon_state = "poster_ripped"
|
||||
name = "ripped poster"
|
||||
desc = "You can't make out anything from the poster's original print. It's ruined."
|
||||
add_fingerprint(user)
|
||||
|
||||
/obj/structure/poster/proc/roll_and_drop(turf/newloc)
|
||||
new /obj/item/poster(newloc, poster_design_id)
|
||||
qdel(src)
|
||||
|
||||
/obj/structure/poster/nanotrasen
|
||||
poster_random_tag = POSTER_TAG_NANOTRASEN
|
||||
@@ -0,0 +1,528 @@
|
||||
//* This file is explicitly licensed under the MIT license. *//
|
||||
//* Copyright (c) 2023 Citadel Station developers. *//
|
||||
|
||||
/**
|
||||
* Dynamic sculpting!
|
||||
*
|
||||
* Later to replace statues entirely.
|
||||
*
|
||||
* Sprites generously 'borrowed' from /tg/station.
|
||||
* Idea is from /tg/station, but entirely reimplemented here.
|
||||
*
|
||||
* stay awesome tg (:
|
||||
*
|
||||
* todo: add in a way to preload a template so it starts out sculpted, and an initialize() override for such
|
||||
* todo: de/serialization
|
||||
* todo: sculpting with shit tools should result in a bad image
|
||||
* todo: the full white alpha masks should be cached
|
||||
*/
|
||||
/obj/structure/sculpting_block
|
||||
name = "material block"
|
||||
desc = "A block of material. You can sculpt this with appropriate tools, like a screwdriver."
|
||||
icon = 'icons/modules/artwork/sculpting.dmi'
|
||||
icon_state = "block"
|
||||
density = TRUE
|
||||
anchored = FALSE
|
||||
|
||||
/// finished base state
|
||||
var/sculpture_base_state = "base"
|
||||
/// material ref
|
||||
var/datum/prototype/material/material = /datum/prototype/material/steel
|
||||
|
||||
icon_x_dimension = 32
|
||||
icon_y_dimension = 32
|
||||
bound_width = 32
|
||||
bound_height = 32
|
||||
|
||||
/// is this sculpture finished?
|
||||
var/finished = FALSE
|
||||
/// sculpture x alignment offset
|
||||
var/alignment = 0
|
||||
|
||||
/// currently being sculpted
|
||||
var/sculpting = FALSE
|
||||
/// current icon being sculpted
|
||||
var/icon/sculpting_buffer
|
||||
/// y start; this is set to sculpting_line at the start of an operation
|
||||
var/sculpting_line_start
|
||||
/// y end; this is set after end of sculpting right before we blend it into our icon
|
||||
var/sculpting_line_end
|
||||
/// is the model overlaid yet? for ones that get aligned to bottom, we don't overlay immediately.
|
||||
var/sculpting_overlay_active
|
||||
/// scultping user, if any
|
||||
var/mob/sculpting_user
|
||||
/// sculpting target
|
||||
var/atom/movable/sculpting_target
|
||||
|
||||
/// current icon for sculpting; every operation flushes to this, this begins at a x by y blank.
|
||||
/// we don't flush directly to our icon only because icon might get fucked with
|
||||
/// list(north, east, south, west)
|
||||
var/list/icon/sculpting_slates
|
||||
/// current combined slates
|
||||
var/icon/sculpting_built
|
||||
/// sculpting block is assumed to be a certain size
|
||||
/// store the current line being sculpted
|
||||
/// this starts at the topmost y
|
||||
/// if we're done sculpting, this should be nulled for consistency
|
||||
var/sculpting_line
|
||||
/// virtual vis contents holder for buffer
|
||||
var/atom/movable/sculpting_render/sculpting_renderer
|
||||
/// slate dimension y
|
||||
var/slate_dimension_y
|
||||
/// slate dimension x
|
||||
var/slate_dimension_x
|
||||
/// amount of time it takes to sculpt one line at 1x toolspeed
|
||||
var/sculpting_hardness = 0.5 SECONDS
|
||||
/// sculpting mask for our slate
|
||||
var/icon/sculpting_mask
|
||||
/// sculpting mask for our block
|
||||
var/icon/sculpting_rolldown_mask
|
||||
|
||||
/obj/structure/sculpting_block/Initialize(mapload, material)
|
||||
// todo: materials system
|
||||
src.material = RSmaterials.fetch(material || src.material)
|
||||
// todo: if it autoinit'd, don't do this
|
||||
reset_sculpting()
|
||||
return ..()
|
||||
|
||||
/obj/structure/sculpting_block/Destroy()
|
||||
QDEL_NULL(sculpting_renderer)
|
||||
sculpting_mask = null
|
||||
sculpting_rolldown_mask = null
|
||||
sculpting_buffer = null
|
||||
sculpting_built = null
|
||||
sculpting_slates = null
|
||||
return ..()
|
||||
|
||||
/obj/structure/sculpting_block/examine(mob/user, dist)
|
||||
. = ..()
|
||||
. += SPAN_NOTICE("It is made out of <b>[isnull(material)? "nothing?!": "[material.display_name]."]</b>")
|
||||
. += SPAN_NOTICE("Use a <b>wrench</b> to un/fasten the anchoring bolts.")
|
||||
. += SPAN_NOTICE("Use a <b>welder</b> to slice it apart.")
|
||||
|
||||
/obj/structure/sculpting_block/proc/reset_sculpting()
|
||||
sculpting_line = icon_y_dimension
|
||||
finished = FALSE
|
||||
remove_filter("top_erasure")
|
||||
update_appearance()
|
||||
|
||||
/obj/structure/sculpting_block/update_icon(updates)
|
||||
if(length(underlays))
|
||||
underlays.len = 0
|
||||
cut_overlays()
|
||||
if(sculpting_built)
|
||||
var/image/render = new
|
||||
render.icon = sculpting_built
|
||||
render.appearance_flags = KEEP_APART | RESET_COLOR
|
||||
add_overlay(render)
|
||||
. = ..()
|
||||
var/image/stand = image(initial(icon), icon_state = sculpture_base_state)
|
||||
stand.appearance_flags = KEEP_APART | RESET_COLOR
|
||||
stand.pixel_x = -alignment
|
||||
underlays += stand
|
||||
|
||||
/obj/structure/sculpting_block/attackby(obj/item/I, mob/living/user, list/params, clickchain_flags, damage_multiplier)
|
||||
if(user.a_intent == INTENT_HARM)
|
||||
return ..()
|
||||
if(user.a_intent == INTENT_HELP)
|
||||
initiate_sculpting(user, tool = I)
|
||||
return CLICKCHAIN_DO_NOT_PROPAGATE
|
||||
|
||||
/obj/structure/sculpting_block/wrench_act(obj/item/I, datum/event_args/actor/clickchain/e_args, flags, hint)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
e_args.visible_feedback(
|
||||
target = src,
|
||||
range = MESSAGE_RANGE_CONSTRUCTION,
|
||||
visible = SPAN_NOTICE("[e_args.performer] starts [anchored? "unbolting [src] from the floor" : "bolting [src] to the floor"]."),
|
||||
audible = SPAN_WARNING("You hear bolts being [anchored? "unfastened" : "fastened"]."),
|
||||
otherwise_self = SPAN_NOTICE("You start [anchored? "unbolting [src] from the floor" : "bolting [src] to the floor"]."),
|
||||
)
|
||||
log_construction(e_args, src, "started [anchored? "unanchoring" : "anchoring"]")
|
||||
if(!use_wrench(I, e_args, flags, 3 SECONDS))
|
||||
return TRUE
|
||||
e_args.visible_feedback(
|
||||
target = src,
|
||||
range = MESSAGE_RANGE_CONSTRUCTION,
|
||||
visible = SPAN_NOTICE("[e_args.performer] finishes [anchored? "unbolting [src] from the floor" : "bolting [src] to the floor"]."),
|
||||
audible = SPAN_WARNING("You hear bolts [anchored? "falling out" : "clicking into place"]."),
|
||||
otherwise_self = SPAN_NOTICE("You finish [anchored? "unbolting [src] from the floor" : "bolting [src] to the floor"]."),
|
||||
)
|
||||
log_construction(e_args, src, "[anchored? "unanchored" : "anchored"]")
|
||||
set_anchored(!anchored)
|
||||
return TRUE
|
||||
|
||||
/obj/structure/sculpting_block/welder_act(obj/item/I, datum/event_args/actor/clickchain/e_args, flags, hint)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
e_args.visible_feedback(
|
||||
target = src,
|
||||
range = MESSAGE_RANGE_CONSTRUCTION,
|
||||
visible = SPAN_NOTICE("[e_args.performer] starts slicing [src] apart."),
|
||||
audible = SPAN_WARNING("You hear the sound of a welding torch being used on something metallic."),
|
||||
otherwise_self = SPAN_NOTICE("You start slicing [src] apart."),
|
||||
)
|
||||
log_construction(e_args, src, "started deconstructing")
|
||||
if(!use_welder(I, e_args, flags, 7 SECONDS))
|
||||
return TRUE
|
||||
e_args.visible_feedback(
|
||||
target = src,
|
||||
range = MESSAGE_RANGE_CONSTRUCTION,
|
||||
visible = SPAN_NOTICE("[e_args.performer] slices [src] apart."),
|
||||
audible = SPAN_WARNING("You hear the sound of a welding torch moving back into open air, and a few pieces of metal falling apart."),
|
||||
otherwise_self = SPAN_NOTICE("You slice [src] apart."),
|
||||
)
|
||||
log_construction(e_args, src, "deconstructed")
|
||||
set_anchored(!anchored)
|
||||
deconstruct(ATOM_DECONSTRUCT_DISASSEMBLED)
|
||||
return TRUE
|
||||
|
||||
/obj/structure/sculpting_block/drop_products(method)
|
||||
. = ..()
|
||||
material.place_sheet(drop_location(), 10)
|
||||
|
||||
/obj/structure/sculpting_block/dynamic_tool_query(obj/item/I, datum/event_args/actor/clickchain/e_args, list/hint_images = list())
|
||||
. = list()
|
||||
LAZYSET(.[TOOL_WRENCH], anchored? "unanchor" : "anchor", anchored? dyntool_image_backward(TOOL_WRENCH) : dyntool_image_forward(TOOL_WRENCH))
|
||||
LAZYSET(.[TOOL_WELDER], "deconstruct", dyntool_image_backward(TOOL_WELDER))
|
||||
return merge_double_lazy_assoc_list(., ..())
|
||||
|
||||
/**
|
||||
* returns speed multiplier, or null if not tool
|
||||
*/
|
||||
/obj/structure/sculpting_block/proc/is_sculpting_tool(obj/item/tool, mob/user)
|
||||
// todo: well fucking obviously we don't want to just have only screwdrivers usable, right gang? ~silicons
|
||||
if(tool.is_screwdriver())
|
||||
return tool.tool_speed
|
||||
return null
|
||||
|
||||
/obj/structure/sculpting_block/proc/initiate_sculpting(mob/user, silent, atom/movable/forced_target, obj/item/tool)
|
||||
if(TIMER_COOLDOWN_CHECK(src, CD_INDEX_SCULPTING_COOLDOWN))
|
||||
if(!silent)
|
||||
user?.action_feedback(SPAN_WARNING("[src] was worked on too recently.."), src)
|
||||
return FALSE
|
||||
if(finished)
|
||||
if(!silent)
|
||||
user?.action_feedback(SPAN_WARNING("[src] is finished."), src)
|
||||
return FALSE
|
||||
if(sculpting)
|
||||
if(!silent)
|
||||
user?.action_feedback(SPAN_WARNING("Someone's already working on [src]."), src)
|
||||
return FALSE
|
||||
if(isnull(tool))
|
||||
tool = user.get_active_held_item()
|
||||
var/tool_multiplier = is_sculpting_tool(tool)
|
||||
if(isnull(tool_multiplier))
|
||||
if(!silent)
|
||||
user?.action_feedback(SPAN_WARNING("You must be holding a valid sculpting tool."), src)
|
||||
return FALSE
|
||||
var/atom/movable/target = isnull(forced_target)? ask_for_target(user) : forced_target
|
||||
if(isnull(target))
|
||||
return FALSE
|
||||
if(tool != user.get_active_held_item())
|
||||
return FALSE
|
||||
if(finished)
|
||||
if(!silent)
|
||||
user?.action_feedback(SPAN_WARNING("[src] is finished."), src)
|
||||
return FALSE
|
||||
if(sculpting)
|
||||
if(!silent)
|
||||
user?.action_feedback(SPAN_WARNING("Someone's already working on [src]."), src)
|
||||
return FALSE
|
||||
if(!user.Adjacent(src))
|
||||
return FALSE
|
||||
|
||||
sculpting = TRUE
|
||||
|
||||
var/list/model_tuple = get_model_tuple(target)
|
||||
TIMER_COOLDOWN_START(src, CD_INDEX_SCULPTING_COOLDOWN, 1 SECONDS)
|
||||
var/icon/model = model_tuple[1]
|
||||
var/model_width = model.Width()
|
||||
var/model_height = model.Height()
|
||||
if(model_height > icon_y_dimension)
|
||||
if(!silent)
|
||||
user.action_feedback(SPAN_WARNING("[target] is too tall."), src)
|
||||
sculpting = FALSE
|
||||
return FALSE
|
||||
// align
|
||||
var/model_x_align = 0
|
||||
if(isnull(slate_dimension_x))
|
||||
slate_dimension_x = icon_x_dimension
|
||||
if(isnull(slate_dimension_y))
|
||||
slate_dimension_y = icon_y_dimension
|
||||
// align to bottom, center width
|
||||
if(model_width != slate_dimension_x)
|
||||
model_x_align = FLOOR((slate_dimension_x - model_width) / 2, 1)
|
||||
|
||||
sculpting_buffer = model
|
||||
sculpting_user = user
|
||||
sculpting_target = target
|
||||
sculpting_line_start = sculpting_line
|
||||
sculpting_overlay_active = model_height >= sculpting_line
|
||||
|
||||
var/lines = 0
|
||||
|
||||
if(isnull(sculpting_rolldown_mask))
|
||||
sculpting_rolldown_mask = icon('icons/system/color_32x32.dmi', "white")
|
||||
if(sculpting_rolldown_mask.Width() != icon_x_dimension || sculpting_rolldown_mask.Height() != icon_y_dimension)
|
||||
sculpting_rolldown_mask.Scale(icon_x_dimension, icon_y_dimension)
|
||||
|
||||
if(isnull(sculpting_renderer))
|
||||
sculpting_renderer = new
|
||||
vis_contents += sculpting_renderer
|
||||
|
||||
sculpting_renderer.icon = sculpting_buffer
|
||||
sculpting_renderer.pixel_x = model_x_align
|
||||
sculpting_renderer.alpha = sculpting_overlay_active? initial(sculpting_renderer.alpha) : 0
|
||||
|
||||
if(isnull(sculpting_mask))
|
||||
sculpting_mask = icon('icons/system/color_32x32.dmi', "white")
|
||||
if(sculpting_mask.Width() != model_width || sculpting_mask.Height() != model_height)
|
||||
sculpting_mask.Scale(model_width, model_height)
|
||||
|
||||
if(sculpting_overlay_active)
|
||||
sculpting_renderer.add_filter("slate", 0, alpha_mask_filter(0, sculpting_line - model_height, sculpting_mask, flags = MASK_INVERSE))
|
||||
sculpting_renderer.add_filter("cut_excess", 0, alpha_mask_filter(0, sculpting_line, sculpting_mask, flags = MASK_INVERSE))
|
||||
|
||||
// todo: actual chisels wit htoolsounds, screwdrivers are dogshit
|
||||
playsound(src, 'sound/effects/break_stone.ogg', vary = TRUE, vol = 50)
|
||||
user.visible_action_feedback(
|
||||
target = src,
|
||||
hard_range = MESSAGE_RANGE_CONSTRUCTION,
|
||||
visible_hard = SPAN_NOTICE("[user] starts chiselling at [src]..."),
|
||||
)
|
||||
|
||||
// deciseconds progress
|
||||
var/progress = 0
|
||||
var/time_per_line = sculpting_hardness * tool_multiplier
|
||||
var/finished_progress = sculpting_line_start * time_per_line
|
||||
var/last = world.time
|
||||
var/last_line = 0
|
||||
|
||||
var/datum/progressbar/progressbar = new(user, sculpting_line, src)
|
||||
|
||||
while(progress < finished_progress)
|
||||
if(QDELETED(src))
|
||||
QDEL_NULL(progressbar)
|
||||
return
|
||||
if(!do_after(user, time_per_line, src, DO_AFTER_NO_PROGRESS))
|
||||
break
|
||||
var/should_be_at = sculpting_line - FLOOR(progress / time_per_line, 1)
|
||||
if(should_be_at != last_line)
|
||||
last_line = should_be_at
|
||||
if(last_line > model_height)
|
||||
else
|
||||
if(!sculpting_overlay_active)
|
||||
sculpting_overlay_active = TRUE
|
||||
sculpting_renderer.alpha = 255
|
||||
sculpting_renderer.add_filter("cut_excess", 0, alpha_mask_filter(0, sculpting_line, sculpting_mask, flags = MASK_INVERSE))
|
||||
sculpting_renderer.add_filter("slate", 0, alpha_mask_filter(0, should_be_at - model_height, sculpting_mask, flags = MASK_INVERSE))
|
||||
add_filter("top_erasure", 0, alpha_mask_filter(1, should_be_at, sculpting_rolldown_mask, flags = MASK_INVERSE))
|
||||
|
||||
progress += world.time - last
|
||||
last = world.time
|
||||
progressbar.update(sculpting_line - should_be_at)
|
||||
|
||||
QDEL_NULL(progressbar)
|
||||
|
||||
lines = min(sculpting_line, progress / time_per_line)
|
||||
|
||||
sculpting_line_end = sculpting_line_start - lines
|
||||
sculpting_line -= lines
|
||||
|
||||
if(lines)
|
||||
if(isnull(sculpting_slates))
|
||||
create_slates()
|
||||
var/model_x_realigned = 0
|
||||
if(slate_dimension_x < model_width)
|
||||
// allow expansion but only for width
|
||||
var/x_alignment = FLOOR((model_width - slate_dimension_x) / 2, 1)
|
||||
model_x_realigned = x_alignment
|
||||
crop_slates(-x_alignment + 1, 1, slate_dimension_x + (model_width - slate_dimension_x - x_alignment), slate_dimension_y)
|
||||
alignment -= x_alignment
|
||||
set_base_pixel_x(base_pixel_x - x_alignment)
|
||||
if(!sculpting_overlay_active)
|
||||
// we didn't even reach the buffer yet
|
||||
else
|
||||
sculpting_buffer = crop_buffer(sculpting_buffer, 1, sculpting_line_end + 1, model_width, sculpting_line_start)
|
||||
//! TODO: this shouldn't be needed, but somehow is because of shennanigans. Figure out why and get rid of.
|
||||
preprocess_model_buffer(sculpting_buffer)
|
||||
//! End
|
||||
blend_slates(sculpting_buffer, model_x_align + 1 + model_x_realigned, sculpting_line_end + 1)
|
||||
assemble_built()
|
||||
update_appearance()
|
||||
|
||||
sculpting_line_start = null
|
||||
sculpting_buffer = null
|
||||
sculpting_line_end = null
|
||||
sculpting_user = null
|
||||
sculpting_target = null
|
||||
sculpting_overlay_active = null
|
||||
|
||||
add_filter("top_erasure", 0, alpha_mask_filter(1, sculpting_line, sculpting_rolldown_mask, flags = MASK_INVERSE))
|
||||
sculpting_renderer.alpha = 0
|
||||
sculpting_renderer.clear_filters()
|
||||
|
||||
if(check_completion())
|
||||
user.visible_action_feedback(
|
||||
target = src,
|
||||
hard_range = MESSAGE_RANGE_CONSTRUCTION,
|
||||
visible_hard = SPAN_NOTICE("[user] finishes chiselling at [src] with a flourish."),
|
||||
)
|
||||
|
||||
sculpting = FALSE
|
||||
|
||||
/obj/structure/sculpting_block/proc/check_completion()
|
||||
if(!sculpting_line)
|
||||
finished = TRUE
|
||||
flush_finished()
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/structure/sculpting_block/proc/flush_finished()
|
||||
assemble_built()
|
||||
icon = sculpting_built
|
||||
sculpting_built = null
|
||||
sculpting_slates = null
|
||||
name = "sculpted statue"
|
||||
desc = "A custom-chiseled statue depicting a particular thing of note."
|
||||
QDEL_NULL(sculpting_renderer)
|
||||
clear_filters()
|
||||
update_appearance()
|
||||
|
||||
/obj/structure/sculpting_block/proc/crop_buffer(icon/buffer, x1, y1, x2, y2)
|
||||
var/icon/built = icon('icons/system/blank_32x32.dmi', "")
|
||||
var/icon/cropping
|
||||
cropping = icon(buffer, dir = NORTH)
|
||||
cropping.Crop(x1, y1, x2, y2)
|
||||
built.Insert(cropping, dir = NORTH)
|
||||
cropping = icon(buffer, dir = EAST)
|
||||
cropping.Crop(x1, y1, x2, y2)
|
||||
built.Insert(cropping, dir = EAST)
|
||||
cropping = icon(buffer, dir = SOUTH)
|
||||
cropping.Crop(x1, y1, x2, y2)
|
||||
built.Insert(cropping, dir = SOUTH)
|
||||
cropping = icon(buffer, dir = WEST)
|
||||
cropping.Crop(x1, y1, x2, y2)
|
||||
built.Insert(cropping, dir = WEST)
|
||||
return built
|
||||
|
||||
/obj/structure/sculpting_block/proc/assemble_built()
|
||||
sculpting_built = icon('icons/system/blank_32x32.dmi', "")
|
||||
sculpting_built.Insert(sculpting_slates[1], dir = NORTH)
|
||||
sculpting_built.Insert(sculpting_slates[2], dir = EAST)
|
||||
sculpting_built.Insert(sculpting_slates[3], dir = SOUTH)
|
||||
sculpting_built.Insert(sculpting_slates[4], dir = WEST)
|
||||
|
||||
/**
|
||||
* grabs an icon from something for sculpting, processing it into a greyscale toned to the material's color
|
||||
*
|
||||
* @params
|
||||
* * to_clone - the atom the person is trying to replicate with the sculpt. no turfs.
|
||||
* * material_color - the color to tone to as rgb color string
|
||||
*
|
||||
* @return list(icon, x, y) where x/y are centering offsets
|
||||
*/
|
||||
/obj/structure/sculpting_block/proc/get_model_tuple(atom/movable/to_clone, material_color)
|
||||
. = get_compound_icon_with_offsets(to_clone, CALLBACK(src, PROC_REF(preprocess_model_slice)))
|
||||
if(isnull(.))
|
||||
return
|
||||
|
||||
/obj/structure/sculpting_block/proc/preprocess_model_slice(icon/slice)
|
||||
slice.ColorTone(material.icon_colour)
|
||||
|
||||
/obj/structure/sculpting_block/proc/preprocess_model_buffer(icon/slice)
|
||||
slice.ColorTone(material.icon_colour)
|
||||
|
||||
/**
|
||||
* get things in range of user that can be sculpted
|
||||
*/
|
||||
/obj/structure/sculpting_block/proc/get_possible_targets(mob/user, range_to_scan = 7)
|
||||
. = list()
|
||||
var/list/atom/potential = view(range_to_scan, user)
|
||||
var/list/mob/mobs = list()
|
||||
var/list/obj/objs = list()
|
||||
var/list/objs_seen_paths = list()
|
||||
for(var/atom/movable/AM in potential)
|
||||
if(AM.atom_flags & ATOM_ABSTRACT)
|
||||
continue
|
||||
if(!isturf(AM.loc))
|
||||
continue
|
||||
if(AM.invisibility > user.see_invisible)
|
||||
continue
|
||||
if(!user.can_see_plane(AM.plane))
|
||||
continue
|
||||
if(isobj(AM))
|
||||
var/obj/O = AM
|
||||
if(O.obj_flags & OBJ_NO_SCULPTING)
|
||||
continue
|
||||
if(objs_seen_paths[O.type])
|
||||
continue
|
||||
objs_seen_paths[O.type] = TRUE
|
||||
objs += O
|
||||
else
|
||||
var/mob/M = AM
|
||||
//! legacy code
|
||||
if(M.is_incorporeal())
|
||||
continue
|
||||
//! end
|
||||
mobs += M
|
||||
return mobs + objs
|
||||
|
||||
/**
|
||||
* ask someone for target
|
||||
*/
|
||||
/obj/structure/sculpting_block/proc/ask_for_target(mob/user)
|
||||
// todo: when we have click intercepts refactored, user should be asked to click on a target.
|
||||
var/list/possible = get_possible_targets(user)
|
||||
return input(user, "Pick a target", "Sculpting") as null|anything in possible
|
||||
|
||||
/obj/structure/sculpting_block/proc/create_slates()
|
||||
sculpting_slates = list()
|
||||
for(var/i in 1 to 4)
|
||||
var/icon/generated
|
||||
generated = icon('icons/system/blank_32x32.dmi')
|
||||
generated.Scale(icon_x_dimension, icon_y_dimension)
|
||||
sculpting_slates += generated
|
||||
slate_dimension_x = icon_x_dimension
|
||||
slate_dimension_y = icon_y_dimension
|
||||
|
||||
/obj/structure/sculpting_block/proc/blend_slates(icon/blending, x, y)
|
||||
sculpting_slates[1].Blend(icon(blending, dir = NORTH), ICON_OVERLAY, x, y)
|
||||
sculpting_slates[2].Blend(icon(blending, dir = EAST), ICON_OVERLAY, x, y)
|
||||
sculpting_slates[3].Blend(icon(blending, dir = SOUTH), ICON_OVERLAY, x, y)
|
||||
sculpting_slates[4].Blend(icon(blending, dir = WEST), ICON_OVERLAY, x, y)
|
||||
|
||||
/obj/structure/sculpting_block/proc/crop_slates(x1, y1, x2, y2)
|
||||
for(var/i in 1 to 4)
|
||||
var/icon/cropping = sculpting_slates[i]
|
||||
cropping.Crop(x1, y1, x2, y2)
|
||||
|
||||
/obj/structure/sculpting_block/proc/check_target(mob/user, atom/movable/target)
|
||||
if(isnull(sculpting_user))
|
||||
return TRUE // userless
|
||||
if(QDELETED(user) || QDELETED(target))
|
||||
return FALSE
|
||||
if(get_dist(user, target) > min(user.using_perspective.cached_view_width, user.using_perspective.cached_view_height))
|
||||
return FALSE
|
||||
if(!user.can_see_plane(target.plane))
|
||||
return FALSE
|
||||
if(target.invisibility > user.see_invisible)
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* rendering object that sits in vis contents while sculpting
|
||||
*/
|
||||
/atom/movable/sculpting_render
|
||||
atom_flags = ATOM_ABSTRACT
|
||||
vis_flags = VIS_INHERIT_PLANE | VIS_INHERIT_DIR | VIS_INHERIT_ID
|
||||
layer = FLOAT_LAYER
|
||||
plane = OBJ_PLANE
|
||||
mouse_opacity = MOUSE_OPACITY_ICON
|
||||
|
||||
/atom/movable/sculpting_render/Destroy()
|
||||
vis_locs.len = 0
|
||||
return ..()
|
||||
Reference in New Issue
Block a user