mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-07-16 10:35:41 +01:00
[MDB IGNORE] [IDB IGNORE] Upstream Sync - 04/17/2026 (#5453)
Upstream 04/17/2026 fixes https://github.com/Bubberstation/Bubberstation/issues/5549 --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: tgstation-ci[bot] <179393467+tgstation-ci[bot]@users.noreply.github.com> Co-authored-by: ArcaneMusic <41715314+ArcaneMusic@users.noreply.github.com> Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Co-authored-by: Rhials <28870487+Rhials@users.noreply.github.com> Co-authored-by: rageguy505 <54517726+rageguy505@users.noreply.github.com> Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com> Co-authored-by: John Willard <53777086+JohnFulpWillard@users.noreply.github.com> Co-authored-by: Aliceee2ch <160794176+Aliceee2ch@users.noreply.github.com> Co-authored-by: Time-Green <7501474+Time-Green@users.noreply.github.com> Co-authored-by: Tsar-Salat <62388554+Tsar-Salat@users.noreply.github.com> Co-authored-by: SmArtKar <44720187+SmArtKar@users.noreply.github.com> Co-authored-by: Maxipat <108554989+Maxipat112@users.noreply.github.com> Co-authored-by: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> Co-authored-by: deltanedas <39013340+deltanedas@users.noreply.github.com> Co-authored-by: SimplyLogan <47579821+loganuk@users.noreply.github.com> Co-authored-by: loganuk <fakeemail123@aol.com> Co-authored-by: Leland Kemble <70413276+lelandkemble@users.noreply.github.com> Co-authored-by: FalloutFalcon <86381784+FalloutFalcon@users.noreply.github.com> Co-authored-by: Roxy <75404941+TealSeer@users.noreply.github.com> Co-authored-by: Lucy <lucy@absolucy.moe> Co-authored-by: siliconOpossum <138069572+siliconOpossum@users.noreply.github.com> Co-authored-by: Isratosh <Isratosh@hotmail.com> Co-authored-by: TheRyeGuyWhoWillNowDie <70169560+TheRyeGuyWhoWillNowDie@users.noreply.github.com> Co-authored-by: Neocloudy <88008002+Neocloudy@users.noreply.github.com> Co-authored-by: Alexander V. <volas@ya.ru> Co-authored-by: ElGitificador <168473461+ElGitificador@users.noreply.github.com> Co-authored-by: Twaticus <46540570+Twaticus@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> Co-authored-by: Cameron Lennox <killer65311@gmail.com> Co-authored-by: Tim <timothymtorres@gmail.com> Co-authored-by: Iamgoofball <iamgoofball@gmail.com> Co-authored-by: Layzu666 <121319428+Layzu666@users.noreply.github.com> Co-authored-by: Arturlang <24881678+Arturlang@users.noreply.github.com> Co-authored-by: _0Steven <42909981+00-Steven@users.noreply.github.com> Co-authored-by: mrmanlikesbt <99309552+mrmanlikesbt@users.noreply.github.com> Co-authored-by: Ben10Omintrix <138636438+Ben10Omintrix@users.noreply.github.com> Co-authored-by: John F. Kennedy <54908920+MacaroniCritter@users.noreply.github.com> Co-authored-by: Cursor <102828457+theselfish@users.noreply.github.com> Co-authored-by: Josh <josh.adam.powell@gmail.com> Co-authored-by: Josh Powell <josh.powell@softwire.com> Co-authored-by: Yobrocharlie <Charliemiller5617@gmail.com> Co-authored-by: Hardly3D <66234359+Hardly3D@users.noreply.github.com> Co-authored-by: shayoki <96078776+shayoki@users.noreply.github.com> Co-authored-by: LT3 <83487515+lessthnthree@users.noreply.github.com>
This commit is contained in:
@@ -215,7 +215,7 @@
|
||||
user.log_message("accepted a shuttle loan event.", LOG_GAME)
|
||||
. = TRUE
|
||||
if("add")
|
||||
var/id = text2path(params["id"])
|
||||
var/id = text2path(params["id"]) || params["id"]
|
||||
var/datum/supply_pack/pack = SSshuttle.supply_packs[id]
|
||||
if(!istype(pack))
|
||||
return
|
||||
|
||||
@@ -1,3 +1,89 @@
|
||||
GLOBAL_LIST_INIT(print_types, init_print_types())
|
||||
|
||||
/proc/init_print_types()
|
||||
var/list/print_types = list()
|
||||
for(var/obj/item/canvas/canvas_type as anything in typesof(/obj/item/canvas))
|
||||
var/width = canvas_type::width
|
||||
var/height = canvas_type::height
|
||||
LAZYADDASSOC(print_types, "[width]x[height]", list(
|
||||
"displayText" = "Canvas ([width]x[height])",
|
||||
"typepath" = canvas_type,
|
||||
"width" = width,
|
||||
"height" = height,
|
||||
"check_callback" = CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(check_can_print_canvas)),
|
||||
"prepare_callback" = CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(prepare_canvas_from_file)),
|
||||
))
|
||||
for(var/size in 1 to CAMERA_PICTURE_SIZE_HARD_LIMIT)
|
||||
var/meters = APERTURE_TO_METERS(size)
|
||||
var/width = ICON_SIZE_X * meters
|
||||
var/height = ICON_SIZE_Y * meters
|
||||
LAZYADDASSOC(print_types, "[width]x[height]", list(
|
||||
"displayText" = "Photo Paper ([meters]m focal length)",
|
||||
"typepath" = /obj/item/photo,
|
||||
"width" = width,
|
||||
"height" = height,
|
||||
"check_callback" = CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(check_can_print_photo)),
|
||||
"prepare_callback" = CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(prepare_photo_from_file)),
|
||||
))
|
||||
return print_types
|
||||
|
||||
/proc/check_can_print_canvas(_typepath, _image_file, obj/item/modular_computer/computer, mob/user)
|
||||
if(!(computer.hardware_flag & PROGRAM_CONSOLE))
|
||||
to_chat(user, span_notice("Printing error: Canvas printing is only supported on stationary consoles."))
|
||||
return FALSE
|
||||
if(computer.stored_paper < CANVAS_PAPER_COST)
|
||||
to_chat(user, span_notice("Printing error: Your printer needs at least [CANVAS_PAPER_COST] paper to print a canvas."))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/proc/prepare_canvas_from_file(obj/item/canvas/canvas, datum/computer_file/image/image_file, obj/item/modular_computer/computer, width, height, x, y)
|
||||
computer.stored_paper -= CANVAS_PAPER_COST
|
||||
if(istype(image_file.source_photo_or_painting, /datum/painting))
|
||||
var/datum/painting/source_painting = image_file.source_photo_or_painting
|
||||
var/icon/painting_icon = source_painting.get_icon()
|
||||
if(width == painting_icon.Width() && height == painting_icon.Height() && !x && !y)
|
||||
source_painting.fill_canvas(canvas)
|
||||
return
|
||||
var/datum/icon_transformer/transformer = new()
|
||||
var/temp_file = "tmp/[copytext(REF(image_file.stored_icon), 2, -1)].dmi"
|
||||
fcopy(image_file.stored_icon, temp_file)
|
||||
transformer.scale(width, height)
|
||||
transformer.blend_color("#ffffff", ICON_OVERLAY)
|
||||
transformer.blend_icon(uni_icon(temp_file, ""), ICON_OVERLAY, x+1, y+1)
|
||||
var/datum/universal_icon/blank = uni_icon('icons/blanks/32x32.dmi', "nothing", transform = transformer)
|
||||
canvas.fill_grid_from_icon(blank.to_icon())
|
||||
fdel(temp_file)
|
||||
canvas.painting_metadata.medium = "Digital Art"
|
||||
canvas.used = TRUE
|
||||
canvas.update_icon()
|
||||
|
||||
/proc/check_can_print_photo(_typepath, _image_file, obj/item/modular_computer/computer, mob/user)
|
||||
if(computer.stored_paper < PHOTO_PAPER_COST)
|
||||
to_chat(user, span_notice("Printing error: Your printer needs at least [PHOTO_PAPER_COST] paper to print a photo."))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/proc/prepare_photo_from_file(obj/item/photo/photo, datum/computer_file/image/image_file, obj/item/modular_computer/computer, width, height, x, y)
|
||||
computer.stored_paper -= PHOTO_PAPER_COST
|
||||
var/icon/photo_image = image_file.stored_icon
|
||||
var/image_width = photo_image.Width()
|
||||
var/image_height = photo_image.Height()
|
||||
if(istype(image_file.source_photo_or_painting, /datum/picture) && width == image_width && height == image_height && !x && !y)
|
||||
var/datum/picture/source_photo = image_file.source_photo_or_painting
|
||||
photo.set_picture(source_photo, TRUE, TRUE)
|
||||
return
|
||||
var/datum/icon_transformer/transformer = new()
|
||||
var/temp_file = "tmp/[copytext(REF(photo_image), 2, -1)].dmi"
|
||||
fcopy(photo_image, temp_file)
|
||||
transformer.scale(width, height)
|
||||
transformer.blend_color("#ffffff", ICON_OVERLAY)
|
||||
transformer.blend_icon(uni_icon(temp_file, ""), ICON_OVERLAY, x+1, y+1)
|
||||
var/datum/universal_icon/blank = uni_icon('icons/blanks/32x32.dmi', "nothing", transform = transformer)
|
||||
var/datum/picture/new_photo = new(image_file.filename, desc = "A printout of a digital image.", image = blank.to_icon(), size_x = width, size_y = height, autogenerate_icon = TRUE, author_ckey_ = image_file.author_ckey)
|
||||
fdel(temp_file)
|
||||
image_file.source_photo_or_painting = new_photo
|
||||
photo.set_picture(new_photo, TRUE, TRUE)
|
||||
|
||||
/datum/computer_file/program/filemanager
|
||||
filename = "filemanager"
|
||||
filedesc = "File Manager"
|
||||
@@ -33,7 +119,7 @@
|
||||
var/datum/computer_file/file = computer.find_file_by_name(params["name"])
|
||||
if(!file)
|
||||
return
|
||||
var/newname = reject_bad_name(params["new_name"])
|
||||
var/newname = reject_bad_name(params["new_name"], allow_numbers = TRUE, cap_after_symbols = FALSE, cap_at_start = FALSE)
|
||||
if(!newname || newname != params["new_name"])
|
||||
playsound(computer, 'sound/machines/terminal/terminal_error.ogg', 25, FALSE)
|
||||
return
|
||||
@@ -45,7 +131,7 @@
|
||||
var/datum/computer_file/file = computer.find_file_by_name(params["name"], computer.inserted_disk)
|
||||
if(!file)
|
||||
return
|
||||
var/newname = reject_bad_name(params["new_name"])
|
||||
var/newname = reject_bad_name(params["new_name"], allow_numbers = TRUE, cap_after_symbols = FALSE, cap_at_start = FALSE)
|
||||
if(!newname || newname != params["new_name"])
|
||||
playsound(computer, 'sound/machines/terminal/terminal_error.ogg', 25, FALSE)
|
||||
return
|
||||
@@ -78,6 +164,54 @@
|
||||
if(!binary || !istype(binary))
|
||||
return
|
||||
binary.alert_silenced = !binary.alert_silenced
|
||||
if("PRG_print")
|
||||
var/datum/computer_file/image/picture = computer.find_file_by_name(params["name"])
|
||||
if(!istype(picture))
|
||||
return
|
||||
try_print(picture, params["width"], params["height"], params["offsetX"], params["offsetY"], params["typepath"], usr)
|
||||
if("PRG_usbprint")
|
||||
if(!computer.inserted_disk)
|
||||
return
|
||||
var/datum/computer_file/image/picture = computer.find_file_by_name(params["name"], computer.inserted_disk)
|
||||
if(!istype(picture))
|
||||
return
|
||||
try_print(picture, params["width"], params["height"], params["offsetX"], params["offsetY"], params["typepath"], usr)
|
||||
|
||||
/datum/computer_file/program/filemanager/proc/try_print(datum/computer_file/image/picture, width, height, offset_x, offset_y, typepath, mob/user)
|
||||
var/list/print_type = GLOB.print_types["[width]x[height]"]
|
||||
if(!length(print_type))
|
||||
return
|
||||
var/image_width = picture.stored_icon.Width()
|
||||
var/image_height = picture.stored_icon.Height()
|
||||
var/min_offset_x = min(width - image_width, 0)
|
||||
var/max_offset_x = max(width - image_width, 0)
|
||||
var/min_offset_y = min(height - image_height, 0)
|
||||
var/max_offset_y = max(height - image_height, 0)
|
||||
if(!ISINRANGE(offset_x, min_offset_x, max_offset_x) || !ISINRANGE(offset_y, min_offset_y, max_offset_y))
|
||||
return
|
||||
typepath = text2path(typepath)
|
||||
var/datum/callback/check_callback = print_type["check_callback"]
|
||||
if(!check_callback.Invoke(typepath, picture, computer, user))
|
||||
return
|
||||
var/obj/item/printed_item = new typepath(computer.physical.drop_location())
|
||||
var/datum/callback/prepare_callback = print_type["prepare_callback"]
|
||||
prepare_callback.Invoke(printed_item, picture, computer, width, height, offset_x, offset_y)
|
||||
user?.put_in_hands(printed_item)
|
||||
playsound(computer.physical, 'sound/machines/printer.ogg', 100, TRUE)
|
||||
|
||||
/datum/computer_file/program/filemanager/ui_static_data(mob/user)
|
||||
var/list/print_types = list()
|
||||
for(var/dimensions, types_for_dimensions in GLOB.print_types)
|
||||
var/list/typepath = types_for_dimensions["typepath"]
|
||||
if(ispath(typepath, /obj/item/canvas) && !(computer.hardware_flag & PROGRAM_CONSOLE))
|
||||
continue
|
||||
print_types += list(list(
|
||||
displayText = types_for_dimensions["displayText"],
|
||||
typepath = "[typepath]",
|
||||
width = types_for_dimensions["width"],
|
||||
height = types_for_dimensions["height"]
|
||||
))
|
||||
return list("printTypes" = print_types)
|
||||
|
||||
/datum/computer_file/program/filemanager/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
@@ -90,10 +224,20 @@
|
||||
for(var/datum/computer_file/F as anything in computer.stored_files)
|
||||
var/noisy = FALSE
|
||||
var/silenced = FALSE
|
||||
var/printable = FALSE
|
||||
var/image_width = 0
|
||||
var/image_height = 0
|
||||
var/image_ref
|
||||
var/datum/computer_file/program/binary = F
|
||||
if(istype(binary))
|
||||
noisy = binary.alert_able
|
||||
silenced = binary.alert_silenced
|
||||
var/datum/computer_file/image/picture_file = F
|
||||
if(istype(picture_file))
|
||||
printable = TRUE
|
||||
image_width = picture_file.stored_icon.Width()
|
||||
image_height = picture_file.stored_icon.Height()
|
||||
image_ref = picture_file.get_image_ref()
|
||||
files += list(list(
|
||||
"name" = F.filename,
|
||||
"type" = F.filetype,
|
||||
@@ -101,17 +245,35 @@
|
||||
"undeletable" = F.undeletable,
|
||||
"alert_able" = noisy,
|
||||
"alert_silenced" = silenced,
|
||||
"printable" = printable,
|
||||
"image_ref" = image_ref,
|
||||
"image_width" = image_width,
|
||||
"image_height" = image_height,
|
||||
))
|
||||
data["files"] = files
|
||||
if(computer.inserted_disk)
|
||||
data["usbconnected"] = TRUE
|
||||
var/list/usbfiles = list()
|
||||
for(var/datum/computer_file/F as anything in computer.inserted_disk.stored_files)
|
||||
var/printable = FALSE
|
||||
var/image_width = 0
|
||||
var/image_height = 0
|
||||
var/image_ref
|
||||
var/datum/computer_file/image/picture_file = F
|
||||
if(istype(picture_file))
|
||||
printable = TRUE
|
||||
image_width = picture_file.stored_icon.Width()
|
||||
image_height = picture_file.stored_icon.Height()
|
||||
image_ref = picture_file.get_image_ref()
|
||||
usbfiles += list(list(
|
||||
"name" = F.filename,
|
||||
"type" = F.filetype,
|
||||
"size" = F.size,
|
||||
"undeletable" = F.undeletable,
|
||||
"printable" = printable,
|
||||
"image_ref" = image_ref,
|
||||
"image_width" = image_width,
|
||||
"image_height" = image_height,
|
||||
))
|
||||
data["usbfiles"] = usbfiles
|
||||
|
||||
|
||||
@@ -14,20 +14,29 @@
|
||||
var/obj/item/camera/app/internal_camera
|
||||
/// Latest picture taken by the app.
|
||||
var/datum/picture/internal_picture
|
||||
/// base64 of the current taken picture
|
||||
var/internal_picture_icon
|
||||
/// How many pictures were taken already, used for the camera's TGUI photo display
|
||||
var/picture_number = 1
|
||||
/// Can we edit the metadata of the latest picture?
|
||||
var/can_edit_metadata = TRUE
|
||||
/// The name we will give to the picture when we first save it
|
||||
var/current_picture_name
|
||||
/// The description we will give to the picture when we first save it
|
||||
var/current_picture_desc
|
||||
/// The caption we will give to the picture when we first save it
|
||||
var/current_picture_caption
|
||||
|
||||
// Special type of camera for this exact usecase to prevent harddels
|
||||
/obj/item/camera/app
|
||||
name = "internal camera"
|
||||
desc = "Specialized internal camera protected from the hellish depths of SSWardrobe. \
|
||||
Yell at coders if you somehow manage to see this"
|
||||
print_picture_on_snap = FALSE
|
||||
cooldown = 1 SECONDS
|
||||
light_range = 3
|
||||
|
||||
/datum/computer_file/program/maintenance/camera/on_install(datum/computer_file/source, obj/item/modular_computer/computer_installing, mob/user)
|
||||
. = ..()
|
||||
internal_camera = new(computer)
|
||||
internal_camera.print_picture_on_snap = FALSE
|
||||
RegisterSignal(internal_camera, COMSIG_CAMERA_IMAGE_CAPTURED, PROC_REF(save_picture))
|
||||
RegisterSignal(internal_camera, COMSIG_CAMERA_IMAGE_CAPTURED, PROC_REF(on_image_captured))
|
||||
|
||||
/datum/computer_file/program/maintenance/camera/Destroy()
|
||||
QDEL_NULL(internal_camera)
|
||||
@@ -36,92 +45,132 @@
|
||||
|
||||
/datum/computer_file/program/maintenance/camera/tap(atom/tapped_atom, mob/living/user, list/modifiers)
|
||||
. = ..()
|
||||
take_picture(user, get_turf(tapped_atom))
|
||||
|
||||
/datum/computer_file/program/maintenance/camera/on_made_active_program(user)
|
||||
RegisterSignal(computer, COMSIG_RANGED_ITEM_INTERACTING_WITH_ATOM_SECONDARY, PROC_REF(on_computer_ranged_interact))
|
||||
|
||||
/datum/computer_file/program/maintenance/camera/kill_program(mob/user)
|
||||
. = ..()
|
||||
UnregisterSignal(computer, COMSIG_RANGED_ITEM_INTERACTING_WITH_ATOM_SECONDARY)
|
||||
QDEL_NULL(internal_picture)
|
||||
if(internal_camera.blending)
|
||||
user.balloon_alert(user, "still blending!")
|
||||
return
|
||||
|
||||
var/turf/our_turf = get_turf(tapped_atom)
|
||||
var/spooky_camera = locate(/datum/computer_file/program/maintenance/spectre_meter) in computer.stored_files
|
||||
internal_camera.see_ghosts = spooky_camera ? CAMERA_SEE_GHOSTS_BASIC : CAMERA_NO_GHOSTS
|
||||
INVOKE_ASYNC(internal_camera, TYPE_PROC_REF(/obj/item/camera, captureimage), our_turf, user, internal_camera.picture_size_x + 1, internal_camera.picture_size_y + 1)
|
||||
/datum/computer_file/program/maintenance/camera/background_program(mob/user)
|
||||
. = ..()
|
||||
UnregisterSignal(computer, COMSIG_RANGED_ITEM_INTERACTING_WITH_ATOM_SECONDARY)
|
||||
|
||||
/datum/computer_file/program/maintenance/camera/proc/save_picture(cam, target, user, datum/picture/picture)
|
||||
/datum/computer_file/program/maintenance/camera/proc/on_computer_ranged_interact(_source, mob/user, atom/target, list/modifiers)
|
||||
SIGNAL_HANDLER
|
||||
take_picture(user, get_turf(target))
|
||||
|
||||
/datum/computer_file/program/maintenance/camera/proc/take_picture(mob/user, turf/target)
|
||||
internal_camera.see_ghosts = (locate(/datum/computer_file/program/maintenance/spectre_meter) in computer.stored_files) ? CAMERA_SEE_GHOSTS_BASIC : CAMERA_NO_GHOSTS
|
||||
internal_camera.attempt_picture(target, user)
|
||||
|
||||
/datum/computer_file/program/maintenance/camera/proc/on_image_captured(cam, target, user, datum/picture/picture)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
QDEL_NULL(internal_picture)
|
||||
internal_picture = picture
|
||||
internal_picture_icon = icon2base64(internal_picture.picture_image)
|
||||
current_picture_name = null
|
||||
current_picture_desc = null
|
||||
current_picture_caption = null
|
||||
can_edit_metadata = TRUE
|
||||
picture_number++
|
||||
computer.save_photo(internal_picture.picture_image)
|
||||
|
||||
/datum/computer_file/program/maintenance/camera/proc/commit_metadata()
|
||||
if(can_edit_metadata)
|
||||
internal_picture.picture_name = current_picture_name
|
||||
internal_picture.picture_desc = "[current_picture_desc] - [internal_picture.picture_desc]"
|
||||
internal_picture.caption = current_picture_caption
|
||||
can_edit_metadata = FALSE
|
||||
|
||||
/datum/computer_file/program/maintenance/camera/ui_static_data(mob/user)
|
||||
return list(
|
||||
"maxNameLength" = 32,
|
||||
"maxDescLength" = 128,
|
||||
"maxCaptionLength" = 256,
|
||||
"printCost" = 1,
|
||||
"minSize" = 2,
|
||||
"maxSize" = CAMERA_PICTURE_SIZE_HARD_LIMIT
|
||||
)
|
||||
|
||||
/datum/computer_file/program/maintenance/camera/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
|
||||
if(!isnull(internal_picture))
|
||||
user << browse_rsc(internal_picture.picture_image, "tmp_photo[picture_number].png")
|
||||
data["photo"] = "tmp_photo[picture_number].png"
|
||||
data["photo"] = internal_picture_icon
|
||||
data["canEditMetadata"] = can_edit_metadata
|
||||
data["name"] = current_picture_name
|
||||
data["desc"] = current_picture_desc
|
||||
data["caption"] = current_picture_caption
|
||||
data["storedPaper"] = computer.stored_paper
|
||||
|
||||
data["paper_left"] = computer.stored_paper
|
||||
data["width"] = internal_camera.picture_size_x
|
||||
data["height"] = internal_camera.picture_size_y
|
||||
data["size"] = "[APERTURE_TO_METERS(internal_camera.picture_size_x)]x[APERTURE_TO_METERS(internal_camera.picture_size_y)]"
|
||||
|
||||
return data
|
||||
|
||||
/datum/computer_file/program/maintenance/camera/ui_act(action, params, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
|
||||
switch(action)
|
||||
if("print_photo")
|
||||
if(computer.stored_paper <= 0)
|
||||
to_chat(ui.user, span_notice("Hardware error: Printer out of paper."))
|
||||
if("adjustWidth")
|
||||
var/new_size = text2num(params["value"])
|
||||
if(!new_size)
|
||||
return
|
||||
internal_camera.printpicture(usr, internal_picture)
|
||||
return internal_camera.adjust_zoom(desired_x = new_size)
|
||||
|
||||
if("adjustHeight")
|
||||
var/new_size = text2num(params["value"])
|
||||
if(!new_size)
|
||||
return
|
||||
return internal_camera.adjust_zoom(desired_y = new_size)
|
||||
|
||||
if("setName")
|
||||
if(!(internal_picture && can_edit_metadata))
|
||||
return FALSE
|
||||
current_picture_name = trim(params["value"], PREVENT_CHARACTER_TRIM_LOSS(32))
|
||||
return TRUE
|
||||
|
||||
if("setDesc")
|
||||
if(!(internal_picture && can_edit_metadata))
|
||||
return
|
||||
current_picture_desc = trim(params["value"], PREVENT_CHARACTER_TRIM_LOSS(128))
|
||||
return TRUE
|
||||
|
||||
if("setCaption")
|
||||
if(!(internal_picture && can_edit_metadata))
|
||||
return
|
||||
current_picture_caption = trim(params["value"], PREVENT_CHARACTER_TRIM_LOSS(256))
|
||||
return TRUE
|
||||
|
||||
if("savePhoto")
|
||||
if(!internal_picture)
|
||||
return
|
||||
var/datum/computer_file/image/photo_file = new(
|
||||
internal_picture.picture_image,
|
||||
display_name = internal_picture.picture_name || "photo[picture_number]",
|
||||
source_photo_or_painting = internal_picture
|
||||
)
|
||||
if(computer.store_file(photo_file, ui.user))
|
||||
return FALSE
|
||||
commit_metadata()
|
||||
return TRUE
|
||||
if("printPhoto")
|
||||
if(!internal_picture)
|
||||
return FALSE
|
||||
if(computer.stored_paper < PHOTO_PAPER_COST)
|
||||
return FALSE
|
||||
commit_metadata()
|
||||
var/obj/item/photo/new_photo = new(computer.physical.drop_location())
|
||||
new_photo.set_picture(internal_picture, TRUE, TRUE)
|
||||
ui.user.put_in_hands(new_photo)
|
||||
playsound(computer.physical, 'sound/machines/printer.ogg', 100, TRUE)
|
||||
computer.stored_paper--
|
||||
computer.visible_message(span_notice("\The [computer] prints out a paper."))
|
||||
|
||||
/obj/item/circuit_component/mod_program/camera
|
||||
associated_program = /datum/computer_file/program/maintenance/camera
|
||||
circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL
|
||||
|
||||
///A target to take a picture of.
|
||||
var/datum/port/input/picture_target
|
||||
///The photographed target
|
||||
var/datum/port/output/photographed
|
||||
/**
|
||||
* Pinged when the image has been captured.
|
||||
* I'm not using the default trigger output here because the process is asynced,
|
||||
* even though I'm mostly sure it only sleeps if there's a set user.
|
||||
*/
|
||||
var/datum/port/output/photo_taken
|
||||
|
||||
/obj/item/circuit_component/mod_program/camera/populate_ports()
|
||||
. = ..()
|
||||
picture_target = add_input_port("Picture Target", PORT_TYPE_ATOM)
|
||||
photographed = add_output_port("Photographed Entity", PORT_TYPE_ATOM)
|
||||
photo_taken = add_output_port("Photo Taken", PORT_TYPE_SIGNAL)
|
||||
|
||||
/obj/item/circuit_component/mod_program/camera/register_shell(atom/movable/shell)
|
||||
. = ..()
|
||||
var/datum/computer_file/program/maintenance/camera/cam = associated_program
|
||||
RegisterSignal(cam.internal_camera, COMSIG_CAMERA_IMAGE_CAPTURED, PROC_REF(on_image_captured))
|
||||
|
||||
/obj/item/circuit_component/mod_program/camera/unregister_shell()
|
||||
var/datum/computer_file/program/maintenance/camera/cam = associated_program
|
||||
UnregisterSignal(cam.internal_camera, COMSIG_CAMERA_IMAGE_CAPTURED)
|
||||
return ..()
|
||||
|
||||
/obj/item/circuit_component/mod_program/camera/input_received(datum/port/input/port)
|
||||
var/atom/target = picture_target.value
|
||||
if(!target)
|
||||
var/turf/our_turf = get_location()
|
||||
target = locate(our_turf.x, our_turf.y, our_turf.z)
|
||||
if(!target)
|
||||
return
|
||||
var/datum/computer_file/program/maintenance/camera/cam = associated_program
|
||||
if(!cam.internal_camera.can_target(target))
|
||||
return
|
||||
var/pic_size_x = cam.internal_camera.picture_size_x - 1
|
||||
var/pic_size_y = cam.internal_camera.picture_size_y - 1
|
||||
INVOKE_ASYNC(cam.internal_camera, TYPE_PROC_REF(/obj/item/camera, captureimage), target, null, pic_size_x, pic_size_y)
|
||||
|
||||
/obj/item/circuit_component/mod_program/camera/proc/on_image_captured(obj/item/camera/source, atom/target, mob/user)
|
||||
SIGNAL_HANDLER
|
||||
photographed.set_output(target)
|
||||
photo_taken.set_output(COMPONENT_SIGNAL)
|
||||
return TRUE
|
||||
|
||||
+14
-14
@@ -52,19 +52,19 @@
|
||||
/datum/computer_file/program/messenger/on_install()
|
||||
. = ..()
|
||||
RegisterSignal(computer, COMSIG_MODULAR_COMPUTER_FILE_STORE, PROC_REF(check_new_photo))
|
||||
RegisterSignal(computer, COMSIG_MODULAR_COMPUTER_FILE_DELETE, PROC_REF(check_photo_removed))
|
||||
RegisterSignal(computer, COMSIG_MODULAR_COMPUTER_FILE_DELETE, PROC_REF(check_image_removed))
|
||||
RegisterSignal(computer, COMSIG_MODULAR_PDA_IMPRINT_UPDATED, PROC_REF(on_imprint_added))
|
||||
RegisterSignal(computer, COMSIG_MODULAR_PDA_IMPRINT_RESET, PROC_REF(on_imprint_reset))
|
||||
|
||||
/datum/computer_file/program/messenger/proc/check_new_photo(sender, datum/computer_file/picture/storing_picture)
|
||||
/datum/computer_file/program/messenger/proc/check_new_photo(sender, datum/computer_file/image/storing_image)
|
||||
SIGNAL_HANDLER
|
||||
if(!istype(storing_picture))
|
||||
if(!istype(storing_image))
|
||||
return
|
||||
update_pictures_for_all()
|
||||
|
||||
/datum/computer_file/program/messenger/proc/check_photo_removed(sender, datum/computer_file/picture/photo_removed)
|
||||
/datum/computer_file/program/messenger/proc/check_image_removed(sender, datum/computer_file/image/image_removed)
|
||||
SIGNAL_HANDLER
|
||||
if(istype(photo_removed) && selected_image == photo_removed.picture_name)
|
||||
if(istype(image_removed) && selected_image == image_removed.image_name)
|
||||
selected_image = null
|
||||
|
||||
/datum/computer_file/program/messenger/proc/on_imprint_added(sender)
|
||||
@@ -109,12 +109,12 @@
|
||||
/datum/computer_file/program/messenger/proc/can_send_everyone_message()
|
||||
return COOLDOWN_FINISHED(src, last_text) && COOLDOWN_FINISHED(src, last_text_everyone)
|
||||
|
||||
/// Gets all currently relevant photo asset keys
|
||||
/// Gets all currently relevant image asset keys
|
||||
/datum/computer_file/program/messenger/proc/get_picture_assets()
|
||||
var/list/data = list()
|
||||
|
||||
for(var/datum/computer_file/picture/photo in computer.stored_files)
|
||||
data |= photo.picture_name
|
||||
for(var/datum/computer_file/image/image_file in computer.stored_files)
|
||||
data |= image_file.image_name
|
||||
|
||||
if(viewing_messages_of in saved_chats)
|
||||
var/datum/pda_chat/chat = LAZYACCESS(saved_chats, viewing_messages_of)
|
||||
@@ -309,12 +309,12 @@
|
||||
|
||||
var/photo_uid = text2num(params["uid"])
|
||||
|
||||
var/datum/computer_file/picture/selected_photo = computer.find_file_by_uid(photo_uid)
|
||||
var/datum/computer_file/image/selected_image_file = computer.find_file_by_uid(photo_uid)
|
||||
|
||||
if(!istype(selected_photo))
|
||||
if(!istype(selected_image_file))
|
||||
return FALSE
|
||||
|
||||
selected_image = selected_photo.picture_name
|
||||
selected_image = selected_image_file.image_name
|
||||
return TRUE
|
||||
|
||||
if("PDA_siliconSelectPhoto")
|
||||
@@ -367,10 +367,10 @@
|
||||
// silicons handle selecting photos a bit differently for now
|
||||
if(!issilicon(user))
|
||||
var/list/stored_photos = list()
|
||||
for(var/datum/computer_file/picture/photo_file in computer.stored_files)
|
||||
for(var/datum/computer_file/image/image_file in computer.stored_files)
|
||||
stored_photos += list(list(
|
||||
"uid" = photo_file.uid,
|
||||
"path" = SSassets.transport.get_asset_url(photo_file.picture_name)
|
||||
"uid" = image_file.uid,
|
||||
"path" = SSassets.transport.get_asset_url(image_file.image_name)
|
||||
))
|
||||
data["stored_photos"] = stored_photos
|
||||
data["selected_photo_path"] = !isnull(selected_image) ? SSassets.transport.get_asset_url(selected_image) : null
|
||||
|
||||
@@ -0,0 +1,313 @@
|
||||
#define PALETTE_SIZE 32
|
||||
#define SANE_PHOTO_EDITING_SIZE_LIMIT 96 // I really don't think the server can handle someone editing large images, but a photo taken with the default camera dimensions shouldn't be too awful.
|
||||
|
||||
GLOBAL_LIST_INIT(nanopaint_supported_filetypes, zebra_typecacheof(list(\
|
||||
/datum/computer_file/data/paint_project = /datum/computer_file/data/paint_project,\
|
||||
/datum/computer_file/image = /datum/computer_file/image,\
|
||||
)))
|
||||
|
||||
/datum/computer_file/program/nanopaint
|
||||
filename = "nanopaint"
|
||||
filedesc = "NanoPaint"
|
||||
downloader_category = PROGRAM_CATEGORY_DEVICE
|
||||
program_open_overlay = "generic"
|
||||
extended_desc = "Draw pictures on your device."
|
||||
tgui_id = "NtosNanopaint"
|
||||
program_icon = "paintbrush"
|
||||
size = 5
|
||||
can_run_on_flags = PROGRAM_ALL
|
||||
/// A weak reference to the data file containing the workspace currently being worked on.
|
||||
var/datum/weakref/backing_file
|
||||
/// The name of the file that was opened, in case we are trying to save a file that is no longer accessible.
|
||||
var/opened_file_name
|
||||
/// The typepath of the file that was opened, in case we are trying to save a file that is no longer accessible.
|
||||
var/datum/computer_file/opened_file_type
|
||||
var/datum/sprite_editor_workspace/current_workspace
|
||||
/// If the opened file is an unmodified photo or painting, this is a reference to it.
|
||||
var/source_photo_or_painting
|
||||
/// If we have modified this project, store whatever unmodified photo or painting we were made from here.
|
||||
var/source_on_undo_all
|
||||
/// The current color we are painting with
|
||||
var/current_color = "#ffffffff"
|
||||
/// A list of colors we have quick access to
|
||||
var/list/palette = list()
|
||||
/// UI data for a modal dialog to display
|
||||
var/list/dialog
|
||||
|
||||
/datum/computer_file/program/nanopaint/ui_static_data(mob/user)
|
||||
return list(
|
||||
"templateSizes" = GLOB.canvas_dimensions,
|
||||
"saveableTypes" = list(
|
||||
list(
|
||||
"displayText" = "NanoPaint Project (.[/datum/computer_file/data/paint_project::filetype])",
|
||||
"typepath" = /datum/computer_file/data/paint_project,
|
||||
"extension" = /datum/computer_file/data/paint_project::filetype,
|
||||
),
|
||||
list(
|
||||
"displayText" = "PNG Image (.[/datum/computer_file/image::filetype])",
|
||||
"typepath" = /datum/computer_file/image,
|
||||
"extension" = /datum/computer_file/image::filetype,
|
||||
),
|
||||
),
|
||||
"minSize" = 1,
|
||||
"maxSize" = SANE_PHOTO_EDITING_SIZE_LIMIT,
|
||||
)
|
||||
|
||||
/datum/computer_file/program/nanopaint/ui_data(mob/user)
|
||||
var/list/data = list()
|
||||
data["dialog"] = dialog
|
||||
var/list/editor_data = list()
|
||||
editor_data["serverSelectedColor"] = current_color
|
||||
editor_data["serverPalette"] = palette
|
||||
editor_data["maxServerColors"] = PALETTE_SIZE
|
||||
editor_data["onSelectServerColor"] = "onSelectColor"
|
||||
editor_data["onAddServerColor"] = "onAddPaletteColor"
|
||||
editor_data["onRemoveServerColor"] = "onRemovePaletteColor"
|
||||
if(current_workspace)
|
||||
editor_data += current_workspace.sprite_editor_ui_data()
|
||||
data["editorData"] = editor_data
|
||||
data["workspaceOpen"] = !!current_workspace
|
||||
data["diskInserted"] = !!computer.inserted_disk
|
||||
var/list/all_files = computer.get_files(TRUE)
|
||||
var/list/drive_files = list()
|
||||
var/list/disk_files = list()
|
||||
for(var/datum/computer_file/file as anything in all_files)
|
||||
var/base_supported_type = is_type_in_typecache(file, GLOB.nanopaint_supported_filetypes)
|
||||
if(!base_supported_type)
|
||||
continue
|
||||
var/list/file_data = list("name" = file.filename, "extension" = file.filetype, "uid" = file.uid, "baseType" = base_supported_type)
|
||||
if(file.computer)
|
||||
drive_files += list(file_data)
|
||||
else
|
||||
disk_files += list(file_data)
|
||||
data["driveFiles"] = drive_files
|
||||
data["diskFiles"] = disk_files
|
||||
return data
|
||||
|
||||
/datum/computer_file/program/nanopaint/proc/check_dialog(act, modal_type)
|
||||
return dialog && dialog["type"] == modal_type && (!act || dialog["action"] == act)
|
||||
|
||||
/datum/computer_file/program/nanopaint/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
|
||||
. = ..()
|
||||
var/mob/user = ui.user
|
||||
switch(action)
|
||||
if("spriteEditorCommand")
|
||||
if(!current_workspace)
|
||||
return
|
||||
var/command = params["command"]
|
||||
switch(command)
|
||||
if("transaction")
|
||||
current_workspace.new_transaction(params["transaction"])
|
||||
if(!source_on_undo_all && source_photo_or_painting)
|
||||
source_on_undo_all = source_photo_or_painting
|
||||
source_photo_or_painting = null
|
||||
if("toggleVisible")
|
||||
current_workspace.toggle_layer_visible(params["layer"])
|
||||
if("undo")
|
||||
current_workspace.undo()
|
||||
if(!length(current_workspace.undo_stack))
|
||||
source_photo_or_painting = source_on_undo_all
|
||||
source_on_undo_all = null
|
||||
if("redo")
|
||||
current_workspace.redo()
|
||||
if(!source_on_undo_all && source_photo_or_painting)
|
||||
source_on_undo_all = source_photo_or_painting
|
||||
source_photo_or_painting = null
|
||||
return TRUE
|
||||
if("onSelectColor")
|
||||
current_color = params["color"]
|
||||
return TRUE
|
||||
if("onAddPaletteColor")
|
||||
if(length(palette) >= PALETTE_SIZE)
|
||||
return
|
||||
palette += params["color"]
|
||||
if("onRemovePaletteColor")
|
||||
var/index = params["index"]
|
||||
palette.Cut(index, index+1)
|
||||
return TRUE
|
||||
if("closeDialog")
|
||||
dialog = null
|
||||
return TRUE
|
||||
if("newDialog")
|
||||
dialog = list("type" = "new")
|
||||
return TRUE
|
||||
if("new")
|
||||
if(!check_dialog(null, "new"))
|
||||
return
|
||||
var/width = params["width"]
|
||||
if(!ISINRANGE(width, 1, SANE_PHOTO_EDITING_SIZE_LIMIT))
|
||||
return
|
||||
var/height = params["height"]
|
||||
if(!ISINRANGE(height, 1, SANE_PHOTO_EDITING_SIZE_LIMIT))
|
||||
return
|
||||
dialog = null
|
||||
close_workspace()
|
||||
INVOKE_ASYNC(src, PROC_REF(new_workspace), width, height)
|
||||
return TRUE
|
||||
if("openDialog")
|
||||
dialog = list("type" = "select", "title" = "Open File", "confirmText" = "Open", "action" = "open")
|
||||
return TRUE
|
||||
if("open")
|
||||
if(!check_dialog("open", "select"))
|
||||
return
|
||||
dialog = null
|
||||
INVOKE_ASYNC(src, PROC_REF(open_file), user, params["uid"], params["onDisk"], params["name"], text2path(params["type"]))
|
||||
return TRUE
|
||||
if("save")
|
||||
var/datum/computer_file/actual_file = backing_file?.resolve()
|
||||
if(!actual_file)
|
||||
if(!opened_file_name)
|
||||
dialog = list("type" = "select", "title" = "Save As", "confirmText" = "Save", "action" = "saveAs")
|
||||
return TRUE
|
||||
actual_file = computer.find_file_by_full_name("[opened_file_name].[opened_file_type::filetype]")
|
||||
if(actual_file && actual_file.computer != computer && actual_file.disk_host != computer.inserted_disk)
|
||||
actual_file = null
|
||||
if(actual_file)
|
||||
INVOKE_ASYNC(src, PROC_REF(write_to_file), user, actual_file, actual_file.disk_host)
|
||||
else
|
||||
INVOKE_ASYNC(src, PROC_REF(save_file), user, opened_file_name, opened_file_type)
|
||||
return TRUE
|
||||
if("saveAsDialog")
|
||||
dialog = list("type" = "select", "title" = "Save As", "confirmText" = "Save", "action" = "saveAs")
|
||||
return TRUE
|
||||
if("saveAs", "overwrite")
|
||||
if(!check_dialog(action, action == "saveAs" ? "select" : "confirm"))
|
||||
return
|
||||
dialog = null
|
||||
var/uid = params["uid"]
|
||||
var/new_file_name = params["name"]
|
||||
var/saving_to_disk = params["onDisk"]
|
||||
var/datum/computer_file/new_file_type = text2path(params["typepath"])
|
||||
var/extension = new_file_type::filetype
|
||||
var/datum/computer_file/existing_file
|
||||
if(saving_to_disk)
|
||||
if(!computer.inserted_disk)
|
||||
dialog = list("type" = "error", "message" = "[new_file_name] - The disk has been removed.")
|
||||
return TRUE
|
||||
if(uid)
|
||||
existing_file = computer.find_file_by_uid(uid, computer.inserted_disk)
|
||||
else
|
||||
existing_file = computer.find_file_by_full_name("[new_file_name].[extension]", computer.inserted_disk)
|
||||
else
|
||||
if(uid)
|
||||
existing_file = computer.find_file_by_uid(uid)
|
||||
else
|
||||
existing_file = computer.find_file_by_full_name("[new_file_name].[extension]")
|
||||
if(existing_file)
|
||||
if(action == "saveAs")
|
||||
dialog = list(
|
||||
"type" = "confirm",
|
||||
"title" = "Confirm Save As",
|
||||
"message" = "[new_file_name] already exists. Do you want to overwrite this file?",
|
||||
"action" = "overwrite",
|
||||
"params" = list("uid" = uid,
|
||||
"name" = new_file_name,
|
||||
"onDisk" = saving_to_disk,
|
||||
"typepath" = new_file_type),
|
||||
)
|
||||
else
|
||||
INVOKE_ASYNC(src, PROC_REF(write_to_file), user, existing_file)
|
||||
return TRUE
|
||||
INVOKE_ASYNC(src, PROC_REF(save_file), user, new_file_name, new_file_type, saving_to_disk && computer.inserted_disk)
|
||||
return TRUE
|
||||
|
||||
/datum/computer_file/program/nanopaint/proc/new_workspace(width, height)
|
||||
current_workspace = new(width, height)
|
||||
|
||||
/datum/computer_file/program/nanopaint/proc/open_file(mob/user, uid, on_disk, file_name, datum/computer_file/file_type)
|
||||
var/datum/computer_file/file_being_opened
|
||||
var/full_file_name = file_name + file_type::filetype
|
||||
if(on_disk)
|
||||
if(!computer.inserted_disk)
|
||||
dialog = list("type" = "error", "message" = "[full_file_name] - The disk has been removed.")
|
||||
return
|
||||
if(uid)
|
||||
file_being_opened = computer.find_file_by_uid(uid, computer.inserted_disk)
|
||||
else
|
||||
file_being_opened = computer.find_file_by_full_name(full_file_name, computer.inserted_disk)
|
||||
else
|
||||
if(uid)
|
||||
file_being_opened = computer.find_file_by_uid(uid)
|
||||
else
|
||||
file_being_opened = computer.find_file_by_full_name(full_file_name)
|
||||
if(!file_being_opened)
|
||||
dialog = list("type" = "error", "message" = "[full_file_name] - The selected file could not be found")
|
||||
return
|
||||
var/base_supported_type = is_type_in_typecache(file_being_opened, GLOB.nanopaint_supported_filetypes)
|
||||
if(!base_supported_type)
|
||||
dialog = list("type" = "error", "message" = "[full_file_name] - Unsupported format")
|
||||
return
|
||||
close_workspace()
|
||||
switch(base_supported_type)
|
||||
if(/datum/computer_file/data/paint_project)
|
||||
var/datum/computer_file/data/paint_project/project_file = file_being_opened
|
||||
current_workspace = project_file.workspace.copy()
|
||||
backing_file = WEAKREF(file_being_opened)
|
||||
opened_file_name = project_file.filename
|
||||
source_photo_or_painting = project_file.source_photo_or_painting
|
||||
if(/datum/computer_file/image)
|
||||
var/datum/computer_file/image/image_file = file_being_opened
|
||||
var/icon/image = image_file.stored_icon
|
||||
var/image_width = image.Width()
|
||||
var/image_height = image.Height()
|
||||
if(image_width <= 0 || image_height <= 0)
|
||||
dialog = list("type" = "error", "message" = "[file_name] - Invalid dimensions")
|
||||
return
|
||||
if(image_width > SANE_PHOTO_EDITING_SIZE_LIMIT || image_height > SANE_PHOTO_EDITING_SIZE_LIMIT)
|
||||
dialog = list("type" = "error", "message" = "[file_name] - Too large")
|
||||
return
|
||||
current_workspace = new(image_width, image_height)
|
||||
fill_grid_from_icon(current_workspace.get_first_layer_pixel_data(), image)
|
||||
source_photo_or_painting = image_file.source_photo_or_painting
|
||||
opened_file_type = base_supported_type
|
||||
|
||||
/datum/computer_file/program/nanopaint/proc/write_to_file(mob/user, datum/computer_file/file)
|
||||
switch(file.type)
|
||||
if(/datum/computer_file/data/paint_project)
|
||||
var/datum/computer_file/data/paint_project/project_file = file
|
||||
project_file.workspace = current_workspace.copy()
|
||||
project_file.set_source(source_photo_or_painting)
|
||||
backing_file = WEAKREF(project_file)
|
||||
if(/datum/computer_file/image)
|
||||
var/datum/computer_file/image/image_file = file
|
||||
image_file.stored_icon = current_workspace.to_icon()
|
||||
image_file.image_name = null
|
||||
image_file.assign_path()
|
||||
image_file.ref_appearance = null
|
||||
image_file.assign_ref_appearance()
|
||||
image_file.set_source(source_photo_or_painting)
|
||||
if(!source_photo_or_painting)
|
||||
image_file.author_ckey = user.ckey
|
||||
message_admins("[ADMIN_LOOKUP(user)] has saved a custom image to [computer] as [file.filename].[file.filetype].")
|
||||
log_player_image_creation("[key_name(user)] has saved a custom image to [computer] as [file.filename].[file.filetype]", user, image_file.stored_icon)
|
||||
|
||||
/datum/computer_file/program/nanopaint/proc/save_file(mob/user, name, file_type, obj/item/disk/computer/target_disk)
|
||||
var/datum/computer_file/file = new file_type()
|
||||
file.filename = reject_bad_name(name, allow_numbers = TRUE, cap_after_symbols = FALSE, cap_at_start = FALSE)
|
||||
var/file_stored
|
||||
if(target_disk)
|
||||
file_stored = target_disk.add_file(file)
|
||||
else
|
||||
file_stored = computer.store_file(file)
|
||||
if(file_stored)
|
||||
write_to_file(user, file)
|
||||
else
|
||||
dialog = list("type" = "error", "message" = "[name] - Unable to save file")
|
||||
SStgui.update_uis(computer)
|
||||
|
||||
/datum/computer_file/program/nanopaint/proc/close_workspace()
|
||||
backing_file = null
|
||||
opened_file_name = null
|
||||
opened_file_type = null
|
||||
current_workspace = null
|
||||
source_photo_or_painting = null
|
||||
source_on_undo_all = null
|
||||
palette = list()
|
||||
current_color = "#ffffffff"
|
||||
|
||||
/datum/computer_file/program/nanopaint/kill_program(mob/user)
|
||||
close_workspace()
|
||||
return ..()
|
||||
|
||||
#undef SANE_PHOTO_EDITING_SIZE_LIMIT
|
||||
#undef PALETTE_SIZE
|
||||
@@ -1,8 +1,3 @@
|
||||
|
||||
///how much paper it takes from the printer to create a canvas.
|
||||
#define CANVAS_PAPER_COST 10
|
||||
|
||||
|
||||
/**
|
||||
* ## the art gallery viewer/printer!
|
||||
*
|
||||
@@ -57,8 +52,10 @@
|
||||
search_mode = search_mode == PAINTINGS_FILTER_SEARCH_TITLE ? PAINTINGS_FILTER_SEARCH_CREATOR : PAINTINGS_FILTER_SEARCH_TITLE
|
||||
generate_matching_paintings_list()
|
||||
. = TRUE
|
||||
if("select")
|
||||
if("print")
|
||||
print_painting(params["selected"])
|
||||
if("download")
|
||||
download_painting(params["selected"])
|
||||
|
||||
/datum/computer_file/program/portrait_printer/proc/generate_matching_paintings_list()
|
||||
matching_paintings = null
|
||||
@@ -72,34 +69,23 @@
|
||||
if(computer.stored_paper < CANVAS_PAPER_COST)
|
||||
to_chat(usr, span_notice("Printing error: Your printer needs at least [CANVAS_PAPER_COST] paper to print a canvas."))
|
||||
return
|
||||
computer.stored_paper -= CANVAS_PAPER_COST
|
||||
|
||||
//canvas printing!
|
||||
var/datum/painting/chosen_portrait = locate(selected_painting) in SSpersistent_paintings.paintings
|
||||
|
||||
var/png = "data/paintings/images/[chosen_portrait.md5].png"
|
||||
var/icon/art_icon = new(png)
|
||||
var/obj/item/canvas/printed_canvas
|
||||
var/art_width = art_icon.Width()
|
||||
var/art_height = art_icon.Height()
|
||||
for(var/canvas_type in typesof(/obj/item/canvas))
|
||||
printed_canvas = canvas_type
|
||||
if(initial(printed_canvas.width) == art_width && initial(printed_canvas.height) == art_height)
|
||||
printed_canvas = new canvas_type(get_turf(computer.physical))
|
||||
break
|
||||
printed_canvas = null
|
||||
if(!printed_canvas)
|
||||
var/obj/item/canvas/new_canvas = chosen_portrait.spawn_canvas(get_turf(computer.physical))
|
||||
if(!new_canvas)
|
||||
to_chat(usr, span_notice("Printing error: An unknown error has occurred."))
|
||||
return
|
||||
printed_canvas.painting_metadata = chosen_portrait
|
||||
printed_canvas.fill_grid_from_icon(art_icon)
|
||||
printed_canvas.generated_icon = art_icon
|
||||
printed_canvas.icon_generated = TRUE
|
||||
printed_canvas.finalized = TRUE
|
||||
printed_canvas.name = "painting - [chosen_portrait.title]"
|
||||
///this is a copy of something that is already in the database- it should not be able to be saved.
|
||||
printed_canvas.no_save = TRUE
|
||||
printed_canvas.update_icon()
|
||||
computer.stored_paper -= CANVAS_PAPER_COST
|
||||
to_chat(usr, span_notice("You have printed [chosen_portrait.title] onto a new canvas."))
|
||||
playsound(computer.physical, 'sound/items/poster/poster_being_created.ogg', 100, TRUE)
|
||||
playsound(computer.physical, 'sound/machines/printer.ogg', 100, TRUE)
|
||||
|
||||
#undef CANVAS_PAPER_COST
|
||||
/datum/computer_file/program/portrait_printer/proc/download_painting(selected_painting)
|
||||
var/datum/painting/chosen_portrait = locate(selected_painting) in SSpersistent_paintings.paintings
|
||||
var/icon/portrait_icon = chosen_portrait.get_icon()
|
||||
var/datum/computer_file/image/image_file = new(portrait_icon, display_name = chosen_portrait.title, source_photo_or_painting = chosen_portrait)
|
||||
if(!computer.store_file(image_file, usr))
|
||||
to_chat(usr, span_notice("Unable to download [chosen_portrait.title].[/datum/computer_file/image::filetype]."))
|
||||
return
|
||||
to_chat(usr, span_notice("Downloaded [chosen_portrait.title].[/datum/computer_file/image::filetype]."))
|
||||
|
||||
@@ -61,3 +61,22 @@
|
||||
|
||||
/datum/computer_file/program/raptordex/ui_data(mob/user)
|
||||
return scan_data
|
||||
|
||||
/datum/computer_file/program/raptordex/on_made_active_program(mob/user)
|
||||
RegisterSignal(computer, COMSIG_ITEM_REQUESTING_CONTEXT_FOR_TARGET, PROC_REF(add_item_context))
|
||||
computer.item_flags |= ITEM_HAS_CONTEXTUAL_SCREENTIPS
|
||||
|
||||
/datum/computer_file/program/raptordex/background_program(mob/user)
|
||||
. = ..()
|
||||
UnregisterSignal(computer, COMSIG_ITEM_REQUESTING_CONTEXT_FOR_TARGET)
|
||||
|
||||
/datum/computer_file/program/raptordex/kill_program(mob/user)
|
||||
. = ..()
|
||||
UnregisterSignal(computer, COMSIG_ITEM_REQUESTING_CONTEXT_FOR_TARGET)
|
||||
|
||||
/datum/computer_file/program/raptordex/proc/add_item_context(obj/item/source, list/context, atom/target, mob/living/user)
|
||||
SIGNAL_HANDLER
|
||||
if(!istype(target, /mob/living/basic/raptor))
|
||||
return NONE
|
||||
context[SCREENTIP_CONTEXT_RMB] = "Scan Raptor"
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
|
||||
@@ -172,7 +172,7 @@
|
||||
var/datum/camerachunk/target_camerachunk = SScameras.get_turf_camera_chunk(target_turf)
|
||||
if(!target_camerachunk)
|
||||
CRASH("[src] was able to track [target] through /datum/trackable, but was not on a visible turf to cameras.")
|
||||
for(var/obj/machinery/camera/cameras as anything in target_camerachunk.cameras[target.z])
|
||||
for(var/obj/machinery/camera/cameras as anything in target_camerachunk.cameras["[target.z]"])
|
||||
// We need to find a particular camera that can see this turf
|
||||
if(length(cameras.can_see() & list(target_turf)))
|
||||
continue
|
||||
|
||||
@@ -195,7 +195,7 @@ GLOBAL_LIST_EMPTY(virtual_pets_list)
|
||||
|
||||
if(isnull(photo))
|
||||
return
|
||||
computer.store_file(new /datum/computer_file/picture(photo))
|
||||
computer.store_file(new /datum/computer_file/image(photo.picture_image, display_name = photo.picture_name))
|
||||
|
||||
/datum/computer_file/program/virtual_pet/proc/set_hat_offsets(new_dir)
|
||||
var/direction_text = dir2text(new_dir)
|
||||
@@ -330,7 +330,7 @@ GLOBAL_LIST_EMPTY(virtual_pets_list)
|
||||
var/datum/action/cooldown/mob_cooldown/capture_photo/photo_ability = new(pet)
|
||||
photo_ability.Grant(pet)
|
||||
pet.ai_controller?.set_blackboard_key(BB_PHOTO_ABILITY, photo_ability)
|
||||
RegisterSignal(photo_ability.ability_camera, COMSIG_CAMERA_IMAGE_CAPTURED, PROC_REF(on_photo_captured))
|
||||
RegisterSignal(photo_ability.internal_camera, COMSIG_CAMERA_IMAGE_CAPTURED, PROC_REF(on_photo_captured))
|
||||
|
||||
/datum/computer_file/program/virtual_pet/proc/announce_global_updates(message)
|
||||
if(isnull(message))
|
||||
|
||||
Reference in New Issue
Block a user