Merge branch 'master' into metachanges
@@ -202,6 +202,3 @@ tools/MapAtmosFixer/MapAtmosFixer/bin/*
|
||||
|
||||
#Jukebox audio files
|
||||
/config/jukebox_music/**/*
|
||||
_maps/map_files/nanostation/nanostation.dmm
|
||||
_maps/nanostation.dm
|
||||
_maps/nanotstation.json
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE
|
||||
"a" = (
|
||||
/turf/template_noop,
|
||||
/area/lavaland/surface/outdoors)
|
||||
"b" = (
|
||||
/obj/effect/sliding_puzzle/lavaland,
|
||||
/turf/open/floor/plating/asteroid/basalt/lava_land_surface,
|
||||
/area/lavaland/surface/outdoors)
|
||||
"c" = (
|
||||
/turf/open/floor/plating/asteroid/basalt/lava_land_surface,
|
||||
/area/lavaland/surface/outdoors)
|
||||
|
||||
(1,1,1) = {"
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
"}
|
||||
(2,1,1) = {"
|
||||
a
|
||||
c
|
||||
c
|
||||
c
|
||||
a
|
||||
"}
|
||||
(3,1,1) = {"
|
||||
a
|
||||
c
|
||||
b
|
||||
c
|
||||
a
|
||||
"}
|
||||
(4,1,1) = {"
|
||||
a
|
||||
c
|
||||
c
|
||||
c
|
||||
a
|
||||
"}
|
||||
(5,1,1) = {"
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
a
|
||||
"}
|
||||
@@ -70,6 +70,7 @@
|
||||
#define ADMIN_PUNISHMENT_FIREBALL "Fireball"
|
||||
#define ADMIN_PUNISHMENT_ROD "Immovable Rod"
|
||||
#define ADMIN_PUNISHMENT_SUPPLYPOD "Supply Pod"
|
||||
#define ADMIN_PUNISHMENT_MAZING "Puzzle"
|
||||
|
||||
#define AHELP_ACTIVE 1
|
||||
#define AHELP_CLOSED 2
|
||||
|
||||
@@ -23,6 +23,8 @@ Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a s
|
||||
//define THIS_PROC_TYPE_WEIRD_STR "[THIS_PROC_TYPE_WEIRD]" //Included for completeness
|
||||
//define THIS_PROC_TYPE_WEIRD_STR_WITH_ARGS "[THIS_PROC_TYPE_WEIRD]([args.Join(",")])" //Ditto
|
||||
|
||||
#define NOT_IMPLEMENTED "NOT_IMPLEMENTED"
|
||||
|
||||
#define MIDNIGHT_ROLLOVER 864000 //number of deciseconds in a day
|
||||
|
||||
#define JANUARY 1
|
||||
@@ -452,8 +454,13 @@ GLOBAL_LIST_INIT(pda_styles, list(MONO, VT, ORBITRON, SHARE))
|
||||
#define PDAIMG(what) {"<span class="pda16x16 [#what]"></span>"}
|
||||
|
||||
//Filters
|
||||
#define AMBIENT_OCCLUSION filter(type="drop_shadow", x=0, y=-2, size=4, border=4, color="#04080FAA")
|
||||
|
||||
#define AMBIENT_OCCLUSION list("type"="drop_shadow","x"=0,"y"=-2,"size"=4,"border"=4,"color"="#04080FAA")
|
||||
#define EYE_BLUR list("type"="blur", "size"=3)
|
||||
#define GRAVITY_MOTION_BLUR list("type"="motion_blur","x"=0,"y"=0)
|
||||
|
||||
#define STANDARD_GRAVITY 1 //Anything above this is high gravity, anything below no grav
|
||||
#define GRAVITY_DAMAGE_TRESHOLD 3 //Starting with this value gravity will start to damage mobs
|
||||
#define GRAVITY_DAMAGE_TRESHOLD 3 //Starting with this value gravity will start to damage mobs
|
||||
|
||||
#define CAMERA_NO_GHOSTS 0
|
||||
#define CAMERA_SEE_GHOSTS_BASIC 1
|
||||
#define CAMERA_SEE_GHOSTS_ORBIT 2
|
||||
|
||||
@@ -931,15 +931,6 @@ world
|
||||
flat_icon.AddAlphaMask(alpha_mask)//Finally, let's mix in a distortion effect.
|
||||
return flat_icon
|
||||
|
||||
//For photo camera.
|
||||
/proc/build_composite_icon(atom/A)
|
||||
var/icon/composite = icon(A.icon, A.icon_state, A.dir, 1)
|
||||
for(var/O in A.overlays)
|
||||
var/image/I = O
|
||||
composite.Blend(icon(I.icon, I.icon_state, I.dir, 1), ICON_OVERLAY)
|
||||
return composite
|
||||
|
||||
|
||||
//What the mob looks like as animated static
|
||||
//By vg's ComicIronic
|
||||
/proc/getStaticIcon(icon/A, safety = TRUE)
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
announcement += "<h1 class='alert'>[sender_override]</h1>"
|
||||
if (title && length(title) > 0)
|
||||
announcement += "<br><h2 class='alert'>[html_encode(title)]</h2>"
|
||||
|
||||
|
||||
if(!sender_override)
|
||||
if(title == "")
|
||||
GLOB.news_network.SubmitArticle(text, "Central Command Update", "Station Announcements", null)
|
||||
@@ -46,7 +46,7 @@
|
||||
var/datum/comm_message/M = new
|
||||
M.title = title
|
||||
M.content = text
|
||||
|
||||
|
||||
SScommunications.send_message(M)
|
||||
|
||||
/proc/minor_announce(message, title = "Attention:", alert)
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
#define QDEL_IN(item, time) addtimer(CALLBACK(GLOBAL_PROC, .proc/qdel, item), time, TIMER_STOPPABLE)
|
||||
#define QDEL_IN_CLIENT_TIME(item, time) addtimer(CALLBACK(GLOBAL_PROC, .proc/qdel, item), time, TIMER_STOPPABLE | TIMER_CLIENT_TIME)
|
||||
#define QDEL_NULL(item) qdel(item); item = null
|
||||
#define QDEL_LIST(L) if(L) { for(var/I in L) qdel(I); L.Cut(); }
|
||||
#define QDEL_LIST_IN(L, time) addtimer(CALLBACK(GLOBAL_PROC, .proc/______qdel_list_wrapper, L), time, TIMER_STOPPABLE)
|
||||
#define QDEL_LIST_ASSOC(L) if(L) { for(var/I in L) { qdel(L[I]); qdel(I); } L.Cut(); }
|
||||
#define QDEL_LIST_ASSOC_VAL(L) if(L) { for(var/I in L) qdel(L[I]); L.Cut(); }
|
||||
|
||||
/proc/______qdel_list_wrapper(list/L) //the underscores are to encourage people not to use this directly.
|
||||
QDEL_LIST(L)
|
||||
@@ -1293,19 +1293,6 @@ GLOBAL_REAL_VAR(list/stack_trace_storage)
|
||||
|
||||
#define RANDOM_COLOUR (rgb(rand(0,255),rand(0,255),rand(0,255)))
|
||||
|
||||
#define QDEL_IN(item, time) addtimer(CALLBACK(GLOBAL_PROC, .proc/qdel, item), time, TIMER_STOPPABLE)
|
||||
#define QDEL_IN_CLIENT_TIME(item, time) addtimer(CALLBACK(GLOBAL_PROC, .proc/qdel, item), time, TIMER_STOPPABLE | TIMER_CLIENT_TIME)
|
||||
#define QDEL_NULL(item) qdel(item); item = null
|
||||
#define QDEL_LIST(L) if(L) { for(var/I in L) qdel(I); L.Cut(); }
|
||||
#define QDEL_LIST_IN(L, time) addtimer(CALLBACK(GLOBAL_PROC, .proc/______qdel_list_wrapper, L), time, TIMER_STOPPABLE)
|
||||
#define QDEL_LIST_ASSOC(L) if(L) { for(var/I in L) { qdel(L[I]); qdel(I); } L.Cut(); }
|
||||
#define QDEL_LIST_ASSOC_VAL(L) if(L) { for(var/I in L) qdel(L[I]); L.Cut(); }
|
||||
|
||||
/proc/______qdel_list_wrapper(list/L) //the underscores are to encourage people not to use this directly.
|
||||
QDEL_LIST(L)
|
||||
|
||||
|
||||
|
||||
/proc/random_nukecode()
|
||||
var/val = rand(0, 99999)
|
||||
var/str = "[val]"
|
||||
|
||||
@@ -44,3 +44,13 @@ GLOBAL_LIST_EMPTY(adminlog)
|
||||
GLOBAL_PROTECT(adminlog)
|
||||
|
||||
GLOBAL_LIST_EMPTY(active_turfs_startlist)
|
||||
|
||||
/////Picture logging
|
||||
GLOBAL_VAR(picture_log_directory)
|
||||
GLOBAL_PROTECT(picture_log_directory)
|
||||
|
||||
GLOBAL_VAR_INIT(picture_logging_id, 1)
|
||||
GLOBAL_PROTECT(picture_logging_id)
|
||||
GLOBAL_VAR(picture_logging_prefix)
|
||||
GLOBAL_PROTECT(picture_logging_prefix)
|
||||
/////
|
||||
|
||||
@@ -72,6 +72,9 @@
|
||||
if(check_click_intercept(params,A))
|
||||
return
|
||||
|
||||
if(notransform)
|
||||
return
|
||||
|
||||
var/list/modifiers = params2list(params)
|
||||
if(modifiers["shift"] && modifiers["middle"])
|
||||
ShiftMiddleClickOn(A)
|
||||
|
||||
@@ -135,10 +135,10 @@
|
||||
return
|
||||
if(isAI(usr))
|
||||
var/mob/living/silicon/ai/AI = usr
|
||||
AI.aicamera.toggle_camera_mode()
|
||||
AI.aicamera.toggle_camera_mode(usr)
|
||||
else if(iscyborg(usr))
|
||||
var/mob/living/silicon/robot/R = usr
|
||||
R.aicamera.toggle_camera_mode()
|
||||
R.aicamera.toggle_camera_mode(usr)
|
||||
|
||||
/obj/screen/ai/image_view
|
||||
name = "View Images"
|
||||
@@ -149,10 +149,10 @@
|
||||
return
|
||||
if(isAI(usr))
|
||||
var/mob/living/silicon/ai/AI = usr
|
||||
AI.aicamera.viewpictures()
|
||||
AI.aicamera.viewpictures(usr)
|
||||
else if(iscyborg(usr))
|
||||
var/mob/living/silicon/robot/R = usr
|
||||
R.aicamera.viewpictures()
|
||||
R.aicamera.viewpictures(usr)
|
||||
|
||||
/obj/screen/ai/sensors
|
||||
name = "Sensor Augmentation"
|
||||
|
||||
@@ -123,11 +123,6 @@
|
||||
/obj/screen/fullscreen/impaired
|
||||
icon_state = "impairedoverlay"
|
||||
|
||||
/obj/screen/fullscreen/blurry
|
||||
icon = 'icons/mob/screen_gen.dmi'
|
||||
screen_loc = "WEST,SOUTH to EAST,NORTH"
|
||||
icon_state = "blurry"
|
||||
|
||||
/obj/screen/fullscreen/flash
|
||||
icon = 'icons/mob/screen_gen.dmi'
|
||||
screen_loc = "WEST,SOUTH to EAST,NORTH"
|
||||
|
||||
@@ -29,9 +29,11 @@
|
||||
blend_mode = BLEND_OVERLAY
|
||||
|
||||
/obj/screen/plane_master/game_world/backdrop(mob/mymob)
|
||||
filters = list()
|
||||
if(istype(mymob) && mymob.client && mymob.client.prefs && mymob.client.prefs.ambientocclusion)
|
||||
filters += AMBIENT_OCCLUSION
|
||||
add_filter("ambient_occlusion", 0, AMBIENT_OCCLUSION)
|
||||
else
|
||||
remove_filter("ambient_occlusion")
|
||||
update_filters()
|
||||
|
||||
/obj/screen/plane_master/lighting
|
||||
name = "lighting plane master"
|
||||
|
||||
@@ -410,3 +410,7 @@
|
||||
|
||||
/datum/config_entry/string/default_view
|
||||
config_entry_value = "15x15"
|
||||
|
||||
/datum/config_entry/flag/log_pictures
|
||||
|
||||
/datum/config_entry/flag/picture_logging_camera
|
||||
|
||||
@@ -23,7 +23,7 @@ SUBSYSTEM_DEF(npcpool)
|
||||
var/mob/living/simple_animal/SA = currentrun[currentrun.len]
|
||||
--currentrun.len
|
||||
|
||||
if(!SA.ckey)
|
||||
if(!SA.ckey && !SA.notransform)
|
||||
if(SA.stat != DEAD)
|
||||
SA.handle_automated_movement()
|
||||
if(SA.stat != DEAD)
|
||||
|
||||
@@ -9,7 +9,7 @@ SUBSYSTEM_DEF(pathfinder)
|
||||
/datum/controller/subsystem/pathfinder/Initialize()
|
||||
space_type_cache = typecacheof(/turf/open/space)
|
||||
mobs = new(10)
|
||||
circuits = new(3)
|
||||
circuits = new(3)
|
||||
return ..()
|
||||
|
||||
/datum/flowcache
|
||||
|
||||
@@ -15,6 +15,9 @@ SUBSYSTEM_DEF(persistence)
|
||||
var/list/spawned_objects = list()
|
||||
var/list/antag_rep = list()
|
||||
var/list/antag_rep_change = list()
|
||||
var/list/picture_logging_information = list()
|
||||
var/list/obj/structure/sign/picture_frame/photo_frames
|
||||
var/list/obj/item/storage/photo_album/photo_albums
|
||||
|
||||
/datum/controller/subsystem/persistence/Initialize()
|
||||
LoadSatchels()
|
||||
@@ -22,6 +25,7 @@ SUBSYSTEM_DEF(persistence)
|
||||
LoadChiselMessages()
|
||||
LoadTrophies()
|
||||
LoadRecentModes()
|
||||
LoadPhotoPersistence()
|
||||
if(CONFIG_GET(flag/use_antag_rep))
|
||||
LoadAntagReputation()
|
||||
..()
|
||||
@@ -194,15 +198,74 @@ SUBSYSTEM_DEF(persistence)
|
||||
T.placer_key = chosen_trophy["placer_key"]
|
||||
T.update_icon()
|
||||
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/CollectData()
|
||||
CollectChiselMessages()
|
||||
CollectSecretSatchels()
|
||||
CollectTrophies()
|
||||
CollectRoundtype()
|
||||
SavePhotoPersistence() //THIS IS PERSISTENCE, NOT THE LOGGING PORTION.
|
||||
if(CONFIG_GET(flag/use_antag_rep))
|
||||
CollectAntagReputation()
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/LoadPhotoPersistence()
|
||||
var/album_path = file("data/photo_albums.json")
|
||||
var/frame_path = file("data/photo_frames.json")
|
||||
if(fexists(album_path))
|
||||
var/list/json = json_decode(file2text(album_path))
|
||||
if(json.len)
|
||||
for(var/i in photo_albums)
|
||||
var/obj/item/storage/photo_album/A = i
|
||||
if(!A.persistence_id)
|
||||
continue
|
||||
if(json[A.persistence_id])
|
||||
A.populate_from_id_list(json[A.persistence_id])
|
||||
|
||||
if(fexists(frame_path))
|
||||
var/list/json = json_decode(file2text(frame_path))
|
||||
if(json.len)
|
||||
for(var/i in photo_frames)
|
||||
var/obj/structure/sign/picture_frame/PF = i
|
||||
if(!PF.persistence_id)
|
||||
continue
|
||||
if(json[PF.persistence_id])
|
||||
PF.load_from_id(json[PF.persistence_id])
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/SavePhotoPersistence()
|
||||
var/album_path = file("data/photo_albums.json")
|
||||
var/frame_path = file("data/photo_frames.json")
|
||||
|
||||
var/list/frame_json = list()
|
||||
var/list/album_json = list()
|
||||
|
||||
if(fexists(album_path))
|
||||
album_json = json_decode(file2text(album_path))
|
||||
fdel(album_path)
|
||||
|
||||
for(var/i in photo_albums)
|
||||
var/obj/item/storage/photo_album/A = i
|
||||
if(!istype(A) || !A.persistence_id)
|
||||
continue
|
||||
var/list/L = A.get_picture_id_list()
|
||||
album_json[A.persistence_id] = L
|
||||
|
||||
album_json = json_encode(album_json)
|
||||
|
||||
WRITE_FILE(album_path, album_json)
|
||||
|
||||
if(fexists(frame_path))
|
||||
frame_json = json_decode(file2text(frame_path))
|
||||
fdel(frame_path)
|
||||
|
||||
for(var/i in photo_frames)
|
||||
var/obj/structure/sign/picture_frame/F = i
|
||||
if(!istype(F) || !F.persistence_id)
|
||||
continue
|
||||
frame_json[F.persistence_id] = F.get_photo_id()
|
||||
|
||||
frame_json = json_encode(frame_json)
|
||||
|
||||
WRITE_FILE(frame_path, frame_json)
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/CollectSecretSatchels()
|
||||
satchel_blacklist = typecacheof(list(/obj/item/stack/tile/plasteel, /obj/item/crowbar))
|
||||
var/list/satchels_to_add = list()
|
||||
|
||||
@@ -214,13 +214,16 @@
|
||||
if(!C)
|
||||
C = H.client
|
||||
var/image = get_id_photo(H, C, show_directions)
|
||||
var/obj/item/photo/photo_front = new()
|
||||
var/obj/item/photo/photo_side = new()
|
||||
for(var/D in show_directions)
|
||||
if(D == SOUTH)
|
||||
photo_front.photocreate(null, icon(image, dir = D))
|
||||
if(D == WEST || D == EAST)
|
||||
photo_side.photocreate(null, icon(image, dir = D))
|
||||
var/datum/picture/pf = new
|
||||
var/datum/picture/ps = new
|
||||
pf.picture_name = "[H]"
|
||||
ps.picture_name = "[H]"
|
||||
pf.picture_desc = "This is [H]."
|
||||
ps.picture_desc = "This is [H]."
|
||||
pf.picture_image = icon(image, dir = SOUTH)
|
||||
ps.picture_image = icon(image, dir = WEST)
|
||||
var/obj/item/photo/photo_front = new(null, pf)
|
||||
var/obj/item/photo/photo_side = new(null, ps)
|
||||
|
||||
//These records should ~really~ be merged or something
|
||||
//General Record
|
||||
|
||||
@@ -83,3 +83,67 @@
|
||||
/datum/proc/to_chat_check_changed_vars(target = world)
|
||||
to_chat(target, txt_changed_vars())
|
||||
#endif
|
||||
|
||||
//Return a LIST for serialize_datum to encode! Not the actual json!
|
||||
/datum/proc/serialize_list(list/options)
|
||||
return NOT_IMPLEMENTED
|
||||
|
||||
//Accepts a LIST from deserialize_datum. Should return src or another datum.
|
||||
/datum/proc/deserialize_list(json, list/options)
|
||||
return NOT_IMPLEMENTED
|
||||
|
||||
//Serializes into JSON. Does not encode type.
|
||||
/datum/proc/serialize_json(list/options)
|
||||
. = serialize_list(options)
|
||||
if((. == NOT_IMPLEMENTED) || !islist(.))
|
||||
. = null
|
||||
else
|
||||
. = json_encode(.)
|
||||
|
||||
//Deserializes from JSON. Does not parse type.
|
||||
/datum/proc/deserialize_json(list/input, list/options)
|
||||
var/list/jsonlist = json_decode(input)
|
||||
. = deserialize_list(jsonlist)
|
||||
if(!istype(., /datum))
|
||||
. = null
|
||||
|
||||
/proc/json_serialize_datum(datum/D, list/options)
|
||||
if(!istype(D))
|
||||
return
|
||||
var/list/jsonlist = D.serialize_list(options)
|
||||
if(islist(jsonlist))
|
||||
jsonlist["DATUM_TYPE"] = D.type
|
||||
return json_encode(jsonlist)
|
||||
|
||||
/proc/json_deserialize_datum(list/jsonlist, list/options, target_type, strict_target_type = FALSE)
|
||||
if(!islist(jsonlist))
|
||||
if(!istext(jsonlist))
|
||||
CRASH("Invalid JSON")
|
||||
return
|
||||
jsonlist = json_decode(jsonlist)
|
||||
if(!islist(jsonlist))
|
||||
CRASH("Invalid JSON")
|
||||
return
|
||||
if(!jsonlist["DATUM_TYPE"])
|
||||
return
|
||||
if(!ispath(jsonlist["DATUM_TYPE"]))
|
||||
if(!istext(jsonlist["DATUM_TYPE"]))
|
||||
return
|
||||
jsonlist["DATUM_TYPE"] = text2path(jsonlist["DATUM_TYPE"])
|
||||
if(!ispath(jsonlist["DATUM_TYPE"]))
|
||||
return
|
||||
if(target_type)
|
||||
if(!ispath(target_type))
|
||||
return
|
||||
if(strict_target_type)
|
||||
if(target_type != jsonlist["DATUM_TYPE"])
|
||||
return
|
||||
else if(!ispath(jsonlist["DATUM_TYPE"], target_type))
|
||||
return
|
||||
var/typeofdatum = jsonlist["DATUM_TYPE"] //BYOND won't directly read if this is just put in the line below, and will instead runtime because it thinks you're trying to make a new list?
|
||||
var/datum/D = new typeofdatum
|
||||
var/datum/returned = D.deserialize_list(jsonlist, options)
|
||||
if(!istype(returned, /datum))
|
||||
qdel(D)
|
||||
else
|
||||
return returned
|
||||
@@ -34,8 +34,8 @@
|
||||
|
||||
D.apply_damage(damage, STAMINA, affecting, armor_block)
|
||||
add_logs(A, D, "punched (boxing) ")
|
||||
if(D.getStaminaLoss() > 50)
|
||||
var/knockout_prob = D.getStaminaLoss() + rand(-15,15)
|
||||
if(D.getStaminaLoss() > 100)
|
||||
var/knockout_prob = (D.getStaminaLoss() + rand(-15,15))*0.75
|
||||
if((D.stat != DEAD) && prob(knockout_prob))
|
||||
D.visible_message("<span class='danger'>[A] has knocked [D] out with a haymaker!</span>", \
|
||||
"<span class='userdanger'>[A] has knocked [D] out with a haymaker!</span>")
|
||||
|
||||
@@ -215,3 +215,10 @@
|
||||
suffix = "lavaland_surface_random_ripley.dmm"
|
||||
allow_duplicates = FALSE
|
||||
cost = 5
|
||||
|
||||
/datum/map_template/ruin/lavaland/puzzle
|
||||
name = "Ancient Puzzle"
|
||||
id = "puzzle"
|
||||
description = "Mystery to be solved."
|
||||
suffix = "lavaland_surface_puzzle.dmm"
|
||||
cost = 5
|
||||
@@ -126,7 +126,6 @@
|
||||
var/datum/supply_pack/P = SSshuttle.supply_packs[/datum/supply_pack/engineering/shuttle_engine]
|
||||
P.special_enabled = TRUE
|
||||
|
||||
|
||||
/datum/map_template/shuttle/emergency/asteroid
|
||||
suffix = "asteroid"
|
||||
name = "Asteroid Station Emergency Shuttle"
|
||||
@@ -229,7 +228,7 @@
|
||||
suffix = "scrapheap"
|
||||
name = "Standby Evacuation Vessel \"Scrapheap Challenge\""
|
||||
credit_cost = -1000
|
||||
description = "Due to a lack of functional emergency shuttles, we bought this second hand from a scrapyard and pressed it into service. Please do not lean to heavily on the exterior windows, they are fragile."
|
||||
description = "Due to a lack of functional emergency shuttles, we bought this second hand from a scrapyard and pressed it into service. Please do not lean to heavily on the exterior windows, they are fragile. <span class='danger'>VIRUS ALERT: This entry seems to be booby-trapped with a redirector trap. Buy this at your own risk.</span>"
|
||||
admin_notes = "An abomination with no functional medbay, sections missing, and some very fragile windows. Surprisingly airtight."
|
||||
|
||||
/datum/map_template/shuttle/emergency/narnar
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
var/mob/living/carbon/human/H = quirk_holder
|
||||
if(NOBLOOD in H.dna.species.species_traits) //can't lose blood if your species doesn't have any
|
||||
return
|
||||
else
|
||||
else
|
||||
quirk_holder.blood_volume -= 0.275
|
||||
|
||||
|
||||
|
||||
@@ -608,4 +608,10 @@
|
||||
|
||||
/atom/movable/proc/get_filter(name)
|
||||
if(filter_data && filter_data[name])
|
||||
return filters[filter_data.Find(name)]
|
||||
return filters[filter_data.Find(name)]
|
||||
|
||||
/atom/movable/proc/remove_filter(name)
|
||||
if(filter_data[name])
|
||||
filter_data -= name
|
||||
update_filters()
|
||||
return TRUE
|
||||
@@ -148,12 +148,12 @@
|
||||
|
||||
/datum/objective_item/steal/blueprints/check_special_completion(obj/item/I)
|
||||
if(istype(I, /obj/item/areaeditor/blueprints))
|
||||
return 1
|
||||
return TRUE
|
||||
if(istype(I, /obj/item/photo))
|
||||
var/obj/item/photo/P = I
|
||||
if(P.blueprints) //if the blueprints are in frame
|
||||
return 1
|
||||
return 0
|
||||
if(P.picture.has_blueprints) //if the blueprints are in frame
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/datum/objective_item/steal/slime
|
||||
name = "an unused sample of slime extract."
|
||||
|
||||
@@ -108,10 +108,10 @@
|
||||
if(active1 in GLOB.data_core.general)
|
||||
if(istype(active1.fields["photo_front"], /obj/item/photo))
|
||||
var/obj/item/photo/P1 = active1.fields["photo_front"]
|
||||
user << browse_rsc(P1.img, "photo_front")
|
||||
user << browse_rsc(P1.picture.picture_image, "photo_front")
|
||||
if(istype(active1.fields["photo_side"], /obj/item/photo))
|
||||
var/obj/item/photo/P2 = active1.fields["photo_side"]
|
||||
user << browse_rsc(P2.img, "photo_side")
|
||||
user << browse_rsc(P2.picture.picture_image, "photo_side")
|
||||
dat += "<tr><td>Name:</td><td>[active1.fields["name"]]</td>"
|
||||
dat += "<td><a href='?src=[REF(src)];field=show_photo_front'><img src=photo_front height=80 width=80 border=4></a></td>"
|
||||
dat += "<td><a href='?src=[REF(src)];field=show_photo_side'><img src=photo_side height=80 width=80 border=4></a></td></tr>"
|
||||
|
||||
@@ -182,10 +182,10 @@
|
||||
if(istype(active1, /datum/data/record) && GLOB.data_core.general.Find(active1))
|
||||
if(istype(active1.fields["photo_front"], /obj/item/photo))
|
||||
var/obj/item/photo/P1 = active1.fields["photo_front"]
|
||||
user << browse_rsc(P1.img, "photo_front")
|
||||
user << browse_rsc(P1.picture.picture_image, "photo_front")
|
||||
if(istype(active1.fields["photo_side"], /obj/item/photo))
|
||||
var/obj/item/photo/P2 = active1.fields["photo_side"]
|
||||
user << browse_rsc(P2.img, "photo_side")
|
||||
user << browse_rsc(P2.picture.picture_image, "photo_side")
|
||||
dat += {"<table><tr><td><table>
|
||||
<tr><td>Name:</td><td><A href='?src=[REF(src)];choice=Edit Field;field=name'> [active1.fields["name"]] </A></td></tr>
|
||||
<tr><td>ID:</td><td><A href='?src=[REF(src)];choice=Edit Field;field=id'> [active1.fields["id"]] </A></td></tr>
|
||||
@@ -446,7 +446,7 @@ What a mess.*/
|
||||
sleep(30)
|
||||
if((istype(active1, /datum/data/record) && GLOB.data_core.general.Find(active1)))//make sure the record still exists.
|
||||
var/obj/item/photo/photo = active1.fields["photo_front"]
|
||||
new /obj/item/poster/wanted(src.loc, photo.img, wanted_name, info)
|
||||
new /obj/item/poster/wanted(loc, photo.picture.picture_image, wanted_name, info)
|
||||
printing = 0
|
||||
|
||||
//RECORD DELETE
|
||||
@@ -611,7 +611,7 @@ What a mess.*/
|
||||
if(photo)
|
||||
qdel(active1.fields["photo_front"])
|
||||
//Lets center it to a 32x32.
|
||||
var/icon/I = photo.img
|
||||
var/icon/I = photo.picture.picture_image
|
||||
var/w = I.Width()
|
||||
var/h = I.Height()
|
||||
var/dw = w - 32
|
||||
@@ -622,7 +622,7 @@ What a mess.*/
|
||||
if(active1.fields["photo_front"])
|
||||
if(istype(active1.fields["photo_front"], /obj/item/photo))
|
||||
var/obj/item/photo/P = active1.fields["photo_front"]
|
||||
print_photo(P.img, active1.fields["name"])
|
||||
print_photo(P.picture.picture_image, active1.fields["name"])
|
||||
if("show_photo_side")
|
||||
if(active1.fields["photo_side"])
|
||||
if(istype(active1.fields["photo_side"], /obj/item/photo))
|
||||
@@ -633,7 +633,7 @@ What a mess.*/
|
||||
if(photo)
|
||||
qdel(active1.fields["photo_side"])
|
||||
//Lets center it to a 32x32.
|
||||
var/icon/I = photo.img
|
||||
var/icon/I = photo.picture.picture_image
|
||||
var/w = I.Width()
|
||||
var/h = I.Height()
|
||||
var/dw = w - 32
|
||||
@@ -644,7 +644,7 @@ What a mess.*/
|
||||
if(active1.fields["photo_side"])
|
||||
if(istype(active1.fields["photo_side"], /obj/item/photo))
|
||||
var/obj/item/photo/P = active1.fields["photo_side"]
|
||||
print_photo(P.img, active1.fields["name"])
|
||||
print_photo(P.picture.picture_image, active1.fields["name"])
|
||||
if("mi_crim_add")
|
||||
if(istype(active1, /datum/data/record))
|
||||
var/t1 = stripped_input(usr, "Please input minor crime names:", "Secure. records", "", null)
|
||||
@@ -759,10 +759,9 @@ What a mess.*/
|
||||
var/obj/item/photo/P = null
|
||||
if(issilicon(user))
|
||||
var/mob/living/silicon/tempAI = user
|
||||
var/datum/picture/selection = tempAI.GetPhoto()
|
||||
var/datum/picture/selection = tempAI.GetPhoto(user)
|
||||
if(selection)
|
||||
P = new()
|
||||
P.photocreate(selection.fields["icon"], selection.fields["img"], selection.fields["desc"])
|
||||
P = new(null, selection)
|
||||
else if(istype(user.get_active_held_item(), /obj/item/photo))
|
||||
P = user.get_active_held_item()
|
||||
return P
|
||||
@@ -778,7 +777,7 @@ What a mess.*/
|
||||
small_img.Scale(8, 8)
|
||||
ic.Blend(small_img,ICON_OVERLAY, 13, 13)
|
||||
P.icon = ic
|
||||
P.img = temp
|
||||
P.picture.picture_image = temp
|
||||
P.desc = "The photo on file for [name]."
|
||||
P.pixel_x = rand(-10, 10)
|
||||
P.pixel_y = rand(-10, 10)
|
||||
|
||||
@@ -129,4 +129,4 @@ GLOBAL_LIST_EMPTY(doppler_arrays)
|
||||
linked_techweb = SSresearch.science_tech
|
||||
|
||||
/proc/techweb_scale_bomb(lightradius)
|
||||
return (lightradius ** 0.5) * 3000
|
||||
return lightradius ** 1.36
|
||||
|
||||
@@ -126,9 +126,9 @@ GLOBAL_LIST_EMPTY(allCasters)
|
||||
newMsg.is_admin_message = adminMessage
|
||||
newMsg.locked = !allow_comments
|
||||
if(photo)
|
||||
newMsg.img = photo.img
|
||||
newMsg.img = photo.picture.picture_image
|
||||
newMsg.caption = photo.scribble
|
||||
newMsg.photo_file = save_photo(photo.img)
|
||||
newMsg.photo_file = save_photo(photo.picture.picture_image)
|
||||
for(var/datum/newscaster/feed_channel/FC in network_channels)
|
||||
if(FC.channel_name == channel_name)
|
||||
FC.messages += newMsg
|
||||
@@ -145,8 +145,8 @@ GLOBAL_LIST_EMPTY(allCasters)
|
||||
wanted_issue.scannedUser = scanned_user
|
||||
wanted_issue.isAdminMsg = adminMsg
|
||||
if(photo)
|
||||
wanted_issue.img = photo.img
|
||||
wanted_issue.photo_file = save_photo(photo.img)
|
||||
wanted_issue.img = photo.picture.picture_image
|
||||
wanted_issue.photo_file = save_photo(photo.picture.picture_image)
|
||||
if(newMessage)
|
||||
for(var/obj/machinery/newscaster/N in GLOB.allCasters)
|
||||
N.newsAlert()
|
||||
@@ -794,10 +794,7 @@ GLOBAL_LIST_EMPTY(allCasters)
|
||||
if(photo && !user.transferItemToLoc(photo, src))
|
||||
photo = null
|
||||
if(issilicon(user))
|
||||
var/list/nametemp = list()
|
||||
var/find
|
||||
var/datum/picture/selection
|
||||
var/obj/item/camera/siliconcam/targetcam = null
|
||||
var/obj/item/camera/siliconcam/targetcam
|
||||
if(isAI(user))
|
||||
var/mob/living/silicon/ai/R = user
|
||||
targetcam = R.aicamera
|
||||
@@ -809,19 +806,12 @@ GLOBAL_LIST_EMPTY(allCasters)
|
||||
targetcam = R.aicamera
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You cannot interface with silicon photo uploading!</span>")
|
||||
if(targetcam.aipictures.len == 0)
|
||||
if(!targetcam.stored.len)
|
||||
to_chat(usr, "<span class='boldannounce'>No images saved</span>")
|
||||
return
|
||||
for(var/datum/picture/t in targetcam.aipictures)
|
||||
nametemp += t.fields["name"]
|
||||
find = input("Select image (numbered in order taken)") in nametemp
|
||||
var/obj/item/photo/P = new/obj/item/photo()
|
||||
for(var/datum/picture/q in targetcam.aipictures)
|
||||
if(q.fields["name"] == find)
|
||||
selection = q
|
||||
break
|
||||
P.photocreate(selection.fields["icon"], selection.fields["img"], selection.fields["desc"])
|
||||
P.sillynewscastervar = 1
|
||||
var/datum/picture/selection = targetcam.selectpicture(user)
|
||||
var/obj/item/photo/P = new(null, selection)
|
||||
P.sillynewscastervar = TRUE
|
||||
photo = P
|
||||
qdel(P)
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@
|
||||
break
|
||||
// Del - Sender - Recepient - Message
|
||||
// X - Al Green - Your Mom - WHAT UP!?
|
||||
dat += "<tr><td width = '5%'><center><A href='?src=[REF(src)];delete_logs=[REF(pda)]' style='color: rgb(255,0,0)'>X</a></center></td><td width='15%'>[pda.sender]</td><td width='15%'>[pda.recipient]</td><td width='300px'>[pda.message][pda.photo ? " <a href='byond://?src=[REF(pda)];photo=1'>(Photo)</a>":""]</td></tr>"
|
||||
dat += "<tr><td width = '5%'><center><A href='?src=[REF(src)];delete_logs=[REF(pda)]' style='color: rgb(255,0,0)'>X</a></center></td><td width='15%'>[pda.sender]</td><td width='15%'>[pda.recipient]</td><td width='300px'>[pda.message][pda.picture ? " <a href='byond://?src=[REF(pda)];photo=1'>(Photo)</a>":""]</td></tr>"
|
||||
dat += "</table>"
|
||||
//Hacking screen.
|
||||
if(2)
|
||||
|
||||
@@ -124,7 +124,7 @@
|
||||
var/sender = "Unspecified"
|
||||
var/recipient = "Unspecified"
|
||||
var/message = "Blank" // transferred message
|
||||
var/icon/photo // attached photo
|
||||
var/datum/picture/picture // attached photo
|
||||
|
||||
/datum/data_pda_msg/New(param_rec, param_sender, param_message, param_photo)
|
||||
if(param_rec)
|
||||
@@ -134,17 +134,17 @@
|
||||
if(param_message)
|
||||
message = param_message
|
||||
if(param_photo)
|
||||
photo = param_photo
|
||||
picture = param_photo
|
||||
|
||||
/datum/data_pda_msg/Topic(href,href_list)
|
||||
..()
|
||||
if(href_list["photo"])
|
||||
var/mob/M = usr
|
||||
M << browse_rsc(photo, "pda_photo.png")
|
||||
M << browse_rsc(picture.picture_image, "pda_photo.png")
|
||||
M << browse("<html><head><title>PDA Photo</title></head>" \
|
||||
+ "<body style='overflow:hidden;margin:0;text-align:center'>" \
|
||||
+ "<img src='pda_photo.png' width='192' style='-ms-interpolation-mode:nearest-neighbor' />" \
|
||||
+ "</body></html>", "window=pdaphoto;size=192x192")
|
||||
+ "</body></html>", "window=pdaphoto;size=[picture.psize_x]x[picture.psize_y]")
|
||||
onclose(M, "pdaphoto")
|
||||
|
||||
/datum/data_rc_msg
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
var/turf/open/atmos_destination //Atmos link destination
|
||||
var/allow_anchored = FALSE
|
||||
var/innate_accuracy_penalty = 0
|
||||
var/last_effect = 0
|
||||
|
||||
/obj/effect/portal/anom
|
||||
name = "wormhole"
|
||||
@@ -154,7 +155,12 @@
|
||||
return
|
||||
if(ismegafauna(M))
|
||||
message_admins("[M] has used a portal at [ADMIN_VERBOSEJMP(src)] made by [usr].")
|
||||
if(do_teleport(M, real_target, innate_accuracy_penalty))
|
||||
var/no_effect = FALSE
|
||||
if(last_effect == world.time)
|
||||
no_effect = TRUE
|
||||
else
|
||||
last_effect = world.time
|
||||
if(do_teleport(M, real_target, innate_accuracy_penalty, no_effects = no_effect))
|
||||
if(istype(M, /obj/item/projectile))
|
||||
var/obj/item/projectile/P = M
|
||||
P.ignore_source_check = TRUE
|
||||
|
||||
@@ -33,3 +33,6 @@
|
||||
/obj/effect/projectile/impact/heavy_laser
|
||||
name = "heavy laser impact"
|
||||
icon_state = "impact_beam_heavy"
|
||||
|
||||
/obj/effect/projectile/impact/wormhole
|
||||
icon_state = "wormhole_g"
|
||||
|
||||
@@ -25,3 +25,6 @@
|
||||
|
||||
/obj/effect/projectile/muzzle/heavy_laser
|
||||
icon_state = "muzzle_beam_heavy"
|
||||
|
||||
/obj/effect/projectile/muzzle/wormhole
|
||||
icon_state = "wormhole_g"
|
||||
|
||||
@@ -51,6 +51,10 @@
|
||||
pixel_x += round((sin(angle_override)+16*sin(angle_override)*2), 1)
|
||||
pixel_y += round((cos(angle_override)+16*cos(angle_override)*2), 1)
|
||||
|
||||
/obj/effect/projectile_lighting/Initialize(mapload, color, range, intensity)
|
||||
/obj/effect/projectile_lighting
|
||||
var/owner
|
||||
|
||||
/obj/effect/projectile_lighting/Initialize(mapload, color, range, intensity, owner_key)
|
||||
. = ..()
|
||||
set_light(range, intensity, color)
|
||||
owner = owner_key
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/proc/generate_tracer_between_points(datum/point/starting, datum/point/ending, beam_type, color, qdel_in = 5, light_range = 2, light_color_override, light_intensity = 1) //Do not pass z-crossing points as that will not be properly (and likely will never be properly until it's absolutely needed) supported!
|
||||
/proc/generate_tracer_between_points(datum/point/starting, datum/point/ending, beam_type, color, qdel_in = 5, light_range = 2, light_color_override, light_intensity = 1, instance_key) //Do not pass z-crossing points as that will not be properly (and likely will never be properly until it's absolutely needed) supported!
|
||||
if(!istype(starting) || !istype(ending) || !ispath(beam_type))
|
||||
return
|
||||
var/datum/point/midpoint = point_midpoint_points(starting, ending)
|
||||
@@ -9,9 +9,13 @@
|
||||
. = PB
|
||||
if(light_range > 0 && light_intensity > 0)
|
||||
var/list/turf/line = getline(starting.return_turf(), ending.return_turf())
|
||||
for(var/i in line)
|
||||
var/turf/T = i
|
||||
QDEL_IN(new /obj/effect/projectile_lighting(T, light_color_override, light_range, light_intensity), qdel_in > 0? qdel_in : 5)
|
||||
tracing_line:
|
||||
for(var/i in line)
|
||||
var/turf/T = i
|
||||
for(var/obj/effect/projectile_lighting/PL in T)
|
||||
if(PL.owner == instance_key)
|
||||
continue tracing_line
|
||||
QDEL_IN(new /obj/effect/projectile_lighting(T, light_color_override, light_range, light_intensity, instance_key), qdel_in > 0? qdel_in : 5)
|
||||
line = null
|
||||
if(qdel_in)
|
||||
QDEL_IN(PB, qdel_in)
|
||||
@@ -57,3 +61,6 @@
|
||||
|
||||
/obj/effect/projectile/tracer/tracer/aiming
|
||||
icon_state = "pixelbeam_greyscale"
|
||||
|
||||
/obj/effect/projectile/tracer/wormhole
|
||||
icon_state = "wormhole_g"
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
var/drawtype
|
||||
var/text_buffer = ""
|
||||
|
||||
var/list/graffiti = list("amyjon","face","matt","revolution","engie","guy","end","dwarf","uboa","body","cyka","arrow","star","poseur tag","prolizard","antilizard")
|
||||
var/list/graffiti = list("amyjon","face","matt","revolution","engie","guy","end","dwarf","uboa","body","cyka","arrow","star","poseur tag","prolizard","antilizard", "tile") //cit edit
|
||||
var/list/letters = list("a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z")
|
||||
var/list/numerals = list("0","1","2","3","4","5","6","7","8","9")
|
||||
var/list/oriented = list("arrow","body") // These turn to face the same way as the drawer
|
||||
|
||||
@@ -72,7 +72,7 @@ GLOBAL_LIST_EMPTY(PDAs)
|
||||
|
||||
var/obj/item/paicard/pai = null // A slot for a personal AI device
|
||||
|
||||
var/icon/photo //Scanned photo
|
||||
var/datum/picture/picture //Scanned photo
|
||||
|
||||
var/list/contained_item = list(/obj/item/pen, /obj/item/toy/crayon, /obj/item/lipstick, /obj/item/flashlight/pen, /obj/item/clothing/mask/cigarette)
|
||||
var/obj/item/inserted_item //Used for pen, crayon, and lipstick insertion or removal. Same as above.
|
||||
@@ -636,8 +636,8 @@ GLOBAL_LIST_EMPTY(PDAs)
|
||||
"message" = message,
|
||||
"targets" = string_targets
|
||||
))
|
||||
if (photo)
|
||||
signal.data["photo"] = photo
|
||||
if (picture)
|
||||
signal.data["photo"] = picture
|
||||
signal.send_to_receivers()
|
||||
|
||||
// If it didn't reach, note that fact
|
||||
@@ -657,7 +657,7 @@ GLOBAL_LIST_EMPTY(PDAs)
|
||||
log_talk(user, "[key_name(user)] (PDA: [initial(name)]) sent \"[message]\" to [target_text]", LOGPDA)
|
||||
to_chat(user, "<span class='info'>Message sent to [target_text]: \"[message]\"</span>")
|
||||
// Reset the photo
|
||||
photo = null
|
||||
picture = null
|
||||
last_text = world.time
|
||||
if (everyone)
|
||||
last_everyone = world.time
|
||||
@@ -811,7 +811,7 @@ GLOBAL_LIST_EMPTY(PDAs)
|
||||
update_icon()
|
||||
else if(istype(C, /obj/item/photo))
|
||||
var/obj/item/photo/P = C
|
||||
photo = P.img
|
||||
picture = P.picture
|
||||
to_chat(user, "<span class='notice'>You scan \the [C].</span>")
|
||||
else
|
||||
return ..()
|
||||
@@ -925,11 +925,11 @@ GLOBAL_LIST_EMPTY(PDAs)
|
||||
|
||||
var/selected = plist[c]
|
||||
|
||||
if(aicamera.aipictures.len>0)
|
||||
if(aicamera.stored.len)
|
||||
var/add_photo = input(user,"Do you want to attach a photo?","Photo","No") as null|anything in list("Yes","No")
|
||||
if(add_photo=="Yes")
|
||||
var/datum/picture/Pic = aicamera.selectpicture(aicamera)
|
||||
aiPDA.photo = Pic.fields["img"]
|
||||
var/datum/picture/Pic = aicamera.selectpicture(user)
|
||||
aiPDA.picture = Pic
|
||||
|
||||
if(incapacitated())
|
||||
return
|
||||
|
||||
@@ -79,10 +79,17 @@
|
||||
has_latches = FALSE
|
||||
|
||||
/obj/item/storage/toolbox/mechanical/old/heirloom
|
||||
name = "toolbox" //this will be named "X family toolbox"
|
||||
name = "old, robust toolbox" //this will be named "X family toolbox"
|
||||
desc = "It's seen better days."
|
||||
force = 5
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
force = 12
|
||||
total_mass = 2
|
||||
|
||||
/obj/item/storage/toolbox/mechanical/old/heirloom/afterattack(atom/A, mob/user, proximity)
|
||||
. = ..()
|
||||
if(proximity)
|
||||
if(isobj(A))
|
||||
var/obj/O = A
|
||||
O.take_damage(20)
|
||||
|
||||
/obj/item/storage/toolbox/mechanical/old/heirloom/PopulateContents()
|
||||
return
|
||||
|
||||
@@ -19,3 +19,4 @@
|
||||
new /obj/item/export_scanner(src)
|
||||
new /obj/item/door_remote/quartermaster(src)
|
||||
new /obj/item/circuitboard/machine/techfab/department/cargo(src)
|
||||
new /obj/item/storage/photo_album/QM(src)
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
new /obj/item/inducer(src)
|
||||
new /obj/item/circuitboard/machine/techfab/department/engineering(src)
|
||||
new /obj/item/extinguisher/advanced(src)
|
||||
new /obj/item/storage/photo_album/CE(src)
|
||||
|
||||
/obj/structure/closet/secure_closet/engineering_electrical
|
||||
name = "electrical supplies locker"
|
||||
|
||||
@@ -76,6 +76,7 @@
|
||||
new /obj/item/pet_carrier(src)
|
||||
new /obj/item/wallframe/defib_mount(src)
|
||||
new /obj/item/circuitboard/machine/techfab/department/medical(src)
|
||||
new /obj/item/storage/photo_album/CMO(src)
|
||||
|
||||
/obj/structure/closet/secure_closet/animal
|
||||
name = "animal control"
|
||||
|
||||
@@ -25,3 +25,4 @@
|
||||
new /obj/item/laser_pointer(src)
|
||||
new /obj/item/door_remote/research_director(src)
|
||||
new /obj/item/circuitboard/machine/techfab/department/science(src)
|
||||
new /obj/item/storage/photo_album/RD(src)
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
new /obj/item/gun/energy/e_gun(src)
|
||||
new /obj/item/door_remote/captain(src)
|
||||
new /obj/item/card/id/captains_spare(src)
|
||||
new /obj/item/storage/photo_album/Captain(src)
|
||||
|
||||
/obj/structure/closet/secure_closet/hop
|
||||
name = "\proper head of personnel's locker"
|
||||
@@ -59,6 +60,7 @@
|
||||
new /obj/item/pet_carrier(src)
|
||||
new /obj/item/door_remote/civillian(src)
|
||||
new /obj/item/circuitboard/machine/techfab/department/service(src)
|
||||
new /obj/item/storage/photo_album/HoP(src)
|
||||
|
||||
/obj/structure/closet/secure_closet/hos
|
||||
name = "\proper head of security's locker"
|
||||
@@ -91,6 +93,7 @@
|
||||
new /obj/item/flashlight/seclite(src)
|
||||
new /obj/item/pinpointer/nuke(src)
|
||||
new /obj/item/circuitboard/machine/techfab/department/security(src)
|
||||
new /obj/item/storage/photo_album/HoS(src)
|
||||
|
||||
/obj/structure/closet/secure_closet/warden
|
||||
name = "\proper warden's locker"
|
||||
|
||||
@@ -79,13 +79,24 @@ GLOBAL_PROTECT(security_mode)
|
||||
/world/proc/SetupLogs()
|
||||
var/override_dir = params[OVERRIDE_LOG_DIRECTORY_PARAMETER]
|
||||
if(!override_dir)
|
||||
GLOB.log_directory = "data/logs/[time2text(world.realtime, "YYYY/MM/DD")]/round-"
|
||||
var/realtime = world.realtime
|
||||
var/texttime = time2text(realtime, "YYYY/MM/DD")
|
||||
GLOB.log_directory = "data/logs/[texttime]/round-"
|
||||
GLOB.picture_logging_prefix = "L_[time2text(realtime, "YYYYMMDD")]_"
|
||||
GLOB.picture_log_directory = "data/picture_logs/[texttime]/round-"
|
||||
if(GLOB.round_id)
|
||||
GLOB.log_directory += "[GLOB.round_id]"
|
||||
GLOB.picture_logging_prefix += "R_[GLOB.round_id]_"
|
||||
GLOB.picture_log_directory += "[GLOB.round_id]"
|
||||
else
|
||||
GLOB.log_directory += "[replacetext(time_stamp(), ":", ".")]"
|
||||
var/timestamp = replacetext(time_stamp(), ":", ".")
|
||||
GLOB.log_directory += "[timestamp]"
|
||||
GLOB.picture_log_directory += "[timestamp]"
|
||||
GLOB.picture_logging_prefix += "T_[timestamp]_"
|
||||
else
|
||||
GLOB.log_directory = "data/logs/[override_dir]"
|
||||
GLOB.picture_logging_prefix = "O_[override_dir]_"
|
||||
GLOB.picture_log_directory = "data/picture_logs/[override_dir]"
|
||||
|
||||
GLOB.world_game_log = "[GLOB.log_directory]/game.log"
|
||||
GLOB.world_attack_log = "[GLOB.log_directory]/attack.log"
|
||||
|
||||
@@ -47,7 +47,7 @@ GLOBAL_LIST_INIT(admin_verbs_debug_mapping, list(
|
||||
/client/proc/stop_line_profiling,
|
||||
/client/proc/show_line_profiling,
|
||||
/client/proc/create_mapping_job_icons,
|
||||
/client/proc/debug_z_levels,
|
||||
/client/proc/debug_z_levels
|
||||
))
|
||||
|
||||
/obj/effect/debugging/mapfix_marker
|
||||
|
||||
@@ -1313,7 +1313,7 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
var/list/punishment_list = list(ADMIN_PUNISHMENT_LIGHTNING, ADMIN_PUNISHMENT_BRAINDAMAGE, ADMIN_PUNISHMENT_GIB, ADMIN_PUNISHMENT_BSA, ADMIN_PUNISHMENT_FIREBALL, ADMIN_PUNISHMENT_ROD, ADMIN_PUNISHMENT_SUPPLYPOD)
|
||||
var/list/punishment_list = list(ADMIN_PUNISHMENT_LIGHTNING, ADMIN_PUNISHMENT_BRAINDAMAGE, ADMIN_PUNISHMENT_GIB, ADMIN_PUNISHMENT_BSA, ADMIN_PUNISHMENT_FIREBALL, ADMIN_PUNISHMENT_ROD, ADMIN_PUNISHMENT_SUPPLYPOD, ADMIN_PUNISHMENT_MAZING)
|
||||
|
||||
var/punishment = input("Choose a punishment", "DIVINE SMITING") as null|anything in punishment_list
|
||||
|
||||
@@ -1359,6 +1359,10 @@ GLOBAL_LIST_EMPTY(custom_outfits) //Admin created outfits
|
||||
if(iscarbon(target))
|
||||
target.Stun(10)//takes 0.53 seconds for CentCom pod to land
|
||||
new /obj/effect/DPtarget(get_turf(target), delivery, POD_CENTCOM)
|
||||
if(ADMIN_PUNISHMENT_MAZING)
|
||||
if(!puzzle_imprison(target))
|
||||
to_chat(usr,"<span class='warning'>Imprisonment failed!</span>")
|
||||
return
|
||||
|
||||
var/msg = "[key_name_admin(usr)] punished [key_name_admin(target)] with [punishment]."
|
||||
message_admins(msg)
|
||||
|
||||
@@ -99,8 +99,9 @@
|
||||
dat += "<h3> Experiment </h3>"
|
||||
if(occupant)
|
||||
var/obj/item/photo/P = new
|
||||
P.photocreate(null, icon(dissection_icon(occupant), dir = SOUTH))
|
||||
user << browse_rsc(P.img, "dissection_img")
|
||||
P.picture = new
|
||||
P.picture.picture_image = icon(dissection_icon(occupant), dir = SOUTH)
|
||||
user << browse_rsc(P.picture.picture_image, "dissection_img")
|
||||
dat += "<table><tr><td>"
|
||||
dat += "<img src=dissection_img height=80 width=80>" //Avert your eyes
|
||||
dat += "</td><td>"
|
||||
|
||||
@@ -225,6 +225,7 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
||||
|
||||
var/res_name = "spritesheet_[name].css"
|
||||
var/fname = "data/spritesheets/[res_name]"
|
||||
fdel(fname)
|
||||
text2file(generate_css(), fname)
|
||||
register_asset(res_name, file(fname))
|
||||
|
||||
|
||||
@@ -729,6 +729,9 @@ GLOBAL_LIST_EMPTY(external_rsc_urls)
|
||||
if (clicklimiter[SECOND_COUNT] > scl)
|
||||
to_chat(src, "<span class='danger'>Your previous click was ignored because you've done too many in a second</span>")
|
||||
return
|
||||
|
||||
if(ab)
|
||||
return
|
||||
|
||||
if (prefs.hotkeys)
|
||||
// If hotkey mode is enabled, then clicking the map will automatically
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
//Yes, I'm sorry.
|
||||
/datum/turf_reservation
|
||||
var/list/reserved_turfs = list()
|
||||
var/width = 0
|
||||
var/height = 0
|
||||
var/bottom_left_coords[3]
|
||||
var/top_right_coords[3]
|
||||
var/wipe_reservation_on_release = TRUE
|
||||
@@ -59,6 +61,8 @@
|
||||
SSmapping.unused_turfs["[T.z]"] -= T
|
||||
SSmapping.used_turfs[T] = src
|
||||
T.ChangeTurf(turf_type, turf_type)
|
||||
src.width = width
|
||||
src.height = height
|
||||
return TRUE
|
||||
|
||||
/datum/turf_reservation/New()
|
||||
|
||||
@@ -1315,3 +1315,18 @@
|
||||
for(var/t in RANGE_TURFS(1, T))
|
||||
var/obj/effect/temp_visual/hierophant/blast/B = new(t, user, friendly_fire_check)
|
||||
B.damage = 15 //keeps monster damage boost due to lower damage
|
||||
|
||||
|
||||
//Just some minor stuff
|
||||
/obj/structure/closet/crate/necropolis/puzzle
|
||||
name = "puzzling chest"
|
||||
|
||||
/obj/structure/closet/crate/necropolis/puzzle/PopulateContents()
|
||||
var/loot = rand(1,3)
|
||||
switch(loot)
|
||||
if(1)
|
||||
new /obj/item/soulstone/anybody(src)
|
||||
if(2)
|
||||
new /obj/item/wisp_lantern(src)
|
||||
if(3)
|
||||
new /obj/item/prisoncube(src)
|
||||
@@ -64,6 +64,9 @@
|
||||
//////////////////////
|
||||
// Hair Definitions //
|
||||
//////////////////////
|
||||
|
||||
#define VHAIR(_name, new_state) /datum/sprite_accessory/hair/##new_state/icon_state=#new_state;/datum/sprite_accessory/hair/##new_state/name = "Virgo - " + #_name
|
||||
|
||||
/datum/sprite_accessory/hair
|
||||
icon = 'icons/mob/human_face.dmi' // default icon for all hairs
|
||||
|
||||
@@ -147,7 +150,6 @@
|
||||
name = "Ponytail 5"
|
||||
icon_state = "hair_ponytail5"
|
||||
|
||||
|
||||
/datum/sprite_accessory/hair/sidetail
|
||||
name = "Side Pony"
|
||||
icon_state = "hair_sidetail"
|
||||
@@ -512,9 +514,172 @@
|
||||
name = "Large Bun"
|
||||
icon_state = "hair_largebun"
|
||||
|
||||
|
||||
//VIRGO PORTED HAIRS
|
||||
VHAIR(Short Hair Rosa, hair_rosa_s)
|
||||
VHAIR(Short Hair 80s, hair_80s_s)
|
||||
VHAIR(Long Bedhead, hair_long_bedhead_s)
|
||||
VHAIR(Dave, hair_dave_s)
|
||||
VHAIR(Country, hair_country_s)
|
||||
VHAIR(Shy, hair_shy_s)
|
||||
VHAIR(Unshaven Mohawk, hair_unshaven_mohawk_s)
|
||||
VHAIR(Manbun, hair_manbun_s)
|
||||
VHAIR(Longer Bedhead, hair_longer_bedhead_s)
|
||||
VHAIR(Ponytail, hair_ponytail_s)
|
||||
VHAIR(Ziegler, hair_ziegler_s)
|
||||
VHAIR(Emo Fringe, hair_emofringe_s)
|
||||
VHAIR(Very Short Over Eye Alt, hair_veryshortovereyealternate_s)
|
||||
VHAIR(Shorthime, hair_shorthime_s)
|
||||
VHAIR(High Tight, hair_hightight_s)
|
||||
VHAIR(Thinning Front, hair_thinningfront_s)
|
||||
VHAIR(Big Afro, hair_bigafro_s)
|
||||
VHAIR(Afro, hair_afro_s)
|
||||
VHAIR(High Braid, hair_hbraid_s)
|
||||
VHAIR(Braid, hair_braid_s)
|
||||
VHAIR(Sargeant, hair_sargeant_s)
|
||||
VHAIR(Gelled, hair_gelled_s)
|
||||
VHAIR(Kagami, hair_kagami_s)
|
||||
VHAIR(ShortTail, hair_stail_s)
|
||||
VHAIR(Gentle, hair_gentle_s)
|
||||
VHAIR(Grande, hair_grande_s)
|
||||
VHAIR(Bobcurl, hair_bobcurl_s)
|
||||
VHAIR(Pompadeur, hair_pompadour_s)
|
||||
VHAIR(Plait, hair_plait_s)
|
||||
VHAIR(Long, hair_long_s)
|
||||
VHAIR(Rattail, hair_rattail_s)
|
||||
VHAIR(Tajspiky, hair_tajspiky_s)
|
||||
VHAIR(Messy, hair_messy_s)
|
||||
VHAIR(Bangs, hair_bangs_s)
|
||||
VHAIR(TBraid, hair_tbraid_s)
|
||||
VHAIR(Toriyama2, hair_toriyama2_s)
|
||||
VHAIR(CIA, hair_cia_s)
|
||||
VHAIR(Mulder, hair_mulder_s)
|
||||
VHAIR(Scully, hair_scully_s)
|
||||
VHAIR(Nitori, hair_nitori_s)
|
||||
VHAIR(Joestar, hair_joestar_s)
|
||||
VHAIR(Ponytail4, hair_ponytail4_s)
|
||||
VHAIR(Ponytail5, hair_ponytail5_s)
|
||||
VHAIR(Beehive2, hair_beehive2_s)
|
||||
VHAIR(Short Braid, hair_shortbraid_s)
|
||||
VHAIR(Reverse Mohawk, hair_reversemohawk_s)
|
||||
VHAIR(SHort Bangs, hair_shortbangs_s)
|
||||
VHAIR(Half Shaved, hair_halfshaved_s)
|
||||
VHAIR(Longer Alt 2, hair_longeralt2_s)
|
||||
VHAIR(Bun, hair_bun_s)
|
||||
VHAIR(Curly, hair_curly_s)
|
||||
VHAIR(Victory, hair_victory_s)
|
||||
VHAIR(Ponytail6, hair_ponytail6_s)
|
||||
VHAIR(Undercut3, hair_undercut3_s)
|
||||
VHAIR(Bobcut Alt, hair_bobcultalt_s)
|
||||
VHAIR(Fingerwave, hair_fingerwave_s)
|
||||
VHAIR(Oxton, hair_oxton_s)
|
||||
VHAIR(Poofy2, hair_poofy2_s)
|
||||
VHAIR(Fringe Tail, hair_fringetail_s)
|
||||
VHAIR(Bun3, hair_bun3_s)
|
||||
VHAIR(Wisp, hair_wisp_s)
|
||||
VHAIR(Undercut2, hair_undercut2_s)
|
||||
VHAIR(TBob, hair_tbob_s)
|
||||
VHAIR(Spiky Ponytail, hair_spikyponytail_s)
|
||||
VHAIR(Rowbun, hair_rowbun_s)
|
||||
VHAIR(Rowdualtail, hair_rowdualtail_s)
|
||||
VHAIR(Rowbraid, hair_rowbraid_s)
|
||||
VHAIR(Shaved Mohawk, hair_shavedmohawk_s)
|
||||
VHAIR(Topknot, hair_topknot_s)
|
||||
VHAIR(Ronin, hair_ronin_s)
|
||||
VHAIR(Bowlcut2, hair_bowlcut2_s)
|
||||
VHAIR(Thinning Rear, hair_thinningrear_s)
|
||||
VHAIR(Thinning, hair_thinning_s)
|
||||
VHAIR(Jade, hair_jade_s)
|
||||
VHAIR(Bedhead, hair_bedhead_s)
|
||||
VHAIR(Dreadlocks, hair_dreads_s)
|
||||
VHAIR(Very Long, hair_vlong_s)
|
||||
VHAIR(Jensen, hair_jensen_s)
|
||||
VHAIR(Halfbang, hair_halfbang_s)
|
||||
VHAIR(Kusangi, hair_kusangi_s)
|
||||
VHAIR(Ponytail, hair_ponytail_s)
|
||||
VHAIR(Ponytail3, hair_ponytail3_s)
|
||||
VHAIR(Halfbang Alt, hair_halfbang_alt_s)
|
||||
VHAIR(Bedhead V2, hair_bedheadv2_s)
|
||||
VHAIR(Long Fringe, hair_longfringe_s)
|
||||
VHAIR(Flair, hair_flair_s)
|
||||
VHAIR(Bedhead V3, hair_bedheadv3_s)
|
||||
VHAIR(Himecut, hair_himecut_s)
|
||||
VHAIR(Curls, hair_curls_s)
|
||||
VHAIR(Very Long Fringe, hair_vlongfringe_s)
|
||||
VHAIR(Longest, hair_longest_s)
|
||||
VHAIR(Father, hair_father_s)
|
||||
VHAIR(Emo Long, hair_emolong_s)
|
||||
VHAIR(Short Hair 3, hair_shorthair3_s)
|
||||
VHAIR(Double Bun, hair_doublebun_s)
|
||||
VHAIR(Sleeze, hair_sleeze_s)
|
||||
VHAIR(Twintail, hair_twintail_s)
|
||||
VHAIR(Emo 2, hair_emo2_s)
|
||||
VHAIR(Low Fade, hair_lowfade_s)
|
||||
VHAIR(Med Fade, hair_medfade_s)
|
||||
VHAIR(High Fade, hair_highfade_s)
|
||||
VHAIR(Bald Fade, hair_baldfade_s)
|
||||
VHAIR(No Fade, hair_nofade_s)
|
||||
VHAIR(Trim Flat, hair_trimflat_s)
|
||||
VHAIR(Shaved, hair_shaved_s)
|
||||
VHAIR(Trimmed, hair_trimmed_s)
|
||||
VHAIR(Tight Bun, hair_tightbun_s)
|
||||
VHAIR(Short Hair 4, hair_d_s)
|
||||
VHAIR(Short Hair 5, hair_e_s)
|
||||
VHAIR(Short Hair 6, hair_f_s)
|
||||
VHAIR(Skinhead, hair_skinhead_s)
|
||||
VHAIR(Afro2, hair_afro2_s)
|
||||
VHAIR(Bobcut, hair_bobcut_s)
|
||||
VHAIR(Emo, hair_emo_s)
|
||||
VHAIR(Long Over Eye, hair_longovereye_s)
|
||||
VHAIR(Feather, hair_feather_s)
|
||||
VHAIR(Hitop, hair_hitop_s)
|
||||
VHAIR(Short Over Eye, hair_shortoverye_s)
|
||||
VHAIR(Straight, hair_straight_s)
|
||||
VHAIR(Buzzcut, hair_buzzcut_s)
|
||||
VHAIR(Combover, hair_combover_s)
|
||||
VHAIR(Crewcut, hair_crewcut_s)
|
||||
VHAIR(Devillock, hair_devilock_s)
|
||||
VHAIR(Clean, hair_clean_s)
|
||||
VHAIR(Shaggy, hair_shaggy_s)
|
||||
VHAIR(Updo, hair_updo_s)
|
||||
VHAIR(Mohawk, hair_mohawk_s)
|
||||
VHAIR(Odango, hair_odango_s)
|
||||
VHAIR(Ombre, hair_ombre_s)
|
||||
VHAIR(Parted, hair_parted_s)
|
||||
VHAIR(Quiff, hair_quiff_s)
|
||||
VHAIR(Volaju, hair_volaju_s)
|
||||
VHAIR(Bun2, hair_bun2_s)
|
||||
VHAIR(Rows1, hair_rows1_s)
|
||||
VHAIR(Rows2, hair_rows2_s)
|
||||
VHAIR(Dandy Pompadour, hair_dandypompadour_s)
|
||||
VHAIR(Poofy, hair_poofy_s)
|
||||
VHAIR(Toriyama, hair_toriyama_s)
|
||||
VHAIR(Drillruru, hair_drillruru_s)
|
||||
VHAIR(Bowlcut, hair_bowlcut_s)
|
||||
VHAIR(Coffee House, hair_coffeehouse_s)
|
||||
VHAIR(Family Man, hair_thefamilyman_s)
|
||||
VHAIR(Shaved Part, hair_shavedpart_s)
|
||||
VHAIR(Modern, hair_modern_s)
|
||||
VHAIR(One Shoulder, hair_oneshoulder_s)
|
||||
VHAIR(Very Short Over Eye, hair_veryshortovereye_s)
|
||||
VHAIR(Unkept, hair_unkept_s)
|
||||
VHAIR(Wife, hair_wife_s)
|
||||
VHAIR(Nia, hair_nia_s)
|
||||
VHAIR(Undercut, hair_undercut_s)
|
||||
VHAIR(Bobcut Alt, hair_bobcutalt_s)
|
||||
VHAIR(Short Hair 4 alt, hair_shorthair4_s)
|
||||
VHAIR(Tressshoulder, hair_tressshoulder_s)
|
||||
|
||||
//END
|
||||
|
||||
#undef VHAIR
|
||||
|
||||
/////////////////////////////
|
||||
// Facial Hair Definitions //
|
||||
/////////////////////////////
|
||||
|
||||
#define VFACE(_name, new_state) /datum/sprite_accessory/facial_hair/##new_state/icon_state=#new_state;;/datum/sprite_accessory/facial_hair/##new_state/name="Virgo" + #_name
|
||||
|
||||
/datum/sprite_accessory/facial_hair
|
||||
icon = 'icons/mob/human_face.dmi'
|
||||
gender = MALE // barf (unless you're a dorf, dorfs dig chix w/ beards :P)
|
||||
@@ -600,6 +765,46 @@
|
||||
name = "Broken Man"
|
||||
icon_state = "facial_brokenman"
|
||||
|
||||
VFACE(Watson, facial_watson_s)
|
||||
VFACE(Chaplin, facial_chaplin_s)
|
||||
VFACE(Fullbeard, facial_fullbeard_s)
|
||||
VFACE(Vandyke, facial_vandyke_s)
|
||||
VFACE(Elvis, facial_elvis_s)
|
||||
VFACE(Abe, facial_abe_s)
|
||||
VFACE(Chin, facial_chin_s)
|
||||
VFACE(GT, facial_gt_s)
|
||||
VFACE(Hip, facial_hip_s)
|
||||
VFACE(Hogan, facial_hogan_s)
|
||||
VFACE(Selleck, facial_selleck_s)
|
||||
VFACE(Neckbeard, facial_neckbeard_s)
|
||||
VFACE(Longbeard, facial_longbeard_s)
|
||||
VFACE(Dwarf, facial_dwarf_s)
|
||||
VFACE(Sideburn, facial_sideburn_s)
|
||||
VFACE(Mutton, facial_mutton_s)
|
||||
VFACE(Moustache, facial_moustache_s)
|
||||
VFACE(Pencilstache, facial_pencilstache_s)
|
||||
VFACE(Goatee, facial_goatee_s)
|
||||
VFACE(Smallstache, facial_smallstache_s)
|
||||
VFACE(Volaju, facial_volaju_s)
|
||||
VFACE(3 O\'clock, facial_3oclock_s)
|
||||
VFACE(5 O\'clock, facial_5oclock_s)
|
||||
VFACE(7 O\'clock, facial_7oclock_s)
|
||||
VFACE(5 O\'clock Moustache, facial_5oclockmoustache_s)
|
||||
VFACE(7 O\'clock, facial_7oclockmoustache_s)
|
||||
VFACE(Walrus, facial_walrus_s)
|
||||
VFACE(Muttonmus, facial_muttonmus_s)
|
||||
VFACE(Wise, facial_wise_s)
|
||||
VFACE(Martial Artist, facial_martialartist_s)
|
||||
VFACE(Dorsalfnil, facial_dorsalfnil_s)
|
||||
VFACE(Hornadorns, facial_hornadorns_s)
|
||||
VFACE(Spike, facial_spike_s)
|
||||
VFACE(Chinhorns, facial_chinhorns_s)
|
||||
VFACE(Cropped Fullbeard, facial_croppedfullbeard_s)
|
||||
VFACE(Chinless Beard, facial_chinlessbeard_s)
|
||||
VFACE(Moonshiner, facial_moonshiner_s)
|
||||
VFACE(Tribearder, facial_tribearder_s)
|
||||
|
||||
#undef VFACE
|
||||
|
||||
///////////////////////////
|
||||
// Underwear Definitions //
|
||||
|
||||
@@ -104,7 +104,6 @@
|
||||
msg += "[t_He] look[p_s()] very happy.\n"
|
||||
if(MOOD_LEVEL_HAPPY4 to INFINITY)
|
||||
msg += "[t_He] look[p_s()] ecstatic.\n"
|
||||
|
||||
msg += "*---------*</span>"
|
||||
|
||||
to_chat(user, msg)
|
||||
|
||||
@@ -133,7 +133,7 @@
|
||||
else if(eye_blurry) //blurry eyes heal slowly
|
||||
eye_blurry = max(eye_blurry-1, 0)
|
||||
if(client && !eye_blurry)
|
||||
clear_fullscreen("blurry")
|
||||
remove_eyeblur()
|
||||
|
||||
/mob/living/proc/update_damage_hud()
|
||||
return
|
||||
@@ -148,7 +148,7 @@
|
||||
|
||||
/mob/living/proc/gravity_animate()
|
||||
if(!get_filter("gravity"))
|
||||
add_filter("gravity",1,list("type"="motion_blur", "x"=0, "y"=0))
|
||||
add_filter("gravity",1, GRAVITY_MOTION_BLUR)
|
||||
INVOKE_ASYNC(src, .proc/gravity_pulse_animation)
|
||||
|
||||
/mob/living/proc/gravity_pulse_animation()
|
||||
|
||||
@@ -78,4 +78,5 @@
|
||||
temp = master.supplied[index]
|
||||
if (length(temp) > 0)
|
||||
laws.supplied[index] = temp
|
||||
return
|
||||
|
||||
picturesync()
|
||||
|
||||
@@ -1205,4 +1205,12 @@
|
||||
lawsync()
|
||||
lawupdate = 1
|
||||
return TRUE
|
||||
picturesync()
|
||||
return FALSE
|
||||
|
||||
/mob/living/silicon/robot/proc/picturesync()
|
||||
if(connected_ai && connected_ai.aicamera && aicamera)
|
||||
for(var/i in aicamera.stored)
|
||||
connected_ai.aicamera.stored[i] = TRUE
|
||||
for(var/i in connected_ai.aicamera.stored)
|
||||
aicamera.stored[i] = TRUE
|
||||
|
||||
@@ -385,9 +385,9 @@
|
||||
add_sensors()
|
||||
to_chat(src, "Sensor overlay activated.")
|
||||
|
||||
/mob/living/silicon/proc/GetPhoto()
|
||||
/mob/living/silicon/proc/GetPhoto(mob/user)
|
||||
if (aicamera)
|
||||
return aicamera.selectpicture(aicamera)
|
||||
return aicamera.selectpicture(user)
|
||||
|
||||
/mob/living/silicon/update_transform()
|
||||
var/matrix/ntransform = matrix(transform) //aka transform.Copy()
|
||||
|
||||
@@ -205,25 +205,37 @@
|
||||
var/old_eye_blurry = eye_blurry
|
||||
eye_blurry = max(amount, eye_blurry)
|
||||
if(!old_eye_blurry)
|
||||
overlay_fullscreen("blurry", /obj/screen/fullscreen/blurry)
|
||||
add_eyeblur()
|
||||
|
||||
/mob/proc/adjust_blurriness(amount)
|
||||
var/old_eye_blurry = eye_blurry
|
||||
eye_blurry = max(eye_blurry+amount, 0)
|
||||
if(amount>0)
|
||||
if(!old_eye_blurry)
|
||||
overlay_fullscreen("blurry", /obj/screen/fullscreen/blurry)
|
||||
add_eyeblur()
|
||||
else if(old_eye_blurry && !eye_blurry)
|
||||
clear_fullscreen("blurry")
|
||||
remove_eyeblur()
|
||||
|
||||
/mob/proc/set_blurriness(amount)
|
||||
var/old_eye_blurry = eye_blurry
|
||||
eye_blurry = max(amount, 0)
|
||||
if(amount>0)
|
||||
if(!old_eye_blurry)
|
||||
overlay_fullscreen("blurry", /obj/screen/fullscreen/blurry)
|
||||
add_eyeblur()
|
||||
else if(old_eye_blurry)
|
||||
clear_fullscreen("blurry")
|
||||
remove_eyeblur()
|
||||
|
||||
/mob/proc/add_eyeblur()
|
||||
var/obj/screen/plane_master/game_world/GW = locate(/obj/screen/plane_master/game_world) in client.screen
|
||||
var/obj/screen/plane_master/floor/F = locate(/obj/screen/plane_master/floor) in client.screen
|
||||
GW.add_filter("blurry_eyes", 2, EYE_BLUR)
|
||||
F.add_filter("blurry_eyes", 2, EYE_BLUR)
|
||||
|
||||
/mob/proc/remove_eyeblur()
|
||||
var/obj/screen/plane_master/game_world/GW = locate(/obj/screen/plane_master/game_world) in client.screen
|
||||
var/obj/screen/plane_master/floor/F = locate(/obj/screen/plane_master/floor) in client.screen
|
||||
GW.remove_filter("blurry_eyes")
|
||||
F.remove_filter("blurry_eyes")
|
||||
|
||||
/////////////////////////////////// DRUGGY ////////////////////////////////////
|
||||
|
||||
|
||||
@@ -94,30 +94,7 @@
|
||||
else if(photocopy)
|
||||
for(var/i = 0, i < copies, i++)
|
||||
if(toner >= 5 && !busy && photocopy) //Was set to = 0, but if there was say 3 toner left and this ran, you would get -2 which would be weird for ink
|
||||
var/obj/item/photo/p = new /obj/item/photo (loc)
|
||||
var/icon/I = icon(photocopy.icon, photocopy.icon_state)
|
||||
var/icon/img = icon(photocopy.img)
|
||||
if(greytoggle == "Greyscale")
|
||||
if(toner > 10) //plenty of toner, go straight greyscale
|
||||
I.MapColors(rgb(77,77,77), rgb(150,150,150), rgb(28,28,28), rgb(0,0,0)) //I'm not sure how expensive this is, but given the many limitations of photocopying, it shouldn't be an issue.
|
||||
img.MapColors(rgb(77,77,77), rgb(150,150,150), rgb(28,28,28), rgb(0,0,0))
|
||||
else //not much toner left, lighten the photo
|
||||
I.MapColors(rgb(77,77,77), rgb(150,150,150), rgb(28,28,28), rgb(100,100,100))
|
||||
img.MapColors(rgb(77,77,77), rgb(150,150,150), rgb(28,28,28), rgb(100,100,100))
|
||||
toner -= 5 //photos use a lot of ink!
|
||||
else if(greytoggle == "Color")
|
||||
if(toner >= 10)
|
||||
toner -= 10 //Color photos use even more ink!
|
||||
else
|
||||
continue
|
||||
p.icon = I
|
||||
p.img = img
|
||||
p.name = photocopy.name
|
||||
p.desc = photocopy.desc
|
||||
p.scribble = photocopy.scribble
|
||||
p.pixel_x = rand(-10, 10)
|
||||
p.pixel_y = rand(-10, 10)
|
||||
p.blueprints = photocopy.blueprints //a copy of a picture is still good enough for the syndicate
|
||||
new /obj/item/photo (loc, photocopy.picture.Copy(greytoggle == "Greyscale"? TRUE : FALSE))
|
||||
busy = TRUE
|
||||
sleep(15)
|
||||
busy = FALSE
|
||||
@@ -155,15 +132,10 @@
|
||||
else
|
||||
break
|
||||
var/obj/item/photo/p = new /obj/item/photo (loc)
|
||||
p.desc = "You see [ass]'s ass on the photo."
|
||||
p.pixel_x = rand(-10, 10)
|
||||
p.pixel_y = rand(-10, 10)
|
||||
p.img = temp_img
|
||||
var/icon/small_img = icon(temp_img) //Icon() is needed or else temp_img will be rescaled too >.>
|
||||
var/icon/ic = icon('icons/obj/items_and_weapons.dmi',"photo")
|
||||
small_img.Scale(8, 8)
|
||||
ic.Blend(small_img,ICON_OVERLAY, 13, 13)
|
||||
p.icon = ic
|
||||
p.picture = new(null, "You see [ass]'s ass on the photo.", temp_img)
|
||||
p.update_icon()
|
||||
toner -= 5
|
||||
busy = TRUE
|
||||
sleep(15)
|
||||
@@ -196,29 +168,14 @@
|
||||
if(!isAI(usr))
|
||||
return
|
||||
if(toner >= 5 && !busy)
|
||||
var/list/nametemp = list()
|
||||
var/find
|
||||
var/datum/picture/selection
|
||||
var/mob/living/silicon/ai/tempAI = usr
|
||||
if(tempAI.aicamera.aipictures.len == 0)
|
||||
if(tempAI.aicamera.stored.len == 0)
|
||||
to_chat(usr, "<span class='boldannounce'>No images saved</span>")
|
||||
return
|
||||
for(var/datum/picture/t in tempAI.aicamera.aipictures)
|
||||
nametemp += t.fields["name"]
|
||||
find = input("Select image (numbered in order taken)") in nametemp
|
||||
var/obj/item/photo/p = new /obj/item/photo (loc)
|
||||
for(var/datum/picture/q in tempAI.aicamera.aipictures)
|
||||
if(q.fields["name"] == find)
|
||||
selection = q
|
||||
break
|
||||
var/icon/I = selection.fields["icon"]
|
||||
var/icon/img = selection.fields["img"]
|
||||
p.icon = I
|
||||
p.img = img
|
||||
p.desc = selection.fields["desc"]
|
||||
p.blueprints = selection.fields["blueprints"]
|
||||
p.pixel_x = rand(-10, 10)
|
||||
p.pixel_y = rand(-10, 10)
|
||||
var/datum/picture/selection = tempAI.aicamera.selectpicture(usr)
|
||||
var/obj/item/photo = new(loc, selection)
|
||||
photo.pixel_x = rand(-10, 10)
|
||||
photo.pixel_y = rand(-10, 10)
|
||||
toner -= 5 //AI prints color pictures only, thus they can do it more efficiently
|
||||
busy = TRUE
|
||||
sleep(15)
|
||||
|
||||
@@ -1,661 +0,0 @@
|
||||
/* Photography!
|
||||
* Contains:
|
||||
* Camera
|
||||
* Camera Film
|
||||
* Photos
|
||||
* Photo Albums
|
||||
* Picture Frames
|
||||
* AI Photography
|
||||
*/
|
||||
|
||||
/*
|
||||
* Film
|
||||
*/
|
||||
/obj/item/camera_film
|
||||
name = "film cartridge"
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
desc = "A camera film cartridge. Insert it into a camera to reload it."
|
||||
icon_state = "film"
|
||||
item_state = "electropack"
|
||||
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
resistance_flags = FLAMMABLE
|
||||
materials = list(MAT_METAL = 10, MAT_GLASS = 10)
|
||||
|
||||
/*
|
||||
* Photo
|
||||
*/
|
||||
/obj/item/photo
|
||||
name = "photo"
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "photo"
|
||||
item_state = "paper"
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
resistance_flags = FLAMMABLE
|
||||
max_integrity = 50
|
||||
grind_results = list("iodine" = 4)
|
||||
var/icon/img //Big photo image
|
||||
var/scribble //Scribble on the back.
|
||||
var/blueprints = 0 //Does it include the blueprints?
|
||||
var/sillynewscastervar //Photo objects with this set to 1 will not be ejected by a newscaster. Only gets set to 1 if a silicon puts one of their images into a newscaster
|
||||
|
||||
/obj/item/photo/suicide_act(mob/living/carbon/user)
|
||||
user.visible_message("<span class='suicide'>[user] is taking one last look at \the [src]! It looks like [user.p_theyre()] giving in to death!</span>")//when you wanna look at photo of waifu one last time before you die...
|
||||
if (user.gender == MALE)
|
||||
playsound(user, 'sound/voice/human/manlaugh1.ogg', 50, 1)//EVERY TIME I DO IT MAKES ME LAUGH
|
||||
else if (user.gender == FEMALE)
|
||||
playsound(user, 'sound/voice/human/womanlaugh.ogg', 50, 1)
|
||||
return OXYLOSS
|
||||
|
||||
/obj/item/photo/attack_self(mob/user)
|
||||
user.examinate(src)
|
||||
|
||||
|
||||
/obj/item/photo/attackby(obj/item/P, mob/user, params)
|
||||
if(istype(P, /obj/item/pen) || istype(P, /obj/item/toy/crayon))
|
||||
if(!user.is_literate())
|
||||
to_chat(user, "<span class='notice'>You scribble illegibly on [src]!</span>")
|
||||
return
|
||||
var/txt = sanitize(input(user, "What would you like to write on the back?", "Photo Writing", null) as text)
|
||||
txt = copytext(txt, 1, 128)
|
||||
if(user.canUseTopic(src, BE_CLOSE))
|
||||
scribble = txt
|
||||
..()
|
||||
|
||||
|
||||
/obj/item/photo/examine(mob/user)
|
||||
..()
|
||||
|
||||
if(in_range(src, user))
|
||||
show(user)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You need to get closer to get a good look at this photo!</span>")
|
||||
|
||||
|
||||
/obj/item/photo/proc/show(mob/user)
|
||||
user << browse_rsc(img, "tmp_photo.png")
|
||||
user << browse("<html><head><title>[name]</title></head>" \
|
||||
+ "<body style='overflow:hidden;margin:0;text-align:center'>" \
|
||||
+ "<img src='tmp_photo.png' width='192' style='-ms-interpolation-mode:nearest-neighbor' />" \
|
||||
+ "[scribble ? "<br>Written on the back:<br><i>[scribble]</i>" : ""]"\
|
||||
+ "</body></html>", "window=book;size=192x[scribble ? 400 : 192]")
|
||||
onclose(user, "[name]")
|
||||
|
||||
|
||||
/obj/item/photo/verb/rename()
|
||||
set name = "Rename photo"
|
||||
set category = "Object"
|
||||
set src in usr
|
||||
|
||||
var/n_name = copytext(sanitize(input(usr, "What would you like to label the photo?", "Photo Labelling", null) as text), 1, MAX_NAME_LEN)
|
||||
//loc.loc check is for making possible renaming photos in clipboards
|
||||
if((loc == usr || loc.loc && loc.loc == usr) && usr.stat == CONSCIOUS && usr.canmove && !usr.restrained())
|
||||
name = "photo[(n_name ? text("- '[n_name]'") : null)]"
|
||||
add_fingerprint(usr)
|
||||
|
||||
/obj/item/photo/proc/photocreate(inicon, inimg, indesc, inblueprints)
|
||||
icon = inicon
|
||||
img = inimg
|
||||
desc = indesc
|
||||
blueprints = inblueprints
|
||||
|
||||
/*
|
||||
* Photo album
|
||||
*/
|
||||
/obj/item/storage/photo_album
|
||||
name = "photo album"
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "album"
|
||||
item_state = "briefcase"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/briefcase_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/briefcase_righthand.dmi'
|
||||
resistance_flags = FLAMMABLE
|
||||
|
||||
/obj/item/storage/photo_album/Initialize()
|
||||
. = ..()
|
||||
GET_COMPONENT(STR, /datum/component/storage)
|
||||
STR.can_hold = typecacheof(list(/obj/item/photo))
|
||||
|
||||
/*
|
||||
* Camera
|
||||
*/
|
||||
/obj/item/camera
|
||||
name = "camera"
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
desc = "A polaroid camera."
|
||||
icon_state = "camera"
|
||||
item_state = "electropack"
|
||||
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
flags_1 = CONDUCT_1
|
||||
slot_flags = ITEM_SLOT_BELT
|
||||
materials = list(MAT_METAL = 50, MAT_GLASS = 150)
|
||||
var/pictures_max = 10
|
||||
var/pictures_left = 10
|
||||
var/on = TRUE
|
||||
var/blueprints = 0 //are blueprints visible in the current photo being created?
|
||||
var/list/aipictures = list() //Allows for storage of pictures taken by AI, in a similar manner the datacore stores info. Keeping this here allows us to share some procs w/ regualar camera
|
||||
var/see_ghosts = 0 //for the spoop of it
|
||||
var/obj/item/disk/holodisk/disk
|
||||
|
||||
|
||||
/obj/item/camera/CheckParts(list/parts_list)
|
||||
..()
|
||||
var/obj/item/camera/C = locate(/obj/item/camera) in contents
|
||||
if(C)
|
||||
pictures_max = C.pictures_max
|
||||
pictures_left = C.pictures_left
|
||||
visible_message("[C] has been imbued with godlike power!")
|
||||
qdel(C)
|
||||
|
||||
|
||||
/obj/item/camera/spooky
|
||||
name = "camera obscura"
|
||||
desc = "A polaroid camera, some say it can see ghosts!"
|
||||
see_ghosts = 1
|
||||
|
||||
/obj/item/camera/detective
|
||||
name = "Detective's camera"
|
||||
desc = "A polaroid camera with extra capacity for crime investigations."
|
||||
pictures_max = 30
|
||||
pictures_left = 30
|
||||
|
||||
|
||||
/obj/item/camera/siliconcam //camera AI can take pictures with
|
||||
name = "silicon photo camera"
|
||||
var/in_camera_mode = 0
|
||||
|
||||
/obj/item/camera/siliconcam/ai_camera //camera AI can take pictures with
|
||||
name = "AI photo camera"
|
||||
|
||||
/obj/item/camera/siliconcam/robot_camera //camera cyborgs can take pictures with.. needs it's own because of verb CATEGORY >.>
|
||||
name = "Cyborg photo camera"
|
||||
|
||||
/obj/item/camera/siliconcam/robot_camera/verb/borgprinting()
|
||||
set category ="Robot Commands"
|
||||
set name = "Print Image"
|
||||
set src in usr
|
||||
|
||||
if(usr.stat == DEAD)
|
||||
return //won't work if dead
|
||||
borgprint()
|
||||
|
||||
/obj/item/camera/attack(mob/living/carbon/human/M, mob/user)
|
||||
return
|
||||
|
||||
|
||||
/obj/item/camera/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/camera_film))
|
||||
if(pictures_left)
|
||||
to_chat(user, "<span class='notice'>[src] still has some film in it!</span>")
|
||||
return
|
||||
if(!user.temporarilyRemoveItemFromInventory(I))
|
||||
return
|
||||
to_chat(user, "<span class='notice'>You insert [I] into [src].</span>")
|
||||
qdel(I)
|
||||
pictures_left = pictures_max
|
||||
return
|
||||
if(istype(I, /obj/item/disk/holodisk))
|
||||
if (!disk)
|
||||
if(!user.transferItemToLoc(I, src))
|
||||
to_chat(user, "<span class='warning'>[I] is stuck to your hand!</span>")
|
||||
return TRUE
|
||||
to_chat(user, "<span class='notice'>You slide [I] into the back of [src].</span>")
|
||||
disk = I
|
||||
else
|
||||
to_chat(user, "<span class='warning'>There's already a disk inside [src].</span>")
|
||||
return TRUE //no afterattack
|
||||
..()
|
||||
|
||||
/obj/item/camera/attack_self(mob/user)
|
||||
if(!disk)
|
||||
return
|
||||
to_chat(user, "<span class='notice'>You eject [disk] out the back of [src].</span>")
|
||||
user.put_in_hands(disk)
|
||||
disk = null
|
||||
|
||||
/obj/item/camera/examine(mob/user)
|
||||
..()
|
||||
to_chat(user, "It has [pictures_left] photo\s left.")
|
||||
|
||||
|
||||
/obj/item/camera/proc/camera_get_icon(list/turfs, turf/center)
|
||||
var/list/atoms = list()
|
||||
for(var/turf/T in turfs)
|
||||
atoms.Add(T)
|
||||
for(var/atom/movable/A in T)
|
||||
if(A.invisibility)
|
||||
if(see_ghosts && isobserver(A))
|
||||
var/mob/dead/observer/O = A
|
||||
if(O.orbiting) //so you dont see ghosts following people like antags, etc.
|
||||
continue
|
||||
else
|
||||
continue
|
||||
atoms.Add(A)
|
||||
|
||||
var/list/sorted = sortTim(atoms,/proc/cmp_atom_layer_asc)
|
||||
|
||||
var/icon/res = icon('icons/effects/96x96.dmi', "")
|
||||
|
||||
for(var/atom/A in sorted)
|
||||
var/icon/img = getFlatIcon(A, no_anim = TRUE)
|
||||
if(isliving(A))
|
||||
var/mob/living/L = A
|
||||
if(L.lying)
|
||||
img.Turn(L.lying)
|
||||
|
||||
var/offX = world.icon_size * (A.x - center.x) + A.pixel_x + 33
|
||||
var/offY = world.icon_size * (A.y - center.y) + A.pixel_y + 33
|
||||
if(ismovableatom(A))
|
||||
var/atom/movable/AM = A
|
||||
offX += AM.step_x
|
||||
offY += AM.step_y
|
||||
|
||||
res.Blend(img, blendMode2iconMode(A.blend_mode), offX, offY)
|
||||
|
||||
if(istype(A, /obj/item/areaeditor/blueprints))
|
||||
blueprints = 1
|
||||
|
||||
for(var/turf/T in turfs)
|
||||
var/area/A = T.loc
|
||||
if(A.icon_state)//There's actually something to blend in.
|
||||
res.Blend(getFlatIcon(A,no_anim = TRUE), blendMode2iconMode(A.blend_mode), world.icon_size * (T.x - center.x) + 33, world.icon_size * (T.y - center.y) + 33)
|
||||
|
||||
return res
|
||||
|
||||
|
||||
/obj/item/camera/proc/camera_get_mobs(turf/the_turf)
|
||||
var/mob_detail
|
||||
for(var/mob/M in the_turf)
|
||||
if(M.invisibility)
|
||||
if(see_ghosts && isobserver(M))
|
||||
var/mob/dead/observer/O = M
|
||||
if(O.orbiting)
|
||||
continue
|
||||
if(!mob_detail)
|
||||
mob_detail = "You can see a g-g-g-g-ghooooost! "
|
||||
else
|
||||
mob_detail += "You can also see a g-g-g-g-ghooooost!"
|
||||
else
|
||||
continue
|
||||
|
||||
var/list/holding = list()
|
||||
|
||||
if(isliving(M))
|
||||
var/mob/living/L = M
|
||||
|
||||
for(var/obj/item/I in L.held_items)
|
||||
if(!holding)
|
||||
holding += "[L.p_theyre(TRUE)] holding \a [I]"
|
||||
else
|
||||
holding += " and \a [I]"
|
||||
holding = holding.Join()
|
||||
|
||||
if(!mob_detail)
|
||||
mob_detail = "You can see [L] on the photo[L.health < (L.maxHealth * 0.75) ? " - [L] looks hurt":""].[holding ? " [holding]":"."]. "
|
||||
else
|
||||
mob_detail += "You can also see [L] on the photo[L.health < (L.maxHealth * 0.75) ? " - [L] looks hurt":""].[holding ? " [holding]":"."]."
|
||||
|
||||
|
||||
return mob_detail
|
||||
|
||||
|
||||
/obj/item/camera/proc/captureimage(atom/target, mob/user, flag) //Proc for both regular and AI-based camera to take the image
|
||||
var/mobs = ""
|
||||
var/isAi = isAI(user)
|
||||
var/list/seen
|
||||
if(!isAi) //crappy check, but without it AI photos would be subject to line of sight from the AI Eye object. Made the best of it by moving the sec camera check inside
|
||||
if(user.client) //To make shooting through security cameras possible
|
||||
seen = get_hear(world.view, user.client.eye) //To make shooting through security cameras possible
|
||||
else
|
||||
seen = get_hear(world.view, user)
|
||||
else
|
||||
seen = get_hear(world.view, target)
|
||||
|
||||
var/list/turfs = list()
|
||||
for(var/turf/T in range(1, target))
|
||||
if(T in seen)
|
||||
if(isAi && !GLOB.cameranet.checkTurfVis(T))
|
||||
continue
|
||||
else
|
||||
turfs += T
|
||||
mobs += camera_get_mobs(T)
|
||||
|
||||
var/icon/temp = icon('icons/effects/96x96.dmi',"")
|
||||
temp.Blend("#000", ICON_OVERLAY)
|
||||
temp.Blend(camera_get_icon(turfs, target), ICON_OVERLAY)
|
||||
|
||||
if(!issilicon(user))
|
||||
printpicture(user, temp, mobs, flag)
|
||||
else
|
||||
aipicture(user, temp, mobs, isAi, blueprints)
|
||||
|
||||
|
||||
|
||||
|
||||
/obj/item/camera/proc/printpicture(mob/user, icon/temp, mobs, flag) //Normal camera proc for creating photos
|
||||
var/obj/item/photo/P = new/obj/item/photo(get_turf(src))
|
||||
if(in_range(src, user)) //needed because of TK
|
||||
user.put_in_hands(P)
|
||||
var/icon/small_img = icon(temp)
|
||||
var/icon/ic = icon('icons/obj/items_and_weapons.dmi',"photo")
|
||||
small_img.Scale(8, 8)
|
||||
ic.Blend(small_img,ICON_OVERLAY, 13, 13)
|
||||
P.icon = ic
|
||||
P.img = temp
|
||||
P.desc = mobs
|
||||
P.pixel_x = rand(-10, 10)
|
||||
P.pixel_y = rand(-10, 10)
|
||||
|
||||
if(blueprints)
|
||||
P.blueprints = 1
|
||||
blueprints = 0
|
||||
|
||||
|
||||
/obj/item/camera/proc/aipicture(mob/user, icon/temp, mobs, isAi) //instead of printing a picture like a regular camera would, we do this instead for the AI
|
||||
|
||||
var/icon/small_img = icon(temp)
|
||||
var/icon/ic = icon('icons/obj/items_and_weapons.dmi',"photo")
|
||||
small_img.Scale(8, 8)
|
||||
ic.Blend(small_img,ICON_OVERLAY, 13, 13)
|
||||
var/icon = ic
|
||||
var/img = temp
|
||||
var/desc = mobs
|
||||
var/pixel_x = rand(-10, 10)
|
||||
var/pixel_y = rand(-10, 10)
|
||||
|
||||
var/injectblueprints = 1
|
||||
if(blueprints)
|
||||
injectblueprints = 1
|
||||
blueprints = 0
|
||||
|
||||
if(isAi)
|
||||
injectaialbum(icon, img, desc, pixel_x, pixel_y, injectblueprints)
|
||||
else
|
||||
injectmasteralbum(icon, img, desc, pixel_x, pixel_y, injectblueprints)
|
||||
|
||||
|
||||
|
||||
/datum/picture
|
||||
var/name = "image"
|
||||
var/list/fields = list()
|
||||
|
||||
|
||||
/obj/item/camera/proc/injectaialbum(icon, img, desc, pixel_x, pixel_y, blueprintsinject) //stores image information to a list similar to that of the datacore
|
||||
var/numberer = 1
|
||||
for(var/datum/picture in src.aipictures)
|
||||
numberer++
|
||||
var/datum/picture/P = new()
|
||||
P.fields["name"] = "Image [numberer] (taken by [src.loc.name])"
|
||||
P.fields["icon"] = icon
|
||||
P.fields["img"] = img
|
||||
P.fields["desc"] = desc
|
||||
P.fields["pixel_x"] = pixel_x
|
||||
P.fields["pixel_y"] = pixel_y
|
||||
P.fields["blueprints"] = blueprintsinject
|
||||
|
||||
aipictures += P
|
||||
to_chat(usr, "<span class='unconscious'>Image recorded</span>") //feedback to the AI player that the picture was taken
|
||||
|
||||
/obj/item/camera/proc/injectmasteralbum(icon, img, desc, pixel_x, pixel_y, blueprintsinject) //stores image information to a list similar to that of the datacore
|
||||
var/numberer = 1
|
||||
var/mob/living/silicon/robot/C = src.loc
|
||||
if(C.connected_ai)
|
||||
for(var/datum/picture in C.connected_ai.aicamera.aipictures)
|
||||
numberer++
|
||||
var/datum/picture/P = new()
|
||||
P.fields["name"] = "Image [numberer] (taken by [src.loc.name])"
|
||||
P.fields["icon"] = icon
|
||||
P.fields["img"] = img
|
||||
P.fields["desc"] = desc
|
||||
P.fields["pixel_x"] = pixel_x
|
||||
P.fields["pixel_y"] = pixel_y
|
||||
P.fields["blueprints"] = blueprintsinject
|
||||
|
||||
C.connected_ai.aicamera.aipictures += P
|
||||
to_chat(usr, "<span class='unconscious'>Image recorded and saved to remote database</span>") //feedback to the Cyborg player that the picture was taken
|
||||
else
|
||||
injectaialbum(icon, img, desc, pixel_x, pixel_y, blueprintsinject)
|
||||
|
||||
/obj/item/camera/siliconcam/proc/selectpicture(obj/item/camera/siliconcam/targetloc)
|
||||
var/list/nametemp = list()
|
||||
var/find
|
||||
if(targetloc.aipictures.len == 0)
|
||||
to_chat(usr, "<span class='boldannounce'>No images saved</span>")
|
||||
return
|
||||
for(var/datum/picture/t in targetloc.aipictures)
|
||||
nametemp += t.fields["name"]
|
||||
find = input("Select image (numbered in order taken)") in nametemp
|
||||
for(var/datum/picture/q in targetloc.aipictures)
|
||||
if(q.fields["name"] == find)
|
||||
return q
|
||||
|
||||
/obj/item/camera/siliconcam/proc/viewpichelper(obj/item/camera/siliconcam/targetloc)
|
||||
var/obj/item/photo/P = new/obj/item/photo()
|
||||
var/datum/picture/selection = selectpicture(targetloc)
|
||||
if(selection)
|
||||
P.photocreate(selection.fields["icon"], selection.fields["img"], selection.fields["desc"])
|
||||
P.pixel_x = selection.fields["pixel_x"]
|
||||
P.pixel_y = selection.fields["pixel_y"]
|
||||
|
||||
P.show(usr)
|
||||
to_chat(usr, P.desc)
|
||||
qdel(P) //so 10 thousand picture items are not left in memory should an AI take them and then view them all
|
||||
|
||||
/obj/item/camera/siliconcam/proc/viewpictures(user)
|
||||
if(iscyborg(user)) // Cyborg
|
||||
var/mob/living/silicon/robot/C = src.loc
|
||||
var/obj/item/camera/siliconcam/Cinfo
|
||||
if(C.connected_ai)
|
||||
Cinfo = C.connected_ai.aicamera
|
||||
viewpichelper(Cinfo)
|
||||
else
|
||||
Cinfo = C.aicamera
|
||||
viewpichelper(Cinfo)
|
||||
else // AI
|
||||
var/Ainfo = src
|
||||
viewpichelper(Ainfo)
|
||||
|
||||
/obj/item/camera/afterattack(atom/target, mob/user, flag)
|
||||
if(!on || !pictures_left || !isturf(target.loc))
|
||||
return
|
||||
if (disk)
|
||||
if(ismob(target))
|
||||
if (disk.record)
|
||||
QDEL_NULL(disk.record)
|
||||
|
||||
disk.record = new
|
||||
var/mob/M = target
|
||||
disk.record.caller_name = M.name
|
||||
disk.record.set_caller_image(M)
|
||||
else
|
||||
return
|
||||
else
|
||||
captureimage(target, user, flag)
|
||||
pictures_left--
|
||||
to_chat(user, "<span class='notice'>[pictures_left] photos left.</span>")
|
||||
|
||||
playsound(loc, pick('sound/items/polaroid1.ogg', 'sound/items/polaroid2.ogg'), 75, 1, -3)
|
||||
|
||||
icon_state = "camera_off"
|
||||
on = FALSE
|
||||
addtimer(CALLBACK(src, .proc/cooldown), 64)
|
||||
|
||||
/obj/item/camera/proc/cooldown()
|
||||
set waitfor = FALSE
|
||||
icon_state = "camera"
|
||||
on = TRUE
|
||||
|
||||
/obj/item/camera/siliconcam/proc/toggle_camera_mode()
|
||||
if(in_camera_mode)
|
||||
camera_mode_off()
|
||||
else
|
||||
camera_mode_on()
|
||||
|
||||
/obj/item/camera/siliconcam/proc/camera_mode_off()
|
||||
src.in_camera_mode = 0
|
||||
to_chat(usr, "<B>Camera Mode deactivated</B>")
|
||||
|
||||
/obj/item/camera/siliconcam/proc/camera_mode_on()
|
||||
src.in_camera_mode = 1
|
||||
to_chat(usr, "<B>Camera Mode activated</B>")
|
||||
|
||||
/obj/item/camera/siliconcam/robot_camera/proc/borgprint()
|
||||
var/list/nametemp = list()
|
||||
var/find
|
||||
var/datum/picture/selection
|
||||
var/mob/living/silicon/robot/C = src.loc
|
||||
var/obj/item/camera/siliconcam/targetcam = null
|
||||
if(C.toner < 20)
|
||||
to_chat(usr, "Insufficent toner to print image.")
|
||||
return
|
||||
if(C.connected_ai)
|
||||
targetcam = C.connected_ai.aicamera
|
||||
else
|
||||
targetcam = C.aicamera
|
||||
if(targetcam.aipictures.len == 0)
|
||||
to_chat(usr, "<span class='userdanger'>No images saved</span>")
|
||||
return
|
||||
for(var/datum/picture/t in targetcam.aipictures)
|
||||
nametemp += t.fields["name"]
|
||||
find = input("Select image (numbered in order taken)") in nametemp
|
||||
for(var/datum/picture/q in targetcam.aipictures)
|
||||
if(q.fields["name"] == find)
|
||||
selection = q
|
||||
break
|
||||
var/obj/item/photo/p = new /obj/item/photo(C.loc)
|
||||
p.photocreate(selection.fields["icon"], selection.fields["img"], selection.fields["desc"], selection.fields["blueprints"])
|
||||
p.pixel_x = rand(-10, 10)
|
||||
p.pixel_y = rand(-10, 10)
|
||||
C.toner -= 20 //Cyborgs are very ineffeicient at printing an image
|
||||
visible_message("[C.name] spits out a photograph from a narrow slot on its chassis.")
|
||||
to_chat(usr, "<span class='notice'>You print a photograph.</span>")
|
||||
|
||||
// Picture frames
|
||||
|
||||
/obj/item/wallframe/picture
|
||||
name = "picture frame"
|
||||
desc = "The perfect showcase for your favorite deathtrap memories."
|
||||
icon = 'icons/obj/decals.dmi'
|
||||
materials = list()
|
||||
flags_1 = 0
|
||||
icon_state = "frame-empty"
|
||||
result_path = /obj/structure/sign/picture_frame
|
||||
var/obj/item/photo/displayed
|
||||
|
||||
/obj/item/wallframe/picture/attackby(obj/item/I, mob/user)
|
||||
if(istype(I, /obj/item/photo))
|
||||
if(!displayed)
|
||||
if(!user.transferItemToLoc(I, src))
|
||||
return
|
||||
displayed = I
|
||||
update_icon()
|
||||
else
|
||||
to_chat(user, "<span class=notice>\The [src] already contains a photo.</span>")
|
||||
..()
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/obj/item/wallframe/picture/attack_hand(mob/user)
|
||||
if(user.get_inactive_held_item() != src)
|
||||
..()
|
||||
return
|
||||
if(contents.len)
|
||||
var/obj/item/I = pick(contents)
|
||||
user.put_in_hands(I)
|
||||
to_chat(user, "<span class='notice'>You carefully remove the photo from \the [src].</span>")
|
||||
displayed = null
|
||||
update_icon()
|
||||
return ..()
|
||||
|
||||
/obj/item/wallframe/picture/attack_self(mob/user)
|
||||
user.examinate(src)
|
||||
|
||||
/obj/item/wallframe/picture/examine(mob/user)
|
||||
if(user.is_holding(src) && displayed)
|
||||
displayed.show(user)
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/item/wallframe/picture/update_icon()
|
||||
cut_overlays()
|
||||
if(displayed)
|
||||
add_overlay(getFlatIcon(displayed))
|
||||
|
||||
/obj/item/wallframe/picture/after_attach(obj/O)
|
||||
..()
|
||||
var/obj/structure/sign/picture_frame/PF = O
|
||||
PF.copy_overlays(src)
|
||||
if(displayed)
|
||||
PF.framed = displayed
|
||||
if(contents.len)
|
||||
var/obj/item/I = pick(contents)
|
||||
I.forceMove(PF)
|
||||
|
||||
|
||||
/obj/structure/sign/picture_frame
|
||||
name = "picture frame"
|
||||
desc = "Every time you look it makes you laugh."
|
||||
icon = 'icons/obj/decals.dmi'
|
||||
icon_state = "frame-empty"
|
||||
var/obj/item/photo/framed
|
||||
|
||||
/obj/structure/sign/picture_frame/New(loc, dir, building)
|
||||
..()
|
||||
if(dir)
|
||||
setDir(dir)
|
||||
if(building)
|
||||
pixel_x = (dir & 3)? 0 : (dir == 4 ? -30 : 30)
|
||||
pixel_y = (dir & 3)? (dir ==1 ? -30 : 30) : 0
|
||||
|
||||
/obj/structure/sign/picture_frame/examine(mob/user)
|
||||
if(in_range(src, user) && framed)
|
||||
framed.show(user)
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/structure/sign/picture_frame/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/screwdriver) || istype(I, /obj/item/wrench))
|
||||
to_chat(user, "<span class='notice'>You start unsecuring [name]...</span>")
|
||||
if(I.use_tool(src, user, 30, volume=50))
|
||||
playsound(loc, 'sound/items/deconstruct.ogg', 50, 1)
|
||||
to_chat(user, "<span class='notice'>You unsecure [name].</span>")
|
||||
deconstruct()
|
||||
return
|
||||
|
||||
else if(istype(I, /obj/item/photo))
|
||||
if(!framed)
|
||||
var/obj/item/photo/P = I
|
||||
if(!user.transferItemToLoc(P, src))
|
||||
return
|
||||
framed = P
|
||||
update_icon()
|
||||
else
|
||||
to_chat(user, "<span class=notice>\The [src] already contains a photo.</span>")
|
||||
|
||||
..()
|
||||
|
||||
/obj/structure/sign/picture_frame/attack_hand(mob/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(framed)
|
||||
framed.show(user)
|
||||
|
||||
/obj/structure/sign/picture_frame/update_icon()
|
||||
cut_overlays()
|
||||
if(framed)
|
||||
add_overlay(getFlatIcon(framed))
|
||||
|
||||
/obj/structure/sign/picture_frame/deconstruct(disassembled = TRUE)
|
||||
if(!(flags_1 & NODECONSTRUCT_1))
|
||||
var/obj/item/wallframe/picture/F = new /obj/item/wallframe/picture(loc)
|
||||
if(framed)
|
||||
F.displayed = framed
|
||||
framed = null
|
||||
if(contents.len)
|
||||
var/obj/item/I = pick(contents)
|
||||
I.forceMove(F)
|
||||
F.update_icon()
|
||||
qdel(src)
|
||||
@@ -0,0 +1,163 @@
|
||||
/datum/picture
|
||||
var/picture_name = "picture"
|
||||
var/picture_desc = "This is a picture."
|
||||
var/caption
|
||||
var/icon/picture_image
|
||||
var/icon/picture_icon
|
||||
var/psize_x = 0
|
||||
var/psize_y = 0
|
||||
var/has_blueprints = FALSE
|
||||
var/logpath //If the picture has been logged this is the path.
|
||||
var/id //this var is NOT protected because the worst you can do with this that you couldn't do otherwise is overwrite photos, and photos aren't going to be used as attack logs/investigations anytime soon.
|
||||
|
||||
/datum/picture/New(name = "picture", desc = "This is a picture. A bugged one. Report it to coderbus!", image, icon, size_x = 96, size_y = 96, bp = FALSE, caption_, autogenerate_icon = FALSE)
|
||||
picture_name = name
|
||||
picture_desc = desc
|
||||
picture_image = image
|
||||
picture_icon = icon
|
||||
psize_x = size_x
|
||||
psize_y = size_y
|
||||
has_blueprints = bp
|
||||
caption = caption_
|
||||
if(autogenerate_icon && !picture_icon && picture_image)
|
||||
regenerate_small_icon()
|
||||
|
||||
/datum/picture/proc/get_small_icon()
|
||||
if(!picture_icon)
|
||||
regenerate_small_icon()
|
||||
return picture_icon
|
||||
|
||||
/datum/picture/proc/regenerate_small_icon()
|
||||
if(!picture_image)
|
||||
return
|
||||
var/icon/small_img = icon(picture_image)
|
||||
var/icon/ic = icon('icons/obj/items_and_weapons.dmi', "photo")
|
||||
small_img.Scale(8, 8)
|
||||
ic.Blend(small_img,ICON_OVERLAY, 13, 13)
|
||||
picture_icon = ic
|
||||
|
||||
/datum/picture/serialize_list(list/options)
|
||||
. = list()
|
||||
.["id"] = id
|
||||
.["desc"] = picture_desc
|
||||
.["name"] = picture_name
|
||||
.["caption"] = caption
|
||||
.["pixel_size_x"] = psize_x
|
||||
.["pixel_size_y"] = psize_y
|
||||
.["blueprints"] = has_blueprints
|
||||
.["logpath"] = logpath
|
||||
|
||||
/datum/picture/deserialize_list(list/input, list/options)
|
||||
if(!input["logpath"] || !fexists(input["logpath"]) || !input["id"] || !input["pixel_size_x"] || !input["pixel_size_y"])
|
||||
return
|
||||
picture_image = icon(file(input["logpath"]))
|
||||
logpath = input["logpath"]
|
||||
id = input["id"]
|
||||
psize_x = input["pixel_size_x"]
|
||||
psize_y = input["pixel_size_y"]
|
||||
if(input["blueprints"])
|
||||
has_blueprints = input["blueprints"]
|
||||
if(input["caption"])
|
||||
caption = input["caption"]
|
||||
if(input["desc"])
|
||||
picture_desc = input["desc"]
|
||||
if(input["name"])
|
||||
picture_name = input["name"]
|
||||
return src
|
||||
|
||||
/proc/load_photo_from_disk(id, location)
|
||||
var/datum/picture/P = load_picture_from_disk(id)
|
||||
if(istype(P))
|
||||
var/obj/item/photo/p = new(location, P)
|
||||
return p
|
||||
|
||||
/proc/load_picture_from_disk(id)
|
||||
var/pathstring = log_path_from_picture_ID(id)
|
||||
if(!pathstring)
|
||||
return
|
||||
var/path = file(pathstring)
|
||||
if(!fexists(path))
|
||||
return
|
||||
var/dir_index = findlasttext(pathstring, "/")
|
||||
var/dir = copytext(pathstring, 1, dir_index)
|
||||
var/json_path = file("[dir]/metadata.json")
|
||||
if(!fexists(json_path))
|
||||
return
|
||||
var/list/json = json_decode(file2text(json_path))
|
||||
if(!json[id])
|
||||
return
|
||||
var/datum/picture/P = new
|
||||
P.deserialize_json(json[id])
|
||||
return P
|
||||
|
||||
/proc/log_path_from_picture_ID(id)
|
||||
if(!istext(id))
|
||||
return
|
||||
. = "data/picture_logs/"
|
||||
var/list/data = splittext(id, "_")
|
||||
if(data.len < 3)
|
||||
return null
|
||||
var/mode = data[1]
|
||||
switch(mode)
|
||||
if("L")
|
||||
if(data.len < 5)
|
||||
return null
|
||||
var/timestamp = data[2]
|
||||
var/year = copytext(timestamp, 1, 5)
|
||||
var/month = copytext(timestamp, 5, 7)
|
||||
var/day = copytext(timestamp, 7, 9)
|
||||
var/round = data[4]
|
||||
. += "[year]/[month]/[day]/round-[round]"
|
||||
if("O")
|
||||
var/list/path = data.Copy(2, data.len)
|
||||
. += path.Join("")
|
||||
else
|
||||
return null
|
||||
var/n = data[data.len]
|
||||
. += "/[n].png"
|
||||
|
||||
//BE VERY CAREFUL WITH THIS PROC, TO AVOID DUPLICATION.
|
||||
/datum/picture/proc/log_to_file()
|
||||
if(!picture_image)
|
||||
return
|
||||
if(!CONFIG_GET(flag/log_pictures))
|
||||
return
|
||||
if(logpath)
|
||||
return //we're already logged
|
||||
var/number = GLOB.picture_logging_id++
|
||||
var/finalpath = "[GLOB.picture_log_directory]/[number].png"
|
||||
fcopy(icon(picture_image, dir = SOUTH, frame = 1), finalpath)
|
||||
logpath = finalpath
|
||||
id = "[GLOB.picture_logging_prefix][number]"
|
||||
var/jsonpath = "[GLOB.picture_log_directory]/metadata.json"
|
||||
jsonpath = file(jsonpath)
|
||||
var/list/json
|
||||
if(fexists(jsonpath))
|
||||
json = json_decode(file2text(jsonpath))
|
||||
fdel(jsonpath)
|
||||
else
|
||||
json = list()
|
||||
json[id] = serialize_json()
|
||||
WRITE_FILE(jsonpath, json_encode(json))
|
||||
|
||||
/datum/picture/proc/Copy(greyscale = FALSE, cropx = 0, cropy = 0)
|
||||
var/datum/picture/P = new
|
||||
P.picture_name = picture_name
|
||||
P.picture_desc = picture_desc
|
||||
if(picture_image)
|
||||
P.picture_image = icon(picture_image) //Copy, not reference.
|
||||
if(picture_icon)
|
||||
P.picture_icon = icon(picture_icon)
|
||||
P.psize_x = psize_x - cropx * 2
|
||||
P.psize_y = psize_y - cropy * 2
|
||||
P.has_blueprints = has_blueprints
|
||||
if(greyscale)
|
||||
if(picture_image)
|
||||
P.picture_image.MapColors(rgb(77,77,77), rgb(150,150,150), rgb(28,28,28), rgb(0,0,0))
|
||||
if(picture_icon)
|
||||
P.picture_icon.MapColors(rgb(77,77,77), rgb(150,150,150), rgb(28,28,28), rgb(0,0,0))
|
||||
if(cropx || cropy)
|
||||
if(picture_image)
|
||||
P.picture_image.Crop(cropx, cropy, psize_x - cropx, psize_y - cropy)
|
||||
P.regenerate_small_icon()
|
||||
return P
|
||||
@@ -0,0 +1,221 @@
|
||||
|
||||
#define CAMERA_PICTURE_SIZE_HARD_LIMIT 21
|
||||
|
||||
/obj/item/camera
|
||||
name = "camera"
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
desc = "A polaroid camera."
|
||||
icon_state = "camera"
|
||||
item_state = "electropack"
|
||||
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
flags_1 = CONDUCT_1
|
||||
slot_flags = ITEM_SLOT_BELT
|
||||
materials = list(MAT_METAL = 50, MAT_GLASS = 150)
|
||||
var/state_on = "camera"
|
||||
var/state_off = "camera_off"
|
||||
var/pictures_max = 10
|
||||
var/pictures_left = 10
|
||||
var/on = TRUE
|
||||
var/cooldown = 64
|
||||
var/blending = FALSE //lets not take pictures while the previous is still processing!
|
||||
var/see_ghosts = CAMERA_NO_GHOSTS //for the spoop of it
|
||||
var/obj/item/disk/holodisk/disk
|
||||
var/sound/custom_sound
|
||||
var/silent = FALSE
|
||||
var/picture_size_x = 1
|
||||
var/picture_size_y = 1
|
||||
var/picture_size_x_min = 0
|
||||
var/picture_size_y_min = 0
|
||||
var/picture_size_x_max = 3
|
||||
var/picture_size_y_max = 3
|
||||
|
||||
/obj/item/camera/CheckParts(list/parts_list)
|
||||
..()
|
||||
var/obj/item/camera/C = locate(/obj/item/camera) in contents
|
||||
if(C)
|
||||
pictures_max = C.pictures_max
|
||||
pictures_left = C.pictures_left
|
||||
visible_message("[C] has been imbued with godlike power!")
|
||||
qdel(C)
|
||||
|
||||
/obj/item/camera/attack_self(mob/user)
|
||||
if(!disk)
|
||||
return
|
||||
to_chat(user, "<span class='notice'>You eject [disk] out the back of [src].</span>")
|
||||
user.put_in_hands(disk)
|
||||
disk = null
|
||||
|
||||
/obj/item/camera/AltClick(mob/user)
|
||||
var/desired_x = input(user, "How high do you want the camera to shoot, between [picture_size_x_min] and [picture_size_x_max]?", "Zoom", picture_size_x) as num
|
||||
var/desired_y = input(user, "How wide do you want the camera to shoot, between [picture_size_y_min] and [picture_size_y_max]?", "Zoom", picture_size_y) as num
|
||||
desired_x = min(CLAMP(desired_x, picture_size_x_min, picture_size_x_max), CAMERA_PICTURE_SIZE_HARD_LIMIT)
|
||||
desired_y = min(CLAMP(desired_y, picture_size_y_min, picture_size_y_max), CAMERA_PICTURE_SIZE_HARD_LIMIT)
|
||||
if(user.canUseTopic(src))
|
||||
picture_size_x = desired_x
|
||||
picture_size_y = desired_y
|
||||
|
||||
/obj/item/camera/attack(mob/living/carbon/human/M, mob/user)
|
||||
return
|
||||
|
||||
/obj/item/camera/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/camera_film))
|
||||
if(pictures_left)
|
||||
to_chat(user, "<span class='notice'>[src] still has some film in it!</span>")
|
||||
return
|
||||
if(!user.temporarilyRemoveItemFromInventory(I))
|
||||
return
|
||||
to_chat(user, "<span class='notice'>You insert [I] into [src].</span>")
|
||||
qdel(I)
|
||||
pictures_left = pictures_max
|
||||
return
|
||||
if(istype(I, /obj/item/disk/holodisk))
|
||||
if (!disk)
|
||||
if(!user.transferItemToLoc(I, src))
|
||||
to_chat(user, "<span class='warning'>[I] is stuck to your hand!</span>")
|
||||
return TRUE
|
||||
to_chat(user, "<span class='notice'>You slide [I] into the back of [src].</span>")
|
||||
disk = I
|
||||
else
|
||||
to_chat(user, "<span class='warning'>There's already a disk inside [src].</span>")
|
||||
return TRUE //no afterattack
|
||||
..()
|
||||
|
||||
/obj/item/camera/examine(mob/user)
|
||||
..()
|
||||
to_chat(user, "It has [pictures_left] photos left.")
|
||||
|
||||
/obj/item/camera/proc/can_target(atom/target, mob/user, prox_flag)
|
||||
if(!on || blending || !pictures_left || (!isturf(target) && !isturf(target.loc)) || !((isAI(user) && GLOB.cameranet.checkTurfVis(get_turf(target))) || ((user.client && (get_turf(target) in get_hear(user.client.view, user)) || (get_turf(target) in get_hear(world.view, user))))))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/item/camera/afterattack(atom/target, mob/user, flag)
|
||||
if (disk)
|
||||
if(ismob(target))
|
||||
if (disk.record)
|
||||
QDEL_NULL(disk.record)
|
||||
|
||||
disk.record = new
|
||||
var/mob/M = target
|
||||
disk.record.caller_name = M.name
|
||||
disk.record.set_caller_image(M)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>Invalid holodisk target.</span>")
|
||||
return
|
||||
|
||||
if(!can_target(target, user, flag))
|
||||
return
|
||||
|
||||
on = FALSE
|
||||
addtimer(CALLBACK(src, .proc/cooldown), cooldown)
|
||||
icon_state = state_off
|
||||
|
||||
INVOKE_ASYNC(src, .proc/captureimage, target, user, flag, picture_size_x, picture_size_y)
|
||||
|
||||
|
||||
/obj/item/camera/proc/cooldown()
|
||||
UNTIL(!blending)
|
||||
icon_state = state_on
|
||||
on = TRUE
|
||||
|
||||
/obj/item/camera/proc/show_picture(mob/user, datum/picture/selection)
|
||||
var/obj/item/photo/P = new(src, selection)
|
||||
P.show(user)
|
||||
to_chat(user, P.desc)
|
||||
qdel(P)
|
||||
|
||||
/obj/item/camera/proc/captureimage(atom/target, mob/user, flag, size_x = 1, size_y = 1)
|
||||
blending = TRUE
|
||||
var/turf/target_turf = get_turf(target)
|
||||
if(!isturf(target_turf))
|
||||
blending = FALSE
|
||||
return FALSE
|
||||
size_x = CLAMP(size_x, 0, CAMERA_PICTURE_SIZE_HARD_LIMIT)
|
||||
size_y = CLAMP(size_y, 0, CAMERA_PICTURE_SIZE_HARD_LIMIT)
|
||||
var/list/desc = list()
|
||||
var/ai_user = isAI(user)
|
||||
var/list/seen
|
||||
var/list/viewlist = (user && user.client)? getviewsize(user.client.view) : getviewsize(world.view)
|
||||
var/viewr = max(viewlist[1], viewlist[2]) + max(size_x, size_y)
|
||||
var/viewc = user.client? user.client.eye : target
|
||||
seen = get_hear(viewr, viewc)
|
||||
var/list/turfs = list()
|
||||
var/list/mobs = list()
|
||||
var/blueprints = FALSE
|
||||
var/clone_area = SSmapping.RequestBlockReservation(size_x * 2 + 1, size_y * 2 + 1)
|
||||
for(var/turf/T in block(locate(target_turf.x - size_x, target_turf.y - size_y, target_turf.z), locate(target_turf.x + size_x, target_turf.y + size_y, target_turf.z)))
|
||||
if((ai_user && GLOB.cameranet.checkTurfVis(T)) || T in seen)
|
||||
turfs += T
|
||||
for(var/mob/M in T)
|
||||
mobs += M
|
||||
if(locate(/obj/item/areaeditor/blueprints) in T)
|
||||
blueprints = TRUE
|
||||
CHECK_TICK
|
||||
for(var/i in mobs)
|
||||
desc += camera_get_mobdesc(i)
|
||||
|
||||
var/psize_x = (size_x * 2 + 1) * world.icon_size
|
||||
var/psize_y = (size_y * 2 + 1) * world.icon_size
|
||||
var/get_icon = camera_get_icon(turfs, target_turf, psize_x, psize_y, clone_area, size_x, size_y, (size_x * 2 + 1), (size_y * 2 + 1))
|
||||
qdel(clone_area)
|
||||
var/icon/temp = icon('icons/effects/96x96.dmi',"")
|
||||
temp.Blend("#000", ICON_OVERLAY)
|
||||
temp.Scale(psize_x, psize_y)
|
||||
temp.Blend(get_icon, ICON_OVERLAY)
|
||||
|
||||
var/datum/picture/P = new("picture", desc.Join(""), temp, null, psize_x, psize_y, blueprints)
|
||||
after_picture(user, P, flag)
|
||||
blending = FALSE
|
||||
|
||||
/obj/item/camera/proc/camera_get_mobdesc(mob/M)
|
||||
var/list/mob_details = list()
|
||||
if(M.invisibility)
|
||||
if(see_ghosts && isobserver(M))
|
||||
mob_details += "You can also see a g-g-g-g-ghooooost! "
|
||||
else
|
||||
return mob_details
|
||||
var/list/holding = list()
|
||||
if(isliving(M))
|
||||
var/mob/living/L = M
|
||||
var/len = length(L.held_items)
|
||||
if(len)
|
||||
for(var/obj/item/I in L.held_items)
|
||||
if(!holding.len)
|
||||
holding += "They are holding \a [I]"
|
||||
else if(L.held_items.Find(I) == len)
|
||||
holding += ", and \a [I]."
|
||||
else
|
||||
holding += ", \a [I]"
|
||||
holding += "."
|
||||
holding = holding.Join("")
|
||||
mob_details += "You can also see [L] on the photo[L.health < (L.maxHealth * 0.75) ? ", looking a bit hurt":""][holding ? ". [holding]":"."]."
|
||||
return mob_details.Join("")
|
||||
|
||||
/obj/item/camera/proc/after_picture(mob/user, datum/picture/picture, proximity_flag)
|
||||
printpicture(user, picture)
|
||||
|
||||
/obj/item/camera/proc/printpicture(mob/user, datum/picture/picture) //Normal camera proc for creating photos
|
||||
var/obj/item/photo/p = new(get_turf(src), picture)
|
||||
if(in_range(src, user)) //needed because of TK
|
||||
user.put_in_hands(p)
|
||||
pictures_left--
|
||||
to_chat(user, "<span class='notice'>[pictures_left] photos left.</span>")
|
||||
var/customize = alert(user, "Do you want to customize the photo?", "Customization", "Yes", "No")
|
||||
if(customize == "Yes")
|
||||
var/name1 = input(user, "Set a name for this photo, or leave blank. 32 characters max.", "Name") as text|null
|
||||
var/desc1 = input(user, "Set a description to add to photo, or leave blank. 128 characters max.", "Caption") as text|null
|
||||
var/caption = input(user, "Set a caption for this photo, or leave blank. 256 characters max.", "Caption") as text|null
|
||||
if(name1)
|
||||
name1 = copytext(name1, 1, 33)
|
||||
picture.picture_name = name1
|
||||
if(desc1)
|
||||
desc1 = copytext(desc1, 1, 129)
|
||||
picture.picture_desc = "[desc1] - [picture.picture_desc]"
|
||||
if(caption)
|
||||
caption = copytext(caption, 1, 257)
|
||||
picture.caption = caption
|
||||
p.set_picture(picture)
|
||||
if(CONFIG_GET(flag/picture_logging_camera))
|
||||
picture.log_to_file()
|
||||
@@ -0,0 +1,88 @@
|
||||
/obj/effect/appearance_clone
|
||||
|
||||
/obj/effect/appearance_clone/New(loc, atom/A) //Intentionally not Initialize().
|
||||
if(istype(A))
|
||||
appearance = A.appearance
|
||||
dir = A.dir
|
||||
if(ismovableatom(A))
|
||||
var/atom/movable/AM = A
|
||||
step_x = AM.step_x
|
||||
step_y = AM.step_y
|
||||
. = ..()
|
||||
|
||||
/obj/item/camera/proc/camera_get_icon(list/turfs, turf/center, psize_x = 96, psize_y = 96, datum/turf_reservation/clone_area, size_x, size_y, total_x, total_y)
|
||||
var/list/atoms = list()
|
||||
var/skip_normal = FALSE
|
||||
var/wipe_atoms = FALSE
|
||||
|
||||
if(istype(clone_area) && total_x == clone_area.width && total_y == clone_area.height && size_x >= 0 && size_y > 0)
|
||||
var/cloned_center_x = round(clone_area.bottom_left_coords[1] + ((total_x - 1) / 2))
|
||||
var/cloned_center_y = round(clone_area.bottom_left_coords[2] + ((total_y - 1) / 2))
|
||||
for(var/t in turfs)
|
||||
var/turf/T = t
|
||||
var/offset_x = T.x - center.x
|
||||
var/offset_y = T.y - center.y
|
||||
var/turf/newT = locate(cloned_center_x + offset_x, cloned_center_y + offset_y, clone_area.bottom_left_coords[3])
|
||||
if(!(newT in clone_area.reserved_turfs)) //sanity check so we don't overwrite other areas somehow
|
||||
continue
|
||||
atoms += new /obj/effect/appearance_clone(newT, T)
|
||||
if(T.loc.icon_state)
|
||||
atoms += new /obj/effect/appearance_clone(newT, T.loc)
|
||||
for(var/i in T.contents)
|
||||
var/atom/A = i
|
||||
if(!A.invisibility || (see_ghosts && isobserver(A)))
|
||||
atoms += new /obj/effect/appearance_clone(newT, A)
|
||||
skip_normal = TRUE
|
||||
wipe_atoms = TRUE
|
||||
center = locate(cloned_center_x, cloned_center_y, clone_area.bottom_left_coords[3])
|
||||
|
||||
if(!skip_normal)
|
||||
for(var/i in turfs)
|
||||
var/turf/T = i
|
||||
atoms += T
|
||||
for(var/atom/movable/A in T)
|
||||
if(A.invisibility)
|
||||
if(!(see_ghosts && isobserver(A)))
|
||||
continue
|
||||
atoms += A
|
||||
CHECK_TICK
|
||||
|
||||
var/icon/res = icon('icons/effects/96x96.dmi', "")
|
||||
res.Scale(psize_x, psize_y)
|
||||
|
||||
var/list/sorted = list()
|
||||
var/j
|
||||
for(var/i in 1 to atoms.len)
|
||||
var/atom/c = atoms[i]
|
||||
for(j = sorted.len, j > 0, --j)
|
||||
var/atom/c2 = sorted[j]
|
||||
if(c2.layer <= c.layer)
|
||||
break
|
||||
sorted.Insert(j+1, c)
|
||||
CHECK_TICK
|
||||
|
||||
var/xcomp = FLOOR(psize_x / 2, 1) - 15
|
||||
var/ycomp = FLOOR(psize_y / 2, 1) - 15
|
||||
|
||||
|
||||
for(var/atom/A in sorted)
|
||||
var/xo = (A.x - center.x) * world.icon_size + A.pixel_x + xcomp
|
||||
var/yo = (A.y - center.y) * world.icon_size + A.pixel_y + ycomp
|
||||
if(ismovableatom(A))
|
||||
var/atom/movable/AM = A
|
||||
xo += AM.step_x
|
||||
yo += AM.step_y
|
||||
var/icon/img = getFlatIcon(A)
|
||||
res.Blend(img, blendMode2iconMode(A.blend_mode), xo, yo)
|
||||
CHECK_TICK
|
||||
|
||||
if(!silent)
|
||||
if(istype(custom_sound)) //This is where the camera actually finishes its exposure.
|
||||
playsound(loc, custom_sound, 75, 1, -3)
|
||||
else
|
||||
playsound(loc, pick('sound/items/polaroid1.ogg', 'sound/items/polaroid2.ogg'), 75, 1, -3)
|
||||
|
||||
if(wipe_atoms)
|
||||
QDEL_LIST(atoms)
|
||||
|
||||
return res
|
||||
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Film
|
||||
*/
|
||||
/obj/item/camera_film
|
||||
name = "film cartridge"
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
desc = "A camera film cartridge. Insert it into a camera to reload it."
|
||||
icon_state = "film"
|
||||
item_state = "electropack"
|
||||
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
resistance_flags = FLAMMABLE
|
||||
materials = list(MAT_METAL = 10, MAT_GLASS = 10)
|
||||
@@ -0,0 +1,14 @@
|
||||
/obj/item/camera/spooky
|
||||
name = "camera obscura"
|
||||
desc = "A polaroid camera, some say it can see ghosts!"
|
||||
see_ghosts = CAMERA_SEE_GHOSTS_BASIC
|
||||
|
||||
/obj/item/camera/spooky/badmin
|
||||
desc = "A polaroid camera, some say it can see ghosts! It seems to have an extra magnifier on the end."
|
||||
see_ghosts = CAMERA_SEE_GHOSTS_ORBIT
|
||||
|
||||
/obj/item/camera/detective
|
||||
name = "Detective's camera"
|
||||
desc = "A polaroid camera with extra capacity for crime investigations."
|
||||
pictures_max = 30
|
||||
pictures_left = 30
|
||||
@@ -0,0 +1,145 @@
|
||||
// Picture frames
|
||||
|
||||
/obj/item/wallframe/picture
|
||||
name = "picture frame"
|
||||
desc = "The perfect showcase for your favorite deathtrap memories."
|
||||
icon = 'icons/obj/decals.dmi'
|
||||
materials = list()
|
||||
flags_1 = 0
|
||||
icon_state = "frame-empty"
|
||||
result_path = /obj/structure/sign/picture_frame
|
||||
var/obj/item/photo/displayed
|
||||
|
||||
/obj/item/wallframe/picture/attackby(obj/item/I, mob/user)
|
||||
if(istype(I, /obj/item/photo))
|
||||
if(!displayed)
|
||||
if(!user.transferItemToLoc(I, src))
|
||||
return
|
||||
displayed = I
|
||||
update_icon()
|
||||
else
|
||||
to_chat(user, "<span class=notice>\The [src] already contains a photo.</span>")
|
||||
..()
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/obj/item/wallframe/picture/attack_hand(mob/user)
|
||||
if(user.get_inactive_held_item() != src)
|
||||
..()
|
||||
return
|
||||
if(contents.len)
|
||||
var/obj/item/I = pick(contents)
|
||||
user.put_in_hands(I)
|
||||
to_chat(user, "<span class='notice'>You carefully remove the photo from \the [src].</span>")
|
||||
displayed = null
|
||||
update_icon()
|
||||
return ..()
|
||||
|
||||
/obj/item/wallframe/picture/attack_self(mob/user)
|
||||
user.examinate(src)
|
||||
|
||||
/obj/item/wallframe/picture/examine(mob/user)
|
||||
if(user.is_holding(src) && displayed)
|
||||
displayed.show(user)
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/item/wallframe/picture/update_icon()
|
||||
cut_overlays()
|
||||
if(displayed)
|
||||
add_overlay(getFlatIcon(displayed))
|
||||
|
||||
/obj/item/wallframe/picture/after_attach(obj/O)
|
||||
..()
|
||||
var/obj/structure/sign/picture_frame/PF = O
|
||||
PF.copy_overlays(src)
|
||||
if(displayed)
|
||||
PF.framed = displayed
|
||||
if(contents.len)
|
||||
var/obj/item/I = pick(contents)
|
||||
I.forceMove(PF)
|
||||
|
||||
/obj/structure/sign/picture_frame
|
||||
name = "picture frame"
|
||||
desc = "Every time you look it makes you laugh."
|
||||
icon = 'icons/obj/decals.dmi'
|
||||
icon_state = "frame-empty"
|
||||
var/obj/item/photo/framed
|
||||
var/persistence_id
|
||||
|
||||
/obj/structure/sign/picture_frame/Initialize(mapload, dir, building)
|
||||
. = ..()
|
||||
LAZYADD(SSpersistence.photo_frames, src)
|
||||
if(dir)
|
||||
setDir(dir)
|
||||
if(building)
|
||||
pixel_x = (dir & 3)? 0 : (dir == 4 ? -30 : 30)
|
||||
pixel_y = (dir & 3)? (dir ==1 ? -30 : 30) : 0
|
||||
|
||||
/obj/structure/sign/picture_frame/Destroy()
|
||||
LAZYREMOVE(SSpersistence.photo_frames, src)
|
||||
return ..()
|
||||
|
||||
/obj/structure/sign/picture_frame/proc/get_photo_id()
|
||||
if(istype(framed) && istype(framed.picture))
|
||||
return framed.picture.id
|
||||
|
||||
/obj/structure/sign/picture_frame/proc/load_from_id(id)
|
||||
var/obj/item/photo/P = load_photo_from_disk(id)
|
||||
if(istype(P))
|
||||
if(istype(framed))
|
||||
framed.forceMove(drop_location())
|
||||
else
|
||||
qdel(framed)
|
||||
framed = P
|
||||
update_icon()
|
||||
|
||||
/obj/structure/sign/picture_frame/examine(mob/user)
|
||||
if(in_range(src, user) && framed)
|
||||
framed.show(user)
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/structure/sign/picture_frame/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/screwdriver) || istype(I, /obj/item/wrench))
|
||||
to_chat(user, "<span class='notice'>You start unsecuring [name]...</span>")
|
||||
if(I.use_tool(src, user, 30, volume=50))
|
||||
playsound(loc, 'sound/items/deconstruct.ogg', 50, 1)
|
||||
to_chat(user, "<span class='notice'>You unsecure [name].</span>")
|
||||
deconstruct()
|
||||
return
|
||||
|
||||
else if(istype(I, /obj/item/photo))
|
||||
if(!framed)
|
||||
var/obj/item/photo/P = I
|
||||
if(!user.transferItemToLoc(P, src))
|
||||
return
|
||||
framed = P
|
||||
update_icon()
|
||||
else
|
||||
to_chat(user, "<span class=notice>\The [src] already contains a photo.</span>")
|
||||
|
||||
..()
|
||||
|
||||
/obj/structure/sign/picture_frame/attack_hand(mob/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(framed)
|
||||
framed.show(user)
|
||||
|
||||
/obj/structure/sign/picture_frame/update_icon()
|
||||
cut_overlays()
|
||||
if(framed)
|
||||
add_overlay(getFlatIcon(framed))
|
||||
|
||||
/obj/structure/sign/picture_frame/deconstruct(disassembled = TRUE)
|
||||
if(!(flags_1 & NODECONSTRUCT_1))
|
||||
var/obj/item/wallframe/picture/F = new /obj/item/wallframe/picture(loc)
|
||||
if(framed)
|
||||
F.displayed = framed
|
||||
framed = null
|
||||
if(contents.len)
|
||||
var/obj/item/I = pick(contents)
|
||||
I.forceMove(F)
|
||||
F.update_icon()
|
||||
qdel(src)
|
||||
@@ -0,0 +1,98 @@
|
||||
|
||||
/obj/item/camera/siliconcam
|
||||
name = "silicon photo camera"
|
||||
var/in_camera_mode = FALSE
|
||||
var/list/datum/picture/stored = list()
|
||||
|
||||
/obj/item/camera/siliconcam/ai_camera
|
||||
name = "AI photo camera"
|
||||
|
||||
/obj/item/camera/siliconcam/proc/toggle_camera_mode(mob/user)
|
||||
if(in_camera_mode)
|
||||
camera_mode_off(user)
|
||||
else
|
||||
camera_mode_on(user)
|
||||
|
||||
/obj/item/camera/siliconcam/proc/camera_mode_off(mob/user)
|
||||
in_camera_mode = FALSE
|
||||
to_chat(user, "<B>Camera Mode deactivated</B>")
|
||||
|
||||
/obj/item/camera/siliconcam/proc/camera_mode_on(mob/user)
|
||||
in_camera_mode = TRUE
|
||||
to_chat(user, "<B>Camera Mode activated</B>")
|
||||
|
||||
/obj/item/camera/siliconcam/proc/selectpicture(mob/user)
|
||||
var/list/nametemp = list()
|
||||
var/find
|
||||
if(!stored.len)
|
||||
to_chat(usr, "<span class='boldannounce'>No images saved</span>")
|
||||
return
|
||||
var/list/temp = list()
|
||||
for(var/i in stored)
|
||||
var/datum/picture/p = i
|
||||
nametemp += p.picture_name
|
||||
temp[p.picture_name] = p
|
||||
find = input(user, "Select image") in nametemp|null
|
||||
if(!find)
|
||||
return
|
||||
return temp[find]
|
||||
|
||||
/obj/item/camera/siliconcam/proc/viewpictures(mob/user)
|
||||
var/datum/picture/selection = selectpicture(user)
|
||||
if(istype(selection))
|
||||
show_picture(user, selection)
|
||||
|
||||
/obj/item/camera/siliconcam/ai_camera/after_picture(mob/user, datum/picture/picture, proximity_flag)
|
||||
var/number = stored.len
|
||||
picture.picture_name = "Image [number] (taken by [loc.name])"
|
||||
stored[picture] = TRUE
|
||||
to_chat(usr, "<span class='unconscious'>Image recorded</span>")
|
||||
|
||||
/obj/item/camera/siliconcam/robot_camera
|
||||
name = "Cyborg photo camera"
|
||||
var/printcost = 2
|
||||
|
||||
/obj/item/camera/siliconcam/robot_camera/after_picture(mob/user, datum/picture/picture, proximity_flag)
|
||||
var/mob/living/silicon/robot/C = loc
|
||||
if(istype(C) && istype(C.connected_ai))
|
||||
var/number = C.connected_ai.aicamera.stored.len
|
||||
picture.picture_name = "Image [number] (taken by [loc.name])"
|
||||
C.connected_ai.aicamera.stored[picture] = TRUE
|
||||
to_chat(usr, "<span class='unconscious'>Image recorded and saved to remote database</span>")
|
||||
else
|
||||
var/number = stored.len
|
||||
picture.picture_name = "Image [number] (taken by [loc.name])"
|
||||
stored[picture] = TRUE
|
||||
to_chat(usr, "<span class='unconscious'>Image recorded and saved to local storage. Upload will happen automatically if unit is lawsynced.</span>")
|
||||
|
||||
/obj/item/camera/siliconcam/robot_camera/selectpicture(mob/user)
|
||||
var/mob/living/silicon/robot/R = loc
|
||||
if(istype(R) && R.connected_ai)
|
||||
R.picturesync()
|
||||
return R.connected_ai.aicamera.selectpicture(user)
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/camera/siliconcam/robot_camera/verb/borgprinting()
|
||||
set category ="Robot Commands"
|
||||
set name = "Print Image"
|
||||
set src in usr
|
||||
if(usr.stat == DEAD)
|
||||
return
|
||||
borgprint(usr)
|
||||
|
||||
/obj/item/camera/siliconcam/robot_camera/proc/borgprint(mob/user)
|
||||
var/mob/living/silicon/robot/C = loc
|
||||
if(!istype(C) || C.toner < 20)
|
||||
to_chat(user, "<span class='warning'>Insufficent toner to print image.</span>")
|
||||
return
|
||||
var/datum/picture/selection = selectpicture(user)
|
||||
if(!istype(selection))
|
||||
to_chat(user, "<span class='warning'>Invalid Image.</span>")
|
||||
return
|
||||
var/obj/item/photo/p = new /obj/item/photo(C.loc, selection)
|
||||
p.pixel_x = rand(-10, 10)
|
||||
p.pixel_y = rand(-10, 10)
|
||||
C.toner -= printcost //All fun allowed.
|
||||
visible_message("[C.name] spits out a photograph from a narrow slot on its chassis.")
|
||||
to_chat(usr, "<span class='notice'>You print a photograph.</span>")
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Photo album
|
||||
*/
|
||||
/obj/item/storage/photo_album
|
||||
name = "photo album"
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "album"
|
||||
item_state = "briefcase"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/briefcase_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/briefcase_righthand.dmi'
|
||||
resistance_flags = FLAMMABLE
|
||||
var/persistence_id
|
||||
|
||||
/obj/item/storage/photo_album/Initialize()
|
||||
. = ..()
|
||||
GET_COMPONENT(STR, /datum/component/storage)
|
||||
STR.can_hold = typecacheof(list(/obj/item/photo))
|
||||
LAZYADD(SSpersistence.photo_albums, src)
|
||||
|
||||
/obj/item/storage/photo_album/Destroy()
|
||||
LAZYREMOVE(SSpersistence.photo_albums, src)
|
||||
return ..()
|
||||
|
||||
/obj/item/storage/photo_album/proc/get_picture_id_list()
|
||||
var/list/L = list()
|
||||
for(var/i in contents)
|
||||
if(istype(i, /obj/item/photo))
|
||||
L += i
|
||||
if(!L.len)
|
||||
return
|
||||
. = list()
|
||||
for(var/i in L)
|
||||
var/obj/item/photo/P = i
|
||||
if(!istype(P.picture))
|
||||
continue
|
||||
. |= P.picture.id
|
||||
|
||||
/obj/item/storage/photo_album/proc/populate_from_id_list(list/ids)
|
||||
for(var/i in ids)
|
||||
var/obj/item/photo/P = load_photo_from_disk(i)
|
||||
if(istype(P))
|
||||
if(!SEND_SIGNAL(src, COMSIG_TRY_STORAGE_INSERT, P, null, TRUE, TRUE))
|
||||
qdel(P)
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Photo
|
||||
*/
|
||||
/obj/item/photo
|
||||
name = "photo"
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "photo"
|
||||
item_state = "paper"
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
resistance_flags = FLAMMABLE
|
||||
max_integrity = 50
|
||||
grind_results = list("iodine" = 4)
|
||||
var/datum/picture/picture
|
||||
var/scribble //Scribble on the back.
|
||||
var/sillynewscastervar //Photo objects with this set to 1 will not be ejected by a newscaster. Only gets set to 1 if a silicon puts one of their images into a newscaster
|
||||
|
||||
/obj/item/photo/Initialize(mapload, datum/picture/P, datum_name = TRUE, datum_desc = TRUE)
|
||||
set_picture(P, datum_name, datum_desc)
|
||||
return ..()
|
||||
|
||||
/obj/item/photo/proc/set_picture(datum/picture/P, setname, setdesc)
|
||||
if(!istype(P))
|
||||
return
|
||||
picture = P
|
||||
update_icon()
|
||||
if(P.caption)
|
||||
scribble = P.caption
|
||||
if(setname && P.picture_name)
|
||||
name = P.picture_name
|
||||
if(setdesc && P.picture_desc)
|
||||
desc = P.picture_desc
|
||||
|
||||
/obj/item/photo/update_icon()
|
||||
var/icon/I = picture.get_small_icon()
|
||||
if(I)
|
||||
icon = I
|
||||
|
||||
/obj/item/photo/suicide_act(mob/living/carbon/user)
|
||||
user.visible_message("<span class='suicide'>[user] is taking one last look at \the [src]! It looks like [user.p_theyre()] giving in to death!</span>")//when you wanna look at photo of waifu one last time before you die...
|
||||
if (user.gender == MALE)
|
||||
playsound(user, 'sound/voice/human/manlaugh1.ogg', 50, 1)//EVERY TIME I DO IT MAKES ME LAUGH
|
||||
else if (user.gender == FEMALE)
|
||||
playsound(user, 'sound/voice/human/womanlaugh.ogg', 50, 1)
|
||||
return OXYLOSS
|
||||
|
||||
/obj/item/photo/attack_self(mob/user)
|
||||
user.examinate(src)
|
||||
|
||||
/obj/item/photo/attackby(obj/item/P, mob/user, params)
|
||||
if(istype(P, /obj/item/pen) || istype(P, /obj/item/toy/crayon))
|
||||
if(!user.is_literate())
|
||||
to_chat(user, "<span class='notice'>You scribble illegibly on [src]!</span>")
|
||||
return
|
||||
var/txt = sanitize(input(user, "What would you like to write on the back?", "Photo Writing", null) as text)
|
||||
txt = copytext(txt, 1, 128)
|
||||
if(user.canUseTopic(src, BE_CLOSE))
|
||||
scribble = txt
|
||||
..()
|
||||
|
||||
/obj/item/photo/examine(mob/user)
|
||||
..()
|
||||
|
||||
if(in_range(src, user))
|
||||
show(user)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You need to get closer to get a good look at this photo!</span>")
|
||||
|
||||
/obj/item/photo/proc/show(mob/user)
|
||||
user << browse_rsc(picture.picture_image, "tmp_photo.png")
|
||||
user << browse("<html><head><title>[name]</title></head>" \
|
||||
+ "<body style='overflow:hidden;margin:0;text-align:center'>" \
|
||||
+ "<img src='tmp_photo.png' width='[picture.psize_y]' style='-ms-interpolation-mode:nearest-neighbor' />" \
|
||||
+ "[scribble ? "<br>Written on the back:<br><i>[scribble]</i>" : ""]"\
|
||||
+ "</body></html>", "window=photo_showing;size=[picture.psize_x + scribble? 128:0]x[picture.psize_y + scribble? 128:0]")
|
||||
onclose(user, "[name]")
|
||||
|
||||
/obj/item/photo/verb/rename()
|
||||
set name = "Rename photo"
|
||||
set category = "Object"
|
||||
set src in usr
|
||||
|
||||
var/n_name = copytext(sanitize(input(usr, "What would you like to label the photo?", "Photo Labelling", null) as text), 1, MAX_NAME_LEN)
|
||||
//loc.loc check is for making possible renaming photos in clipboards
|
||||
if((loc == usr || loc.loc && loc.loc == usr) && usr.stat == CONSCIOUS && usr.canmove && !usr.restrained())
|
||||
name = "photo[(n_name ? text("- '[n_name]'") : null)]"
|
||||
add_fingerprint(usr)
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Photo album
|
||||
*/
|
||||
/obj/item/storage/photo_album
|
||||
name = "photo album"
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "album"
|
||||
item_state = "briefcase"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/briefcase_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/briefcase_righthand.dmi'
|
||||
resistance_flags = FLAMMABLE
|
||||
var/persistence_id
|
||||
|
||||
/obj/item/storage/photo_album/Initialize()
|
||||
. = ..()
|
||||
GET_COMPONENT(STR, /datum/component/storage)
|
||||
STR.can_hold = typecacheof(list(/obj/item/photo))
|
||||
STR.max_combined_w_class = 42
|
||||
STR.max_items = 21
|
||||
LAZYADD(SSpersistence.photo_albums, src)
|
||||
|
||||
/obj/item/storage/photo_album/Destroy()
|
||||
LAZYREMOVE(SSpersistence.photo_albums, src)
|
||||
return ..()
|
||||
|
||||
/obj/item/storage/photo_album/proc/get_picture_id_list()
|
||||
var/list/L = list()
|
||||
for(var/i in contents)
|
||||
if(istype(i, /obj/item/photo))
|
||||
L += i
|
||||
if(!L.len)
|
||||
return
|
||||
. = list()
|
||||
for(var/i in L)
|
||||
var/obj/item/photo/P = i
|
||||
if(!istype(P.picture))
|
||||
continue
|
||||
. |= P.picture.id
|
||||
|
||||
/obj/item/storage/photo_album/proc/populate_from_id_list(list/ids)
|
||||
for(var/i in ids)
|
||||
var/obj/item/photo/P = load_photo_from_disk(i)
|
||||
if(istype(P))
|
||||
if(!SEND_SIGNAL(src, COMSIG_TRY_STORAGE_INSERT, P, null, TRUE, TRUE))
|
||||
qdel(P)
|
||||
|
||||
#define ALBUM_DEFINE(id) /obj/item/storage/photo_album/##id/persistence_id = #id
|
||||
|
||||
ALBUM_DEFINE(HoS)
|
||||
ALBUM_DEFINE(RD)
|
||||
ALBUM_DEFINE(HoP)
|
||||
ALBUM_DEFINE(Captain)
|
||||
ALBUM_DEFINE(CMO)
|
||||
ALBUM_DEFINE(QM)
|
||||
ALBUM_DEFINE(CE)
|
||||
|
||||
#undef ALBUM_DEFINE
|
||||
@@ -0,0 +1,157 @@
|
||||
// Picture frames
|
||||
|
||||
/obj/item/wallframe/picture
|
||||
name = "picture frame"
|
||||
desc = "The perfect showcase for your favorite deathtrap memories."
|
||||
icon = 'icons/obj/decals.dmi'
|
||||
materials = list()
|
||||
flags_1 = 0
|
||||
icon_state = "frame-empty"
|
||||
result_path = /obj/structure/sign/picture_frame
|
||||
var/obj/item/photo/displayed
|
||||
|
||||
/obj/item/wallframe/picture/attackby(obj/item/I, mob/user)
|
||||
if(istype(I, /obj/item/photo))
|
||||
if(!displayed)
|
||||
if(!user.transferItemToLoc(I, src))
|
||||
return
|
||||
displayed = I
|
||||
update_icon()
|
||||
else
|
||||
to_chat(user, "<span class=notice>\The [src] already contains a photo.</span>")
|
||||
..()
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/obj/item/wallframe/picture/attack_hand(mob/user)
|
||||
if(user.get_inactive_held_item() != src)
|
||||
..()
|
||||
return
|
||||
if(contents.len)
|
||||
var/obj/item/I = pick(contents)
|
||||
user.put_in_hands(I)
|
||||
to_chat(user, "<span class='notice'>You carefully remove the photo from \the [src].</span>")
|
||||
displayed = null
|
||||
update_icon()
|
||||
return ..()
|
||||
|
||||
/obj/item/wallframe/picture/attack_self(mob/user)
|
||||
user.examinate(src)
|
||||
|
||||
/obj/item/wallframe/picture/examine(mob/user)
|
||||
if(user.is_holding(src) && displayed)
|
||||
displayed.show(user)
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/item/wallframe/picture/update_icon()
|
||||
cut_overlays()
|
||||
if(displayed)
|
||||
add_overlay(getFlatIcon(displayed))
|
||||
|
||||
/obj/item/wallframe/picture/after_attach(obj/O)
|
||||
..()
|
||||
var/obj/structure/sign/picture_frame/PF = O
|
||||
PF.copy_overlays(src)
|
||||
if(displayed)
|
||||
PF.framed = displayed
|
||||
if(contents.len)
|
||||
var/obj/item/I = pick(contents)
|
||||
I.forceMove(PF)
|
||||
|
||||
/obj/structure/sign/picture_frame
|
||||
name = "picture frame"
|
||||
desc = "Every time you look it makes you laugh."
|
||||
icon = 'icons/obj/decals.dmi'
|
||||
icon_state = "frame-empty"
|
||||
var/obj/item/photo/framed
|
||||
var/persistence_id
|
||||
var/can_decon = TRUE
|
||||
|
||||
#define FRAME_DEFINE(id) /obj/structure/sign/picture_frame/##id/persistence_id = #id
|
||||
|
||||
//Put default persistent frame defines here!
|
||||
|
||||
#undef FRAME_DEFINE
|
||||
|
||||
/obj/structure/sign/picture_frame/Initialize(mapload, dir, building)
|
||||
. = ..()
|
||||
LAZYADD(SSpersistence.photo_frames, src)
|
||||
if(dir)
|
||||
setDir(dir)
|
||||
if(building)
|
||||
pixel_x = (dir & 3)? 0 : (dir == 4 ? -30 : 30)
|
||||
pixel_y = (dir & 3)? (dir ==1 ? -30 : 30) : 0
|
||||
|
||||
/obj/structure/sign/picture_frame/Destroy()
|
||||
LAZYREMOVE(SSpersistence.photo_frames, src)
|
||||
return ..()
|
||||
|
||||
/obj/structure/sign/picture_frame/proc/get_photo_id()
|
||||
if(istype(framed) && istype(framed.picture))
|
||||
return framed.picture.id
|
||||
|
||||
/obj/structure/sign/picture_frame/proc/load_from_id(id)
|
||||
var/obj/item/photo/P = load_photo_from_disk(id)
|
||||
if(istype(P))
|
||||
if(istype(framed))
|
||||
framed.forceMove(drop_location())
|
||||
else
|
||||
qdel(framed)
|
||||
framed = P
|
||||
update_icon()
|
||||
|
||||
/obj/structure/sign/picture_frame/examine(mob/user)
|
||||
if(in_range(src, user) && framed)
|
||||
framed.show(user)
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/structure/sign/picture_frame/attackby(obj/item/I, mob/user, params)
|
||||
if(can_decon && (istype(I, /obj/item/screwdriver) || istype(I, /obj/item/wrench)))
|
||||
to_chat(user, "<span class='notice'>You start unsecuring [name]...</span>")
|
||||
if(I.use_tool(src, user, 30, volume=50))
|
||||
playsound(loc, 'sound/items/deconstruct.ogg', 50, 1)
|
||||
to_chat(user, "<span class='notice'>You unsecure [name].</span>")
|
||||
deconstruct()
|
||||
|
||||
else if(istype(I, /obj/item/wirecutters) && framed)
|
||||
framed.forceMove(drop_location())
|
||||
framed = null
|
||||
user.visible_message("<span class='warning'>[user] cuts away [framed] from [src]!</span>")
|
||||
return
|
||||
|
||||
else if(istype(I, /obj/item/photo))
|
||||
if(!framed)
|
||||
var/obj/item/photo/P = I
|
||||
if(!user.transferItemToLoc(P, src))
|
||||
return
|
||||
framed = P
|
||||
update_icon()
|
||||
else
|
||||
to_chat(user, "<span class=notice>\The [src] already contains a photo.</span>")
|
||||
|
||||
..()
|
||||
|
||||
/obj/structure/sign/picture_frame/attack_hand(mob/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(framed)
|
||||
framed.show(user)
|
||||
|
||||
/obj/structure/sign/picture_frame/update_icon()
|
||||
cut_overlays()
|
||||
if(framed)
|
||||
add_overlay(getFlatIcon(framed))
|
||||
|
||||
/obj/structure/sign/picture_frame/deconstruct(disassembled = TRUE)
|
||||
if(!(flags_1 & NODECONSTRUCT_1))
|
||||
var/obj/item/wallframe/picture/F = new /obj/item/wallframe/picture(loc)
|
||||
if(framed)
|
||||
F.displayed = framed
|
||||
framed = null
|
||||
if(contents.len)
|
||||
var/obj/item/I = pick(contents)
|
||||
I.forceMove(F)
|
||||
F.update_icon()
|
||||
qdel(src)
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Photo
|
||||
*/
|
||||
/obj/item/photo
|
||||
name = "photo"
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "photo"
|
||||
item_state = "paper"
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
resistance_flags = FLAMMABLE
|
||||
max_integrity = 50
|
||||
grind_results = list("iodine" = 4)
|
||||
var/datum/picture/picture
|
||||
var/scribble //Scribble on the back.
|
||||
var/sillynewscastervar //Photo objects with this set to 1 will not be ejected by a newscaster. Only gets set to 1 if a silicon puts one of their images into a newscaster
|
||||
|
||||
/obj/item/photo/Initialize(mapload, datum/picture/P, datum_name = TRUE, datum_desc = TRUE)
|
||||
set_picture(P, datum_name, datum_desc)
|
||||
return ..()
|
||||
|
||||
/obj/item/photo/proc/set_picture(datum/picture/P, setname, setdesc)
|
||||
if(!istype(P))
|
||||
return
|
||||
picture = P
|
||||
update_icon()
|
||||
if(P.caption)
|
||||
scribble = P.caption
|
||||
if(setname && P.picture_name)
|
||||
name = P.picture_name
|
||||
if(setdesc && P.picture_desc)
|
||||
desc = P.picture_desc
|
||||
|
||||
/obj/item/photo/update_icon()
|
||||
if(!istype(picture) || !picture.picture_image)
|
||||
return
|
||||
var/icon/I = picture.get_small_icon()
|
||||
if(I)
|
||||
icon = I
|
||||
|
||||
/obj/item/photo/suicide_act(mob/living/carbon/user)
|
||||
user.visible_message("<span class='suicide'>[user] is taking one last look at \the [src]! It looks like [user.p_theyre()] giving in to death!</span>")//when you wanna look at photo of waifu one last time before you die...
|
||||
if (user.gender == MALE)
|
||||
playsound(user, 'sound/voice/human/manlaugh1.ogg', 50, 1)//EVERY TIME I DO IT MAKES ME LAUGH
|
||||
else if (user.gender == FEMALE)
|
||||
playsound(user, 'sound/voice/human/womanlaugh.ogg', 50, 1)
|
||||
return OXYLOSS
|
||||
|
||||
/obj/item/photo/attack_self(mob/user)
|
||||
user.examinate(src)
|
||||
|
||||
/obj/item/photo/attackby(obj/item/P, mob/user, params)
|
||||
if(istype(P, /obj/item/pen) || istype(P, /obj/item/toy/crayon))
|
||||
if(!user.is_literate())
|
||||
to_chat(user, "<span class='notice'>You scribble illegibly on [src]!</span>")
|
||||
return
|
||||
var/txt = sanitize(input(user, "What would you like to write on the back?", "Photo Writing", null) as text)
|
||||
txt = copytext(txt, 1, 128)
|
||||
if(user.canUseTopic(src, BE_CLOSE))
|
||||
scribble = txt
|
||||
..()
|
||||
|
||||
/obj/item/photo/examine(mob/user)
|
||||
..()
|
||||
|
||||
if(in_range(src, user))
|
||||
show(user)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You need to get closer to get a good look at this photo!</span>")
|
||||
|
||||
/obj/item/photo/proc/show(mob/user)
|
||||
if(!istype(picture) || !picture.picture_image)
|
||||
to_chat(user, "<span class='warning'>[src] seems to be blank...</span>")
|
||||
return
|
||||
user << browse_rsc(picture.picture_image, "tmp_photo.png")
|
||||
user << browse("<html><head><title>[name]</title></head>" \
|
||||
+ "<body style='overflow:hidden;margin:0;text-align:center'>" \
|
||||
+ "<img src='tmp_photo.png' width='480' style='-ms-interpolation-mode:nearest-neighbor' />" \
|
||||
+ "[scribble ? "<br>Written on the back:<br><i>[scribble]</i>" : ""]"\
|
||||
+ "</body></html>", "window=photo_showing;size=480x608")
|
||||
onclose(user, "[name]")
|
||||
|
||||
/obj/item/photo/verb/rename()
|
||||
set name = "Rename photo"
|
||||
set category = "Object"
|
||||
set src in usr
|
||||
|
||||
var/n_name = copytext(sanitize(input(usr, "What would you like to label the photo?", "Photo Labelling", null) as text), 1, MAX_NAME_LEN)
|
||||
//loc.loc check is for making possible renaming photos in clipboards
|
||||
if((loc == usr || loc.loc && loc.loc == usr) && usr.stat == CONSCIOUS && usr.canmove && !usr.restrained())
|
||||
name = "photo[(n_name ? text("- '[n_name]'") : null)]"
|
||||
add_fingerprint(usr)
|
||||
@@ -179,6 +179,7 @@
|
||||
icon_state = "wormhole_projector"
|
||||
var/obj/effect/portal/p_blue
|
||||
var/obj/effect/portal/p_orange
|
||||
var/atmos_link = FALSE
|
||||
|
||||
/obj/item/gun/energy/wormhole_projector/update_icon()
|
||||
icon_state = "[initial(icon_state)][select]"
|
||||
@@ -227,7 +228,7 @@
|
||||
p_blue.link_portal(p_orange)
|
||||
|
||||
/obj/item/gun/energy/wormhole_projector/proc/create_portal(obj/item/projectile/beam/wormhole/W, turf/target)
|
||||
var/obj/effect/portal/P = new /obj/effect/portal(target, src, 300, null, FALSE, null)
|
||||
var/obj/effect/portal/P = new /obj/effect/portal(target, src, 300, null, FALSE, null, atmos_link)
|
||||
if(istype(W, /obj/item/projectile/beam/wormhole/orange))
|
||||
qdel(p_orange)
|
||||
p_orange = P
|
||||
|
||||
@@ -597,8 +597,9 @@
|
||||
if(!length(beam_segments))
|
||||
return
|
||||
if(tracer_type)
|
||||
var/tempref = REF(src)
|
||||
for(var/datum/point/p in beam_segments)
|
||||
generate_tracer_between_points(p, beam_segments[p], tracer_type, color, duration, hitscan_light_range, hitscan_light_color_override, hitscan_light_intensity)
|
||||
generate_tracer_between_points(p, beam_segments[p], tracer_type, color, duration, hitscan_light_range, hitscan_light_color_override, hitscan_light_intensity, tempref)
|
||||
if(muzzle_type && duration > 0)
|
||||
var/datum/point/p = beam_segments[1]
|
||||
var/atom/movable/thing = new muzzle_type
|
||||
|
||||
@@ -2,9 +2,15 @@
|
||||
name = "bluespace beam"
|
||||
icon_state = "spark"
|
||||
hitsound = "sparks"
|
||||
damage = 3
|
||||
damage = 0
|
||||
nodamage = TRUE
|
||||
hitscan = TRUE
|
||||
pass_flags = PASSGLASS | PASSTABLE | PASSGRILLE | PASSMOB
|
||||
var/obj/item/gun/energy/wormhole_projector/gun
|
||||
color = "#33CCFF"
|
||||
tracer_type = /obj/effect/projectile/tracer/wormhole
|
||||
impact_type = /obj/effect/projectile/impact/wormhole
|
||||
muzzle_type = /obj/effect/projectile/muzzle/wormhole
|
||||
|
||||
/obj/item/projectile/beam/wormhole/orange
|
||||
name = "orange bluespace beam"
|
||||
@@ -16,10 +22,6 @@
|
||||
gun = casing.gun
|
||||
|
||||
/obj/item/projectile/beam/wormhole/on_hit(atom/target)
|
||||
if(ismob(target))
|
||||
var/turf/portal_destination = pick(orange(6, src))
|
||||
do_teleport(target, portal_destination)
|
||||
return ..()
|
||||
if(!gun)
|
||||
qdel(src)
|
||||
gun.create_portal(src, get_turf(src))
|
||||
|
||||
@@ -224,7 +224,7 @@
|
||||
list_reagents = list("chloralhydrate" = 50)
|
||||
|
||||
/obj/item/reagent_containers/syringe/lethal/execution
|
||||
list_reagents = list("plasma" = 15, "formaldehyde" = 15, "cyanide" = 10, "facid" = 10)
|
||||
list_reagents = list("amatoxin" = 15, "formaldehyde" = 15, "cyanide" = 10, "facid" = 10)
|
||||
|
||||
/obj/item/reagent_containers/syringe/mulligan
|
||||
name = "Mulligan"
|
||||
|
||||
@@ -501,15 +501,6 @@
|
||||
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
|
||||
export_price = 5000
|
||||
|
||||
/datum/techweb_node/exp_flight
|
||||
id = "exp_flight"
|
||||
display_name = "Experimental Flight Equipment"
|
||||
description = "Highly advanced construction tools."
|
||||
design_ids = list("flightshoes", "flightpack", "flightsuit")
|
||||
prereq_ids = list("adv_engi","integrated_HUDs", "adv_power" , "high_efficiency")
|
||||
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 5000)
|
||||
export_price = 5000
|
||||
|
||||
/////////////////////////weaponry tech/////////////////////////
|
||||
/datum/techweb_node/weaponry
|
||||
id = "weaponry"
|
||||
|
||||
@@ -0,0 +1,351 @@
|
||||
/obj/effect/sliding_puzzle
|
||||
name = "Sliding puzzle generator"
|
||||
icon = 'icons/obj/items_and_weapons.dmi' //mapping
|
||||
icon_state = "syndballoon"
|
||||
invisibility = INVISIBILITY_ABSTRACT
|
||||
anchored = TRUE
|
||||
var/list/elements
|
||||
var/floor_type = /turf/open/floor/vault
|
||||
var/finished = FALSE
|
||||
var/reward_type = /obj/item/reagent_containers/food/snacks/cookie
|
||||
var/element_type = /obj/structure/puzzle_element
|
||||
var/auto_setup = TRUE
|
||||
var/empty_tile_id
|
||||
|
||||
//Gets the turf where the tile with given id should be
|
||||
/obj/effect/sliding_puzzle/proc/get_turf_for_id(id)
|
||||
var/turf/center = get_turf(src)
|
||||
switch(id)
|
||||
if(1)
|
||||
return get_step(center,NORTHWEST)
|
||||
if(2)
|
||||
return get_step(center,NORTH)
|
||||
if(3)
|
||||
return get_step(center,NORTHEAST)
|
||||
if(4)
|
||||
return get_step(center,WEST)
|
||||
if(5)
|
||||
return center
|
||||
if(6)
|
||||
return get_step(center,EAST)
|
||||
if(7)
|
||||
return get_step(center,SOUTHWEST)
|
||||
if(8)
|
||||
return get_step(center,SOUTH)
|
||||
if(9)
|
||||
return get_step(center,SOUTHEAST)
|
||||
|
||||
/obj/effect/sliding_puzzle/Initialize(mapload)
|
||||
..()
|
||||
return INITIALIZE_HINT_LATELOAD
|
||||
|
||||
/obj/effect/sliding_puzzle/LateInitialize()
|
||||
if(auto_setup)
|
||||
setup()
|
||||
|
||||
/obj/effect/sliding_puzzle/proc/check_setup_location()
|
||||
for(var/id in 1 to 9)
|
||||
var/turf/T = get_turf_for_id(id)
|
||||
if(!T)
|
||||
return FALSE
|
||||
if(istype(T,/turf/closed/indestructible))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
|
||||
/obj/effect/sliding_puzzle/proc/validate()
|
||||
if(finished)
|
||||
return
|
||||
|
||||
if(elements.len < 8) //Someone broke it
|
||||
qdel(src)
|
||||
|
||||
//Check if everything is in place
|
||||
for(var/id in 1 to 9)
|
||||
var/target_turf = get_turf_for_id(id)
|
||||
var/obj/structure/puzzle_element/E = locate() in target_turf
|
||||
if(id == empty_tile_id && !E) // This location should be empty.
|
||||
continue
|
||||
if(!E || E.id != id) //wrong tile or no tile at all
|
||||
return
|
||||
//Ding ding
|
||||
finish()
|
||||
|
||||
/obj/effect/sliding_puzzle/Destroy()
|
||||
if(LAZYLEN(elements))
|
||||
for(var/obj/structure/puzzle_element/E in elements)
|
||||
E.source = null
|
||||
elements.Cut()
|
||||
return ..()
|
||||
|
||||
#define COLLAPSE_DURATION 7
|
||||
|
||||
/obj/effect/sliding_puzzle/proc/finish()
|
||||
finished = TRUE
|
||||
for(var/mob/M in range(7,src))
|
||||
shake_camera(M, COLLAPSE_DURATION , 1)
|
||||
for(var/obj/structure/puzzle_element/E in elements)
|
||||
E.collapse()
|
||||
|
||||
dispense_reward()
|
||||
|
||||
/obj/effect/sliding_puzzle/proc/dispense_reward()
|
||||
new reward_type(get_turf(src))
|
||||
|
||||
/obj/effect/sliding_puzzle/proc/is_solvable()
|
||||
var/list/current_ordering = list()
|
||||
for(var/obj/structure/puzzle_element/E in elements_in_order())
|
||||
current_ordering += E.id
|
||||
|
||||
var/swap_tally = 0
|
||||
for(var/i in 1 to current_ordering.len)
|
||||
var/checked_value = current_ordering[i]
|
||||
for(var/j in i to current_ordering.len)
|
||||
if(current_ordering[j] < checked_value)
|
||||
swap_tally++
|
||||
|
||||
return swap_tally % 2 == 0
|
||||
|
||||
//swap two tiles in same row
|
||||
/obj/effect/sliding_puzzle/proc/make_solvable()
|
||||
var/first_tile_id = 1
|
||||
var/other_tile_id = 2
|
||||
if(empty_tile_id == 1 || empty_tile_id == 2) //Can't swap with empty one so just grab some in second row
|
||||
first_tile_id = 4
|
||||
other_tile_id = 5
|
||||
|
||||
var/turf/T1 = get_turf_for_id(first_tile_id)
|
||||
var/turf/T2 = get_turf_for_id(other_tile_id)
|
||||
|
||||
var/obj/structure/puzzle_element/E1 = locate() in T1
|
||||
var/obj/structure/puzzle_element/E2 = locate() in T2
|
||||
|
||||
E1.forceMove(T2)
|
||||
E2.forceMove(T1)
|
||||
|
||||
/proc/cmp_xy_desc(atom/movable/A,atom/movable/B)
|
||||
if(A.y > B.y)
|
||||
return -1
|
||||
if(A.y < B.y)
|
||||
return 1
|
||||
if(A.x > B.x)
|
||||
return 1
|
||||
if(A.x < B.x)
|
||||
return -1
|
||||
return 0
|
||||
|
||||
/obj/effect/sliding_puzzle/proc/elements_in_order()
|
||||
return sortTim(elements,cmp=/proc/cmp_xy_desc)
|
||||
|
||||
/obj/effect/sliding_puzzle/proc/get_base_icon()
|
||||
var/icon/I = new('icons/obj/puzzle.dmi')
|
||||
var/list/puzzles = icon_states(I)
|
||||
var/puzzle_state = pick(puzzles)
|
||||
var/icon/P = new('icons/obj/puzzle.dmi',puzzle_state)
|
||||
return P
|
||||
|
||||
/obj/effect/sliding_puzzle/proc/setup()
|
||||
//First we slice the 96x96 icon into 32x32 pieces
|
||||
var/list/puzzle_pieces = list() //id -> icon list
|
||||
|
||||
var/width = 3
|
||||
var/height = 3
|
||||
var/list/left_ids = list()
|
||||
var/tile_count = width * height
|
||||
|
||||
//Generate per tile icons
|
||||
for(var/id in 1 to tile_count)
|
||||
var/y = width - round((id - 1) / width)
|
||||
var/x = ((id - 1) % width) + 1
|
||||
|
||||
var/x_start = 1 + (x - 1) * world.icon_size
|
||||
var/x_end = x_start + world.icon_size - 1
|
||||
var/y_start = 1 + ((y - 1) * world.icon_size)
|
||||
var/y_end = y_start + world.icon_size - 1
|
||||
|
||||
var/icon/T = get_base_icon()
|
||||
T.Crop(x_start,y_start,x_end,y_end)
|
||||
puzzle_pieces["[id]"] = T
|
||||
left_ids += id
|
||||
|
||||
//Setup random empty tile
|
||||
empty_tile_id = pick_n_take(left_ids)
|
||||
var/turf/empty_tile_turf = get_turf_for_id(empty_tile_id)
|
||||
empty_tile_turf.PlaceOnTop(floor_type,null,CHANGETURF_INHERIT_AIR)
|
||||
var/mutable_appearance/MA = new(puzzle_pieces["[empty_tile_id]"])
|
||||
MA.layer = empty_tile_turf.layer + 0.1
|
||||
empty_tile_turf.add_overlay(MA)
|
||||
|
||||
elements = list()
|
||||
var/list/empty_spots = left_ids.Copy()
|
||||
for(var/spot_id in empty_spots)
|
||||
var/turf/T = get_turf_for_id(spot_id)
|
||||
T = T.PlaceOnTop(floor_type,null,CHANGETURF_INHERIT_AIR)
|
||||
var/obj/structure/puzzle_element/E = new element_type(T)
|
||||
elements += E
|
||||
var/chosen_id = pick_n_take(left_ids)
|
||||
E.puzzle_icon = puzzle_pieces["[chosen_id]"]
|
||||
E.source = src
|
||||
E.id = chosen_id
|
||||
E.set_puzzle_icon()
|
||||
|
||||
if(!is_solvable())
|
||||
make_solvable()
|
||||
|
||||
/obj/structure/puzzle_element
|
||||
name = "mysterious pillar"
|
||||
desc = "puzzling..."
|
||||
icon = 'icons/obj/lavaland/artefacts.dmi'
|
||||
icon_state = "puzzle_pillar"
|
||||
anchored = FALSE
|
||||
density = TRUE
|
||||
var/id = 0
|
||||
var/obj/effect/sliding_puzzle/source
|
||||
var/icon/puzzle_icon
|
||||
|
||||
/obj/structure/puzzle_element/Move(nloc, dir)
|
||||
if(!isturf(nloc) || moving_diagonally || get_dist(get_step(src,dir),get_turf(source)) > 1)
|
||||
return 0
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/structure/puzzle_element/proc/set_puzzle_icon()
|
||||
cut_overlays()
|
||||
if(puzzle_icon)
|
||||
//Need to scale it down a bit to fit the static border
|
||||
var/icon/C = new(puzzle_icon)
|
||||
C.Scale(19,19)
|
||||
var/mutable_appearance/puzzle_small = new(C)
|
||||
puzzle_small.layer = layer + 0.1
|
||||
puzzle_small.pixel_x = 7
|
||||
puzzle_small.pixel_y = 7
|
||||
add_overlay(puzzle_small)
|
||||
|
||||
/obj/structure/puzzle_element/Destroy()
|
||||
if(source)
|
||||
source.elements -= src
|
||||
source.validate()
|
||||
return ..()
|
||||
|
||||
//Set the full image on the turf and delete yourself
|
||||
/obj/structure/puzzle_element/proc/collapse()
|
||||
var/turf/T = get_turf(src)
|
||||
var/mutable_appearance/MA = new(puzzle_icon)
|
||||
MA.layer = T.layer + 0.1
|
||||
T.add_overlay(MA)
|
||||
//Some basic shaking animation
|
||||
for(var/i in 1 to COLLAPSE_DURATION)
|
||||
animate(src, pixel_x=rand(-5,5), pixel_y=rand(-2,2), time=1)
|
||||
QDEL_IN(src,COLLAPSE_DURATION)
|
||||
|
||||
/obj/structure/puzzle_element/Moved()
|
||||
. = ..()
|
||||
source.validate()
|
||||
|
||||
//Admin abuse version so you can pick the icon before it sets up
|
||||
/obj/effect/sliding_puzzle/admin
|
||||
auto_setup = FALSE
|
||||
var/icon/puzzle_icon
|
||||
var/puzzle_state
|
||||
|
||||
/obj/effect/sliding_puzzle/admin/get_base_icon()
|
||||
var/icon/I = new(puzzle_icon,puzzle_state)
|
||||
return I
|
||||
|
||||
//Ruin version
|
||||
/obj/effect/sliding_puzzle/lavaland
|
||||
reward_type = /obj/structure/closet/crate/necropolis/puzzle
|
||||
|
||||
/obj/effect/sliding_puzzle/lavaland/dispense_reward()
|
||||
if(prob(25))
|
||||
//If it's not roaming somewhere else already.
|
||||
var/mob/living/simple_animal/hostile/megafauna/bubblegum/B = locate() in GLOB.mob_list
|
||||
if(!B)
|
||||
reward_type = /mob/living/simple_animal/hostile/megafauna/bubblegum
|
||||
return ..()
|
||||
|
||||
//Prison cube version
|
||||
/obj/effect/sliding_puzzle/prison
|
||||
auto_setup = FALSE //This will be done by cube proc
|
||||
var/mob/living/prisoner
|
||||
element_type = /obj/structure/puzzle_element/prison
|
||||
|
||||
/obj/effect/sliding_puzzle/prison/get_base_icon()
|
||||
if(!prisoner)
|
||||
CRASH("Prison cube without prisoner")
|
||||
prisoner.setDir(SOUTH)
|
||||
var/icon/I = getFlatIcon(prisoner)
|
||||
I.Scale(96,96)
|
||||
return I
|
||||
|
||||
/obj/effect/sliding_puzzle/prison/Destroy()
|
||||
if(prisoner)
|
||||
to_chat(prisoner,"<span class='userdanger'>With the cube broken by force, you can feel your body falling apart.</span>")
|
||||
prisoner.death()
|
||||
qdel(prisoner)
|
||||
. = ..()
|
||||
|
||||
/obj/effect/sliding_puzzle/prison/dispense_reward()
|
||||
prisoner.forceMove(get_turf(src))
|
||||
prisoner.notransform = FALSE
|
||||
prisoner = null
|
||||
|
||||
//Some armor so it's harder to kill someone by mistake. EDITED - Hugboxed
|
||||
/obj/structure/puzzle_element/prison
|
||||
resistance_flags = INDESTRUCTIBLE | ACID_PROOF | FIRE_PROOF | LAVA_PROOF
|
||||
|
||||
/obj/structure/puzzle_element/prison/relaymove(mob/user)
|
||||
return
|
||||
|
||||
/obj/item/prisoncube
|
||||
name = "Prison Cube"
|
||||
desc = "Dusty cube with humanoid imprint on it."
|
||||
icon = 'icons/obj/lavaland/artefacts.dmi'
|
||||
icon_state = "prison_cube"
|
||||
|
||||
/obj/item/prisoncube/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
|
||||
. = ..()
|
||||
if(!proximity_flag || !isliving(target))
|
||||
return
|
||||
var/mob/living/victim = target
|
||||
var/mob/living/carbon/carbon_victim = victim
|
||||
//Handcuffed or unconcious
|
||||
if(istype(carbon_victim) && carbon_victim.handcuffed || victim.stat != CONSCIOUS)
|
||||
if(!puzzle_imprison(target))
|
||||
to_chat(user,"<span class='warning'>[src] does nothing.</span>")
|
||||
return
|
||||
to_chat(user,"<span class='warning'>You trap [victim] in the prison cube!</span>")
|
||||
qdel(src)
|
||||
else
|
||||
to_chat(user,"<span class='notice'>[src] only accepts restrained or unconcious prisoners.</span>")
|
||||
|
||||
/proc/puzzle_imprison(mob/living/prisoner)
|
||||
var/turf/T = get_turf(prisoner)
|
||||
var/obj/effect/sliding_puzzle/prison/cube = new(T)
|
||||
if(!cube.check_setup_location())
|
||||
qdel(cube)
|
||||
return FALSE
|
||||
|
||||
//First grab the prisoner and move them temporarily into the generator so they won't get thrown around.
|
||||
prisoner.notransform = TRUE
|
||||
prisoner.forceMove(cube)
|
||||
to_chat(prisoner,"<span class='userdanger'>You're trapped by the prison cube! You will remain trapped until someone solves it.</span>")
|
||||
|
||||
//Clear the area from objects (and cube user)
|
||||
var/list/things_to_throw = list()
|
||||
for(var/atom/movable/AM in range(1,T))
|
||||
if(!AM.anchored)
|
||||
things_to_throw += AM
|
||||
|
||||
for(var/atom/movable/AM in things_to_throw)
|
||||
var/throwtarget = get_edge_target_turf(T, get_dir(T, get_step_away(AM, T)))
|
||||
AM.throw_at(throwtarget, 2, 3)
|
||||
|
||||
//Create puzzle itself
|
||||
cube.prisoner = prisoner
|
||||
cube.setup()
|
||||
|
||||
//Move them into random block
|
||||
var/obj/structure/puzzle_element/E = pick(cube.elements)
|
||||
prisoner.forceMove(E)
|
||||
return TRUE
|
||||
@@ -21,7 +21,6 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
|
||||
var/product_path = null
|
||||
var/amount = 0
|
||||
var/max_amount = 0
|
||||
var/display_color = "blue"
|
||||
|
||||
/obj/machinery/vending
|
||||
name = "\improper Vendomat"
|
||||
@@ -66,6 +65,8 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
|
||||
var/scan_id = 1
|
||||
var/obj/item/coin/coin
|
||||
var/obj/item/stack/spacecash/bill
|
||||
|
||||
var/global/vending_cache = list() //used for storing the icons of items being vended
|
||||
|
||||
var/dish_quants = list() //used by the snack machine's custom compartment to count dishes.
|
||||
|
||||
@@ -158,7 +159,6 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
|
||||
if(!start_empty)
|
||||
R.amount = amount
|
||||
R.max_amount = amount
|
||||
R.display_color = pick("#ff8080","#80ff80","#8080ff")
|
||||
recordlist += R
|
||||
|
||||
/obj/machinery/vending/proc/restock(obj/item/vending_refill/canister)
|
||||
@@ -317,7 +317,7 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/machinery/vending/interact(mob/user)
|
||||
/obj/machinery/vending/ui_interact(mob/user)
|
||||
var/dat = ""
|
||||
|
||||
dat += "<h3>Select an item</h3>"
|
||||
@@ -332,17 +332,16 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
|
||||
display_records = product_records + coin_records
|
||||
if((coin || bill) && extended_inventory)
|
||||
display_records = product_records + hidden_records + coin_records
|
||||
dat += "<ul>"
|
||||
dat += "<table>"
|
||||
for (var/datum/data/vending_product/R in display_records)
|
||||
dat += "<li>"
|
||||
dat += "<tr><td><img src='data:image/jpeg;base64,[GetIconForProduct(R)]'/></td>"
|
||||
dat += "<td style=\"width: 100%\"><b>[sanitize(R.name)]</b></td>"
|
||||
if(R.amount > 0)
|
||||
dat += "<a href='byond://?src=[REF(src)];vend=[REF(R)]'>Vend</a> "
|
||||
dat += "<td><b>[R.amount] </b></td><td><a href='byond://?src=[REF(src)];vend=[REF(R)]'>Vend</a></td>"
|
||||
else
|
||||
dat += "<span class='linkOff'>Sold out</span> "
|
||||
dat += "<font color = '[R.display_color]'><b>[sanitize(R.name)]</b>:</font>"
|
||||
dat += " <b>[R.amount]</b>"
|
||||
dat += "</li>"
|
||||
dat += "</ul>"
|
||||
dat += "<td>0 </td><td><span class='linkOff'>Vend</span></td>"
|
||||
dat += "</tr>"
|
||||
dat += "</table>"
|
||||
dat += "</div>"
|
||||
if(premium.len > 0)
|
||||
dat += "<b>Change Return:</b> "
|
||||
@@ -365,6 +364,14 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
|
||||
popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
|
||||
popup.open()
|
||||
|
||||
/obj/machinery/vending/proc/GetIconForProduct(datum/data/vending_product/P)
|
||||
if(vending_cache[P.product_path])
|
||||
return vending_cache[P.product_path]
|
||||
var/product = new P.product_path()
|
||||
vending_cache[P.product_path] = icon2base64(getFlatIcon(product, no_anim = TRUE))
|
||||
qdel(product)
|
||||
return vending_cache[P.product_path]
|
||||
|
||||
/obj/machinery/vending/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
@@ -461,10 +468,13 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
|
||||
use_power(5)
|
||||
if(icon_vend) //Show the vending animation if needed
|
||||
flick(icon_vend,src)
|
||||
new R.product_path(get_turf(src))
|
||||
var/vended = new R.product_path(get_turf(src))
|
||||
if(usr.put_in_hands(vended))
|
||||
to_chat(usr, "<span class='notice'>You take [R.name] out of the slot.</span>")
|
||||
else
|
||||
to_chat(usr, "<span class='warning'>[capitalize(R.name)] falls onto the floor!</span>")
|
||||
SSblackbox.record_feedback("nested tally", "vending_machine_usage", 1, list("[type]", "[R.product_path]"))
|
||||
vend_ready = 1
|
||||
return
|
||||
|
||||
updateUsrDialog()
|
||||
return
|
||||
|
||||
@@ -133,6 +133,12 @@ LOG_MANIFEST
|
||||
## As an example of how this could be """useful""" look towards Poly (https://twitter.com/Poly_the_Parrot)
|
||||
# LOG_TWITTER
|
||||
|
||||
## Enable logging pictures
|
||||
LOG_PICTURES
|
||||
|
||||
##Log camera pictures - Must have picture logging enabled
|
||||
PICTURE_LOGGING_CAMERA
|
||||
|
||||
## period of time in seconds for players to be considered inactive
|
||||
# INACTIVITY_PERIOD 300
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
author: "Hatterhat"
|
||||
delete-after: True
|
||||
changes:
|
||||
- tweak: "The plasma formerly present in some execution syringes was replaced with amatoxin."
|
||||
@@ -0,0 +1,4 @@
|
||||
author: "deathride58"
|
||||
delete-after: True
|
||||
changes:
|
||||
- rscadd: "Added Raiq's boombox as a donor item"
|
||||
@@ -0,0 +1,9 @@
|
||||
author: "kevinz000"
|
||||
delete-after: True
|
||||
changes:
|
||||
- rscadd: "Cameras now can take pictures up to 7x7. Alt click them to change their width/height from the default 3x3."
|
||||
- rscadd: "Photos are now logged to disk, assuming the host enabled the configuration option"
|
||||
- rscadd: "If the above is enabled, albums/frames can now have their persistence IDs set in variables to allow for PHOTO PERSISTENCE"
|
||||
- rscadd: "Every head of staff gets a unique album with its own ID in their locker. Let your successors know about your accomplishments, screwups, and everything in between!"
|
||||
- rscadd: "All of this works or should work with newcasters/pdas/etc etc"
|
||||
- rscadd: "Photo taking now clones the area into transit space and then operates on it, instead of on the spot, in theory making photographing things more accurate?"
|
||||
@@ -0,0 +1,5 @@
|
||||
author: "deathride58"
|
||||
delete-after: True
|
||||
changes:
|
||||
- balance: "The combat rework's training wheels have been removed. Knockdowns no longer have any noticeable stun. This indirectly means stunbatons and tasers will always deal their full stamloss on hit."
|
||||
- balance: "The stamloss required for boxing gloves to throw a knockout punch has been increased from 50 to 100."
|
||||
@@ -0,0 +1,6 @@
|
||||
author: "slate3"
|
||||
delete-after: True
|
||||
changes:
|
||||
- rscadd: "ported a new alternative sprite for engineering borgs, mr. handy"
|
||||
- rscadd: "ported a new alternative sprite for security borgs, a spider-like walker"
|
||||
- rscadd: "ported a new alternative sprite for medical borgs, an eyebot"
|
||||
@@ -0,0 +1,5 @@
|
||||
author: "nicc"
|
||||
delete-after: True
|
||||
changes:
|
||||
- tweak: "area alterations"
|
||||
- rscadd: "escape pod"
|
||||
@@ -0,0 +1,4 @@
|
||||
author: "Flatty"
|
||||
delete-after: True
|
||||
changes:
|
||||
- tweak: "The blurry eye overlay has been replaced with an actual blur."
|
||||
@@ -0,0 +1,4 @@
|
||||
author: "Flatty"
|
||||
delete-after: True
|
||||
changes:
|
||||
- tweak: "The vending machine UI is now prettier."
|
||||
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 165 KiB |
|
Before Width: | Height: | Size: 122 KiB After Width: | Height: | Size: 118 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 956 B |