mirror of
https://github.com/Citadel-Station-13/Citadel-Station-13-RP.git
synced 2026-08-27 11:06:33 +01:00
overhauls rendering + redoes some of widescreen/dynamic sizing + misc fixes (#4668)
Co-authored-by: VM_USER <VM_USER>
This commit is contained in:
co-authored by
VM_USER <VM_USER>
parent
798902257c
commit
bc5e0940a2
@@ -79,6 +79,7 @@
|
||||
#include "code\__DEFINES\shields.dm"
|
||||
#include "code\__DEFINES\shuttle.dm"
|
||||
#include "code\__DEFINES\shuttles.dm"
|
||||
#include "code\__DEFINES\skin.dm"
|
||||
#include "code\__DEFINES\sonar.dm"
|
||||
#include "code\__DEFINES\spaceman_dmm.dm"
|
||||
#include "code\__DEFINES\spans.dm"
|
||||
@@ -4210,6 +4211,8 @@
|
||||
#include "interface\interface.dm"
|
||||
#include "interface\stylesheet.dm"
|
||||
#include "interface\skin.dmf"
|
||||
#include "interface\menus\_menus.dm"
|
||||
#include "interface\menus\main.dm"
|
||||
#include "maps\Generic\death_triggers.dm"
|
||||
#include "maps\Generic\map_data.dm"
|
||||
#include "maps\Generic\misc.dm"
|
||||
|
||||
@@ -50,10 +50,10 @@ What is the naming convention for planes or layers?
|
||||
/// Reserved for use in space/parallax
|
||||
#define PARALLAX_PLANE -90
|
||||
/// everything layering below
|
||||
#define PARALLAX_VIS_LAYER_BELOW -10000
|
||||
#define PARALLAX_VIS_LAYER_BELOW -100
|
||||
#define PARALLAX_LAYER_CENTER 0
|
||||
/// ditto
|
||||
#define PARALLAX_VIS_LAYER_ABOVE 10000
|
||||
#define PARALLAX_VIS_LAYER_ABOVE 100
|
||||
///For the Looking Glass holodecks
|
||||
#define PLANE_LOOKINGGLASS -77
|
||||
///For the Looking Glass holodecks
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
//? WINCLONE IDs; NO SKIN CONTROL MAY HAVE THESE IDs, OR WINCLONE WILL NOT CREATE "NAKED" CONTROLS OF THIS TYPE!
|
||||
#define SKIN_ID_ABSTRACT_MENU "menu"
|
||||
#define SKIN_ID_ABSTRACT_WINDOW "window"
|
||||
#define SKIN_ID_ABSTRACT_PANE "pane"
|
||||
#define SKIN_ID_ABSTRACT_MACRO "macro"
|
||||
|
||||
//? SKIN ELEMENT IDS; MAKE SURE TO UPDATE THESE WHEN CHANGING SKIN.DMF.
|
||||
//! Window IDs
|
||||
/// main game window
|
||||
#define SKIN_WINDOW_ID_MAIN "mainwindow"
|
||||
|
||||
//! Map IDs
|
||||
/// main game viewport
|
||||
#define SKIN_MAP_ID_VIEWPORT "mapwindow.map"
|
||||
|
||||
//! Splitter IDs
|
||||
/// main window split
|
||||
#define SKIN_SPLITTER_ID_MAIN "mainwindow.split"
|
||||
|
||||
//? Dynamic skin IDs used by code-generated elements
|
||||
//? button groups MUST have unique ids to all skin elements!
|
||||
// TOP LEVEL MENU //
|
||||
#define SKIN_ID_MAIN_MENU "menu_main"
|
||||
// what it attaches to
|
||||
#define SKIN_ID_MAIN_MENU_ATTACH_TO "mainwindow"
|
||||
// categories
|
||||
#define SKIN_ID_MENU_CATEGORY_FILE "menu_file"
|
||||
#define SKIN_ID_MENU_CATEGORY_ZOOM "menu_zoom"
|
||||
#define SKIN_ID_MENU_CATEGORY_SCALING "menu_scaling"
|
||||
#define SKIN_ID_MENU_CATEGORY_HELP "menu_help"
|
||||
// groups
|
||||
#define SKIN_BUTTON_GROUP_MAP_ZOOM "group_map_zoom"
|
||||
#define SKIN_BUTTON_GROUP_MAP_SCALING "group_map_scaling"
|
||||
#define SKIN_BUTTON_GROUP_MAP_WIDESCREEN "group_map_widescreen"
|
||||
// buttons - file
|
||||
#define SKIN_ID_MENU_BUTTON_SCREENSHOT "menubutton_screenshot"
|
||||
#define SKIN_ID_MENU_BUTTON_SCREENSHOT_QUICK "menubutton_screenshot_quick"
|
||||
#define SKIN_ID_MENU_BUTTON_RECONNECT "menubutton_reconnect"
|
||||
#define SKIN_ID_MENU_BUTTON_PING "menubutton_ping"
|
||||
#define SKIN_ID_MENU_BUTTON_QUIT "menubutton_quit"
|
||||
// buttons - size
|
||||
#define SKIN_ID_MENU_BUTTON_STRETCH_TO_FIT "menubutton_stretchtofit"
|
||||
#define SKIN_ID_MENU_BUTTON_STRETCH_NO_LETTERBOX "menubutton_stretchtofill"
|
||||
#define SKIN_ID_MENU_BUTTON_FOR_RESOLUTION(resolution) "menubutton_[resolution]x[resolution]"
|
||||
#define SKIN_ID_MENU_BUTTON_WIDESCREEN_ENABLED "menubutton_widescreen_on"
|
||||
#define SKIN_ID_MENU_BUTTON_WIDESCREEN_DISABLED "menubutton_widescreen_off"
|
||||
#define SKIN_ID_MENU_BUTTON_AUTO_FIT_VIEWPORT "menubutton_auto_fit_viewport"
|
||||
#define SKIN_ID_MENU_BUTTON_FIT_VIEWPORT "menubutton_fit_viewport"
|
||||
// buttons - scaling
|
||||
#define SKIN_ID_MENU_BUTTON_NEAREST_NEIGHBOR "menubutton_scale_distort"
|
||||
#define SKIN_ID_MENU_BUTTON_POINT_SAMPLE "menubutton_scale_normal"
|
||||
#define SKIN_ID_MENU_BUTTON_BILINEAR "menubutton_scale_blur"
|
||||
// buttons - help
|
||||
#define SKIN_ID_MENU_BUTTON_ADMINHELP "menubutton_adminhelp"
|
||||
@@ -1,167 +1,3 @@
|
||||
/**
|
||||
* This is intended to be a full wrapper. DO NOT directly modify its values.
|
||||
* Container for client viewsize.
|
||||
*/
|
||||
/datum/view_data
|
||||
/// Width offset to apply to the default view string if we're not supressed for some reason.
|
||||
var/width = 0
|
||||
/// Height offset to apply to the default view string, see above.
|
||||
var/height = 0
|
||||
/**
|
||||
* This client's current "default" view, in the format "WidthxHeight".
|
||||
* We add/remove from this when we want to change their window size.
|
||||
*/
|
||||
var/default = ""
|
||||
/**
|
||||
* This client's current zoom level, if it's not being supressed.
|
||||
* If it's 0, we autoscale to the size of the window. Otherwise it's treated as the ratio between
|
||||
* the pixels on the map and output pixels. Only looks proper nice in increments of whole numbers (iirc).
|
||||
* Stored here so other parts of the code have a non blocking way of getting a user's functional zoom.
|
||||
*/
|
||||
var/zoom = 0
|
||||
/**
|
||||
* If the view is currently being supressed by some other "monitor".
|
||||
* For when you want to own the client's eye without fucking with their viewport.
|
||||
* Doesn't make sense for a binocoler to effect your view in a camera console.
|
||||
*/
|
||||
var/is_suppressed = FALSE
|
||||
/// The client that owns this view packet.
|
||||
var/client/chief = null
|
||||
|
||||
/datum/view_data/New(client/owner, view_string)
|
||||
default = view_string
|
||||
chief = owner
|
||||
apply()
|
||||
|
||||
/datum/view_data/proc/setDefault(string)
|
||||
default = string
|
||||
apply()
|
||||
|
||||
/datum/view_data/proc/safeApplyFormat()
|
||||
if(isZooming())
|
||||
assertFormat()
|
||||
return
|
||||
resetFormat()
|
||||
|
||||
/// T-Pose
|
||||
/datum/view_data/proc/assertFormat()
|
||||
// if(!is_preference_enabled(/datum/client_preference/scaling_viewport))
|
||||
// return
|
||||
// winset(chief, "mapwindow.map", "zoom=0")
|
||||
// We're using icon dropdown instead
|
||||
|
||||
/// Cuck
|
||||
/datum/view_data/proc/resetFormat()
|
||||
// if(!is_preference_enabled(/datum/client_preference/scaling_viewport))
|
||||
// return
|
||||
// winset(chief, "mapwindow.map", "zoom=[chief.prefs.pixel_size]")
|
||||
// We're using icon dropdown instead
|
||||
|
||||
/datum/view_data/proc/setZoomMode()
|
||||
// if(!is_preference_enabled(/datum/client_preference/scaling_viewport))
|
||||
// return
|
||||
// winset(chief, "mapwindow.map", "zoom-mode=[chief.prefs.scaling_method]")
|
||||
// We're using icon dropdown instead
|
||||
|
||||
/datum/view_data/proc/isZooming()
|
||||
return (width || height)
|
||||
|
||||
/datum/view_data/proc/resetToDefault()
|
||||
width = 0
|
||||
height = 0
|
||||
apply()
|
||||
|
||||
/datum/view_data/proc/add(toAdd)
|
||||
width += toAdd
|
||||
height += toAdd
|
||||
apply()
|
||||
|
||||
/datum/view_data/proc/addTo(toAdd)
|
||||
var/list/shitcode = getviewsize(toAdd)
|
||||
width += shitcode[1]
|
||||
height += shitcode[2]
|
||||
apply(toAdd)
|
||||
|
||||
/datum/view_data/proc/setTo(toAdd)
|
||||
/**
|
||||
* Backward compatability to account.
|
||||
* For a change in how sizes get calculated. we used to include world.view in
|
||||
* This, but it was jank, so I had to move it.
|
||||
*/
|
||||
var/list/shitcode = getviewsize(toAdd)
|
||||
width = shitcode[1]
|
||||
height = shitcode[2]
|
||||
apply(toAdd)
|
||||
|
||||
/datum/view_data/proc/setBoth(wid, hei)
|
||||
width = wid
|
||||
height = hei
|
||||
apply()
|
||||
|
||||
/datum/view_data/proc/setWidth(wid)
|
||||
width = wid
|
||||
apply()
|
||||
|
||||
/datum/view_data/proc/setHeight(hei)
|
||||
width = hei
|
||||
apply()
|
||||
|
||||
/datum/view_data/proc/addToWidth(toAdd)
|
||||
width += toAdd
|
||||
apply()
|
||||
|
||||
/datum/view_data/proc/addToHeight(screen, toAdd)
|
||||
height += toAdd
|
||||
apply()
|
||||
|
||||
/datum/view_data/proc/apply(forced)
|
||||
if(!chief.is_preference_enabled(/datum/client_preference/scaling_viewport) && !forced)
|
||||
return
|
||||
chief.change_view(getView(), forced)
|
||||
safeApplyFormat()
|
||||
if(chief.prefs.auto_fit_viewport)
|
||||
chief.fit_viewport()
|
||||
|
||||
/datum/view_data/proc/supress()
|
||||
is_suppressed = TRUE
|
||||
apply()
|
||||
|
||||
/datum/view_data/proc/unsupress()
|
||||
is_suppressed = FALSE
|
||||
apply()
|
||||
|
||||
/datum/view_data/proc/getView()
|
||||
var/list/temp = getviewsize(default)
|
||||
if(is_suppressed)
|
||||
return "[temp[1]]x[temp[2]]"
|
||||
return "[width + temp[1]]x[height + temp[2]]"
|
||||
|
||||
/datum/view_data/proc/zoomIn()
|
||||
resetToDefault()
|
||||
animate(chief, pixel_x = 0, pixel_y = 0, 0, FALSE, LINEAR_EASING, ANIMATION_END_NOW)
|
||||
|
||||
/datum/view_data/proc/zoomOut(radius = 0, offset = 0, direction = FALSE)
|
||||
if(direction)
|
||||
var/_x = 0
|
||||
var/_y = 0
|
||||
switch(direction)
|
||||
if(NORTH)
|
||||
_y = offset
|
||||
if(EAST)
|
||||
_x = offset
|
||||
if(SOUTH)
|
||||
_y = -offset
|
||||
if(WEST)
|
||||
_x = -offset
|
||||
animate(chief, pixel_x = world.icon_size*_x, pixel_y = world.icon_size*_y, 0, FALSE, LINEAR_EASING, ANIMATION_END_NOW)
|
||||
// Ready for this one?
|
||||
setTo(radius)
|
||||
/*
|
||||
/proc/getScreenSize(widescreen)
|
||||
if(widescreen)
|
||||
return CONFIG_GET(string/default_view)
|
||||
return CONFIG_GET(string/default_view_square)
|
||||
*/
|
||||
/proc/getviewsize(view)
|
||||
if(isnum(view))
|
||||
var/totalviewrange = 1 + 2 * view
|
||||
@@ -169,9 +5,3 @@
|
||||
else
|
||||
var/list/viewrangelist = splittext(view,"x")
|
||||
return list(text2num(viewrangelist[1]), text2num(viewrangelist[2]))
|
||||
|
||||
/proc/in_view_range(mob/user, atom/A)
|
||||
var/list/view_range = getviewsize(user.client.view)
|
||||
var/turf/source = get_turf(user)
|
||||
var/turf/target = get_turf(A)
|
||||
return ISINRANGE(target.x, source.x - view_range[1], source.x + view_range[1]) && ISINRANGE(target.y, source.y - view_range[1], source.y + view_range[1])
|
||||
|
||||
@@ -24,3 +24,12 @@ var/world_log_redirected = FALSE
|
||||
|
||||
/datum/world_log_shunter/New()
|
||||
world.ensure_logging_active()
|
||||
|
||||
//! Debugging
|
||||
var/datum/world_debug_enabler/world_debug_enabler = new
|
||||
|
||||
/datum/world_debug_enabler/New()
|
||||
var/debug_server = world.GetConfig("env", "AUXTOOLS_DEBUG_DLL")
|
||||
if (debug_server)
|
||||
call(debug_server, "auxtools_init")()
|
||||
enable_debugging()
|
||||
|
||||
+37
-38
@@ -6,6 +6,7 @@
|
||||
adjacency code.
|
||||
*/
|
||||
|
||||
// todo: unify with normal click procs
|
||||
/mob/living/silicon/robot/ClickOn(var/atom/A, var/params)
|
||||
if(world.time <= next_click)
|
||||
return
|
||||
@@ -15,23 +16,23 @@
|
||||
build_click(src, client.buildmode, params, A)
|
||||
return
|
||||
|
||||
var/list/modifiers = params2list(params)
|
||||
if(modifiers["shift"] && modifiers["ctrl"])
|
||||
var/list/unpacked_params = params2list(params)
|
||||
if(unpacked_params["shift"] && unpacked_params["ctrl"])
|
||||
CtrlShiftClickOn(A)
|
||||
return
|
||||
if(modifiers["shift"] && modifiers["middle"])
|
||||
if(unpacked_params["shift"] && unpacked_params["middle"])
|
||||
ShiftMiddleClickOn(A)
|
||||
return
|
||||
if(modifiers["middle"])
|
||||
if(unpacked_params["middle"])
|
||||
MiddleClickOn(A)
|
||||
return
|
||||
if(modifiers["shift"])
|
||||
if(unpacked_params["shift"])
|
||||
ShiftClickOn(A)
|
||||
return
|
||||
if(modifiers["alt"]) // alt and alt-gr (rightalt)
|
||||
if(unpacked_params["alt"]) // alt and alt-gr (rightalt)
|
||||
AltClickOn(A)
|
||||
return
|
||||
if(modifiers["ctrl"])
|
||||
if(unpacked_params["ctrl"])
|
||||
CtrlClickOn(A)
|
||||
return
|
||||
|
||||
@@ -58,49 +59,47 @@
|
||||
return
|
||||
*/
|
||||
|
||||
var/obj/item/W = get_active_held_item()
|
||||
//? Grab click semantics
|
||||
var/obj/item/I = get_active_held_item()
|
||||
|
||||
//? Core cyborg code
|
||||
// Cyborgs have no range-checking unless there is item use
|
||||
if(!W)
|
||||
if(!I)
|
||||
if(bolt && !bolt.malfunction && A.loc != module)
|
||||
return
|
||||
A.add_hiddenprint(src)
|
||||
A.attack_robot(src)
|
||||
return
|
||||
|
||||
// buckled cannot prevent machine interlinking but stops arm movement
|
||||
if( buckled )
|
||||
//? Handle special cases
|
||||
if(I == A)
|
||||
// attack_self
|
||||
I.attack_self(src)
|
||||
// todo: refactor
|
||||
trigger_aiming(TARGET_CAN_CLICK)
|
||||
return
|
||||
|
||||
if(W == A)
|
||||
//? check if we can click from our current location
|
||||
var/ranged_generics_allowed = loc?.AllowClick(src, A, I)
|
||||
|
||||
W.attack_self(src)
|
||||
return
|
||||
|
||||
// cyborgs are prohibited from using storage items so we can I think safely remove (A.loc in contents)
|
||||
if(A == loc || (A in loc) || (A in contents))
|
||||
// No adjacency checks
|
||||
|
||||
var/resolved = A.attackby(W, src, params)
|
||||
if(!resolved && A && W)
|
||||
W.afterattack(A,src,1,params)
|
||||
return
|
||||
|
||||
if(!isturf(loc))
|
||||
return
|
||||
|
||||
// cyborgs are prohibited from using storage items so we can I think safely remove (A.loc && isturf(A.loc.loc))
|
||||
if(isturf(A) || isturf(A.loc))
|
||||
if(A.Adjacent(src)) // see adjacent.dm
|
||||
|
||||
var/resolved = A.attackby(W, src, params)
|
||||
if(!resolved && A && W)
|
||||
W.afterattack(A, src, 1, params)
|
||||
return
|
||||
if(Reachability(A, null, I?.reach, I))
|
||||
//? attempt melee attack chain
|
||||
if(I)
|
||||
I.melee_attack_chain(A, src, CLICKCHAIN_HAS_PROXIMITY, unpacked_params)
|
||||
else
|
||||
W.afterattack(A, src, 0, params)
|
||||
return
|
||||
return
|
||||
melee_attack_chain(A, CLICKCHAIN_HAS_PROXIMITY, unpacked_params)
|
||||
// todo: refactor aiming
|
||||
trigger_aiming(TARGET_CAN_CLICK)
|
||||
return
|
||||
else if(ranged_generics_allowed)
|
||||
//? attempt ranged attack chain
|
||||
if(I)
|
||||
I.ranged_attack_chain(A, src, NONE, params)
|
||||
else
|
||||
ranged_attack_chain(A, NONE, unpacked_params)
|
||||
// todo: refactor aiming
|
||||
trigger_aiming(TARGET_CAN_CLICK)
|
||||
return
|
||||
|
||||
//Middle click cycles through selected modules.
|
||||
/mob/living/silicon/robot/MiddleClickOn(var/atom/A)
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
/atom/movable/screen
|
||||
name = ""
|
||||
icon = 'icons/mob/screen1.dmi'
|
||||
appearance_flags = TILE_BOUND|PIXEL_SCALE|NO_CLIENT_COLOR
|
||||
appearance_flags = PIXEL_SCALE | NO_CLIENT_COLOR
|
||||
layer = LAYER_HUD_BASE
|
||||
plane = PLANE_PLAYER_HUD
|
||||
var/obj/master = null //A reference to the object in the slot. Grabs or items, generally.
|
||||
|
||||
@@ -176,8 +176,6 @@
|
||||
|
||||
/mob/Login()
|
||||
. = ..()
|
||||
if(client?.is_preference_enabled(/datum/client_preference/scaling_viewport))
|
||||
INVOKE_ASYNC(client, /client.verb/SetWindowIconSize, client.prefs.icon_size)
|
||||
|
||||
if(ability_master)
|
||||
ability_master.toggle_open(1)
|
||||
|
||||
@@ -31,7 +31,9 @@
|
||||
*/
|
||||
|
||||
/atom/movable/screen/click_catcher/proc/UpdateFill(view_size_x, view_size_y)
|
||||
screen_loc = "1,1 to [view_size_x],[view_size_y]"
|
||||
var/matrix/transforming = matrix()
|
||||
transforming.Scale(view_size_x, view_size_y)
|
||||
transform = transforming
|
||||
|
||||
/atom/movable/screen/click_catcher/Click(location, control, params)
|
||||
var/list/modifiers = params2list(params)
|
||||
@@ -63,12 +65,8 @@
|
||||
/**
|
||||
* Makes a clickcatcher if necessary, and ensures it's fit to our size.
|
||||
*/
|
||||
/client/proc/update_clickcatcher(list/view_override)
|
||||
/client/proc/update_clickcatcher()
|
||||
if(!click_catcher)
|
||||
click_catcher = new
|
||||
screen |= click_catcher
|
||||
if(view_override)
|
||||
click_catcher.UpdateFill(view_override[1], view_override[2])
|
||||
else
|
||||
var/list/view_list = getviewsize(view)
|
||||
click_catcher.UpdateFill(view_list[1], view_list[2])
|
||||
click_catcher.UpdateFill(current_viewport_width, current_viewport_height)
|
||||
|
||||
@@ -14,6 +14,16 @@
|
||||
|
||||
reload_fullscreen()
|
||||
client.update_clickcatcher()
|
||||
INVOKE_ASYNC(client, /client/proc/init_viewport_blocking)
|
||||
|
||||
/**
|
||||
* reloads rendering after screen viewport size change
|
||||
*/
|
||||
/mob/proc/refit_rendering()
|
||||
client?.parallax_holder?.Reset(force = TRUE)
|
||||
reload_fullscreen()
|
||||
client?.update_clickcatcher()
|
||||
|
||||
/**
|
||||
* destroys screen rendering. call on mob del
|
||||
*/
|
||||
|
||||
@@ -175,6 +175,8 @@
|
||||
continue
|
||||
L.SetView(C.view, TRUE)
|
||||
. |= L
|
||||
if(vis_holder)
|
||||
. |= vis_holder
|
||||
C.screen |= .
|
||||
if(!secondary_map)
|
||||
var/atom/movable/screen/plane_master/parallax_white/PM = locate() in C.screen
|
||||
@@ -191,6 +193,7 @@
|
||||
if(QDELETED(C))
|
||||
return
|
||||
C.screen -= layers
|
||||
C.screen -= vis_holder
|
||||
if(!secondary_map)
|
||||
var/atom/movable/screen/plane_master/parallax_white/PM = locate() in C.screen
|
||||
if(PM)
|
||||
@@ -311,4 +314,5 @@
|
||||
parallax_holder = new(src)
|
||||
|
||||
/atom/movable/screen/parallax_vis
|
||||
screen_loc = "CENTER,CENTER"
|
||||
screen_loc = "LEFT,BOTTOM"
|
||||
icon = null
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
plane = PARALLAX_PLANE
|
||||
screen_loc = "CENTER-7,CENTER-7"
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
appearance_flags = PIXEL_SCALE | KEEP_TOGETHER
|
||||
appearance_flags = PIXEL_SCALE | KEEP_TOGETHER | TILE_BOUND
|
||||
|
||||
// notice - all parallax layers are 15x15 tiles. They roll over every 240 pixels.
|
||||
/// pixel x/y shift per real x/y
|
||||
|
||||
@@ -1,3 +1,30 @@
|
||||
/datum/config_entry/string/max_viewport_size
|
||||
default = "19x15"
|
||||
|
||||
/datum/config_entry/string/max_viewport_size/ValidateAndSet(str_val)
|
||||
if(!istext(str_val))
|
||||
return FALSE
|
||||
var/list/split = splittext(str_val, "x")
|
||||
if(length(split) != 2)
|
||||
return FALSE
|
||||
var/width = text2num(split[1])
|
||||
var/height = text2num(split[2])
|
||||
if(height < 1 || width < 1 || height > 67 || width > 67)
|
||||
return FALSE
|
||||
. = ..()
|
||||
if(!.)
|
||||
return
|
||||
config.update_player_viewsize()
|
||||
|
||||
/*
|
||||
/datum/config_entry/string/game_viewport_size
|
||||
default = "19x15"
|
||||
|
||||
/datum/config_entry/string/max_viewport_size/ValidateAndSet(str_val)
|
||||
. = ..()
|
||||
*/
|
||||
//! BYONd world.view is immutable, this config is left here as a todo. If it's still immutable by, say, 516, remove it.
|
||||
|
||||
/datum/config_entry/number/starlight
|
||||
default = 2
|
||||
|
||||
@@ -51,13 +78,3 @@
|
||||
|
||||
/datum/config_entry/flag/emojis
|
||||
default = TRUE
|
||||
|
||||
/datum/config_entry/number/max_client_view_x
|
||||
default = 21
|
||||
min_val = 15
|
||||
max_val = 50 // Byond (the) limits
|
||||
|
||||
/datum/config_entry/number/max_client_view_y
|
||||
default = 15
|
||||
min_val = 15
|
||||
max_val = 50 // Byond (the) limits
|
||||
|
||||
@@ -11,3 +11,6 @@
|
||||
|
||||
/// The mob the client controls
|
||||
var/mob/mob
|
||||
|
||||
var/current_viewport_width = 15
|
||||
var/current_viewport_height = 15
|
||||
|
||||
+135
-17
@@ -3,6 +3,25 @@
|
||||
*
|
||||
* allows managed control of client viewport/eye changes
|
||||
*
|
||||
* ! - - - ATTENTION - - -
|
||||
* ! These datums will modify mob variables.
|
||||
* ! This can result in AI mobs having inconsistent sight/whatevers
|
||||
* ! from what they'd usually have after a player enters, and
|
||||
* ! leaves them.
|
||||
* ! Mob reset_perspective() should handle most of these cases, but be wary.
|
||||
*
|
||||
* ! - - - ATTENTION - - -
|
||||
* ! View sizes should only be for clients.
|
||||
* ! Do not read off this for stuff like AI view/target tracking.
|
||||
*
|
||||
* ? - - - ATTENTION - - -
|
||||
* ? We track MAXIMUM view sizes.
|
||||
* ? Client can resize up/down as needed.
|
||||
* ? If you want to force a client to a specific size,
|
||||
* ? regardless of their widescreen setting,
|
||||
* ? use client.set_temporary_view.
|
||||
* ? Augmented view will also ignore client prefs on widescreen, *kinda.*
|
||||
*
|
||||
* as of right now, perspectives will **trample** the following on every set:
|
||||
* client.eye
|
||||
* client.lazy_eye (unimplemented)
|
||||
@@ -42,11 +61,9 @@
|
||||
/// sight var
|
||||
var/sight = SEE_SELF
|
||||
/// active clients - this is not the same as mobs because a client can be looking somewhere that isn't their mob
|
||||
var/list/client/clients = list()
|
||||
var/list/client/clients
|
||||
/// mobs that are using this - required for clean gcs
|
||||
var/list/mob/mobs = list()
|
||||
/// view size
|
||||
var/view_size
|
||||
/// when a client logs out of a mob, and it's using us, the mob should reset to its self_perspective
|
||||
var/reset_on_logout = TRUE
|
||||
/// see in dark
|
||||
@@ -54,6 +71,22 @@
|
||||
/// see_invisible
|
||||
var/see_invisible = SEE_INVISIBLE_LIVING
|
||||
|
||||
//! view size
|
||||
/// default view; if null, world.view
|
||||
var/default_view_size
|
||||
/// view size increase x
|
||||
var/augment_view_width = 0
|
||||
/// view size increase y
|
||||
var/augment_view_height = 0
|
||||
/// suppression sources
|
||||
var/list/view_suppression
|
||||
/// cached view x
|
||||
var/cached_view_width
|
||||
/// cached view y
|
||||
var/cached_view_height
|
||||
/// view cache needs recompute
|
||||
var/view_dirty = TRUE
|
||||
|
||||
/datum/perspective/Destroy()
|
||||
KickAll()
|
||||
ClearMobs()
|
||||
@@ -73,7 +106,7 @@
|
||||
return
|
||||
if(C.using_perspective)
|
||||
CRASH("client already had perspective")
|
||||
clients += C
|
||||
LAZYADD(clients, C)
|
||||
C.using_perspective = src
|
||||
SEND_SIGNAL(src, COMSIG_PERSPECTIVE_CLIENT_REGISTER, C)
|
||||
Apply(C)
|
||||
@@ -85,7 +118,7 @@
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
if(!(C in clients))
|
||||
return
|
||||
clients -= C
|
||||
LAZYREMOVE(clients, C)
|
||||
Remove(C)
|
||||
// if we're not doing this as part of a switch have them immediately switch to the mob
|
||||
// oh and make sure they unregister
|
||||
@@ -100,7 +133,7 @@
|
||||
* gets all clients viewing us
|
||||
*/
|
||||
/datum/perspective/proc/GetClients()
|
||||
return clients.Copy()
|
||||
return isnull(clients)? list() : clients.Copy()
|
||||
|
||||
/**
|
||||
* kicks all clients off us
|
||||
@@ -118,6 +151,7 @@
|
||||
|
||||
/**
|
||||
* registers as a mob's current perspective
|
||||
* sets mob vars as necessary
|
||||
*/
|
||||
/datum/perspective/proc/AddMob(mob/M)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
@@ -127,13 +161,20 @@
|
||||
return
|
||||
mobs += M
|
||||
M.using_perspective = src
|
||||
M.sight = sight
|
||||
M.see_in_dark = see_in_dark
|
||||
M.see_invisible = see_invisible
|
||||
SEND_SIGNAL(src, COMSIG_PERSPECTIVE_MOB_ADD, M)
|
||||
|
||||
/**
|
||||
* unregisters as a mob's current perspective
|
||||
* resets mob vars to initial() values
|
||||
*/
|
||||
/datum/perspective/proc/RemoveMob(mob/M, switching = FALSE)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
M.sight = initial(M.sight)
|
||||
M.see_in_dark = initial(M.see_in_dark)
|
||||
M.see_invisible = initial(M.see_invisible)
|
||||
mobs -= M
|
||||
SEND_SIGNAL(src, COMSIG_PERSPECTIVE_MOB_REMOVE, M, switching)
|
||||
if(M.using_perspective == src)
|
||||
@@ -184,11 +225,7 @@
|
||||
if(changed != C.eye)
|
||||
C.parallax_holder?.Reset(force = TRUE)
|
||||
C.perspective = GetEyeMode(C)
|
||||
C.mob.sight = sight
|
||||
C.mob.see_in_dark = see_in_dark
|
||||
C.mob.see_invisible = see_invisible
|
||||
if(view_size)
|
||||
C.change_view(view_size, TRUE)
|
||||
update_view_size(C)
|
||||
|
||||
/**
|
||||
* update all viewers
|
||||
@@ -294,13 +331,94 @@
|
||||
for(var/client/C as anything in clients)
|
||||
C.mob.see_invisible = see_invisible
|
||||
|
||||
/datum/perspective/proc/SetViewSize(new_size)
|
||||
var/change = view_size == new_size
|
||||
view_size = new_size
|
||||
if(change)
|
||||
for(var/client/C as anything in clients)
|
||||
C.change_view(new_size, TRUE)
|
||||
//! view size
|
||||
/**
|
||||
* Sets our default size.
|
||||
*
|
||||
* DO NOT use this in place of augmented.
|
||||
* User widescreen preferences WILL override this!
|
||||
*
|
||||
* Ideally this shouldn't be used at all.
|
||||
*/
|
||||
/datum/perspective/proc/set_default_view(size)
|
||||
if(size == default_view_size)
|
||||
return
|
||||
// assert it y'know, works
|
||||
if(isnum(size))
|
||||
default_view_size = size
|
||||
else if(isnull(size))
|
||||
default_view_size = size
|
||||
else if(istext(size))
|
||||
var/list/split = splittext(size, "x")
|
||||
ASSERT(split.len == 2)
|
||||
// if the above runtimes, let it so we know who fucked up
|
||||
default_view_size = size
|
||||
else
|
||||
CRASH("What?")
|
||||
view_dirty = TRUE
|
||||
update_view_size()
|
||||
|
||||
/**
|
||||
* Sets augmented size ontop of default size.
|
||||
*
|
||||
* Currently only supports positive numbers. Numbers apply equally
|
||||
* to both directions of a dimension.
|
||||
*/
|
||||
/datum/perspective/proc/set_augmented_view(width, height)
|
||||
if(!isnum(height) || !isnum(width))
|
||||
CRASH("invalid")
|
||||
// no negative augment values for now
|
||||
augment_view_height = max(0, height)
|
||||
augment_view_width = max(0, width)
|
||||
view_dirty = TRUE
|
||||
update_view_size()
|
||||
|
||||
/datum/perspective/proc/update_view_size(client/C)
|
||||
if(view_dirty)
|
||||
recompute_view_size()
|
||||
if(C)
|
||||
C.request_viewport_update()
|
||||
else
|
||||
for(var/client/_C as anything in clients)
|
||||
update_view_size(_C)
|
||||
|
||||
/datum/perspective/proc/recompute_view_size()
|
||||
view_dirty = FALSE
|
||||
if(isnum(default_view_size))
|
||||
cached_view_height = default_view_size + augment_view_width
|
||||
cached_view_width = default_view_size + augment_view_height
|
||||
return
|
||||
else if(isnull(default_view_size))
|
||||
cached_view_width = GLOB.max_client_view_x + augment_view_width
|
||||
cached_view_height = GLOB.max_client_view_y + augment_view_height
|
||||
return
|
||||
var/list/parsed = splittext(default_view_size, "x")
|
||||
if(length(parsed) != 2)
|
||||
cached_view_width = GLOB.max_client_view_x + augment_view_width
|
||||
cached_view_height = GLOB.max_client_view_y + augment_view_height
|
||||
return
|
||||
cached_view_width = parsed[1] + augment_view_width
|
||||
cached_view_height = parsed[2] + augment_view_height
|
||||
|
||||
/datum/perspective/proc/suppress_view(source)
|
||||
var/was = LAZYLEN(view_suppression)
|
||||
LAZYOR(view_suppression, source)
|
||||
if(!was && LAZYLEN(view_suppression))
|
||||
view_dirty = TRUE
|
||||
update_view_size()
|
||||
|
||||
/datum/perspective/proc/unsuppress_view(source)
|
||||
var/was = LAZYLEN(view_suppression)
|
||||
LAZYREMOVE(view_suppression, source)
|
||||
if(was && !LAZYLEN(view_suppression))
|
||||
view_dirty = TRUE
|
||||
update_view_size()
|
||||
|
||||
/datum/perspective/proc/ensure_view_cached()
|
||||
if(view_dirty)
|
||||
recompute_view_size()
|
||||
|
||||
//! remotes
|
||||
/datum/perspective/proc/considered_remote(mob/M)
|
||||
return eye == M
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/atom/movable
|
||||
layer = OBJ_LAYER
|
||||
appearance_flags = TILE_BOUND|PIXEL_SCALE|KEEP_TOGETHER
|
||||
// todo: evaluate if we need TILE_BOUND
|
||||
SET_APPEARANCE_FLAGS(TILE_BOUND | PIXEL_SCALE)
|
||||
|
||||
// todo: kill this (only used for elcetropacks)
|
||||
var/moved_recently = FALSE
|
||||
|
||||
@@ -225,7 +225,12 @@
|
||||
//causes damage when running into objects
|
||||
/obj/mecha/combat/fighter/Bump(atom/obstacle)
|
||||
. = ..()
|
||||
// this isn't defined becuase this is shitcode anyways and i'm just patching it
|
||||
// todo: why the fuck are you guys doing snowflake collision code??
|
||||
if(TIMER_COOLDOWN_CHECK(src, "fighter_collision"))
|
||||
return
|
||||
if(istype(obstacle, /obj) || istype(obstacle, /turf))
|
||||
TIMER_COOLDOWN_START(src, "fighter_collision", 5 SECONDS)
|
||||
occupant_message("<B><FONT COLOR=red SIZE=+1>Collision Alert!</B></FONT>")
|
||||
take_damage(20, "brute")
|
||||
playsound(src, 'sound/effects/grillehit.ogg', 50, 1)
|
||||
|
||||
@@ -837,7 +837,7 @@
|
||||
/obj/mecha/proc/mechstep(direction)
|
||||
var/current_dir = dir //For strafing
|
||||
var/result = get_step(src,direction)
|
||||
if(result && Move(result))
|
||||
if(result && Move(result, direction))
|
||||
if(stomp_sound)
|
||||
playsound(src,stomp_sound,40,1)
|
||||
handle_equipment_movement()
|
||||
|
||||
@@ -363,10 +363,10 @@
|
||||
src.log_message("Toggled zoom mode.")
|
||||
src.occupant_message("<font color='[src.zoom?"blue":"red"]'>Zoom mode [zoom?"en":"dis"]abled.</font>")
|
||||
if(zoom)
|
||||
myclient.change_view(12, TRUE)
|
||||
myclient.set_temporary_view(GLOB.max_client_view_x + 5, GLOB.max_client_view_y + 5)
|
||||
src.occupant << sound('sound/mecha/imag_enh.ogg',volume=50)
|
||||
else
|
||||
myclient.change_view("[myclient.last_view_x_dim*2]x[myclient.last_view_y_dim*2]", TRUE) // Reset to default
|
||||
myclient.reset_temporary_view()
|
||||
return
|
||||
|
||||
|
||||
|
||||
@@ -629,11 +629,11 @@ modules/mob/living/carbon/human/life.dm if you die, you will be zoomed out.
|
||||
else if(!zoom && user.item_by_slot(wornslot) != src && wornslot != FALSE)
|
||||
to_chat(user, "You need to wear the [devicename] to look through it properly")
|
||||
cannotzoom = 1
|
||||
|
||||
//We checked above if they are a human and returned already if they weren't.
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(!zoom && !cannotzoom)
|
||||
INVOKE_ASYNC(H.client, /client.proc/change_view, viewsize, TRUE) // Reset to default
|
||||
H.ensure_self_perspective()
|
||||
H.self_perspective.set_augmented_view(viewsize - 2, viewsize - 2)
|
||||
zoom = 1
|
||||
|
||||
var/tilesize = 32
|
||||
@@ -652,14 +652,12 @@ modules/mob/living/carbon/human/life.dm if you die, you will be zoomed out.
|
||||
if (WEST)
|
||||
H.client.pixel_x = -viewoffset
|
||||
H.client.pixel_y = 0
|
||||
|
||||
H.visible_message("[user] peers through the [zoomdevicename ? "[zoomdevicename] of the [src.name]" : "[src.name]"].")
|
||||
H.looking_elsewhere = TRUE
|
||||
H.handle_vision()
|
||||
|
||||
else
|
||||
|
||||
|
||||
H.ensure_self_perspective()
|
||||
H.self_perspective.set_augmented_view(0, 0)
|
||||
zoom = 0
|
||||
|
||||
H.client.pixel_x = 0
|
||||
@@ -667,8 +665,6 @@ modules/mob/living/carbon/human/life.dm if you die, you will be zoomed out.
|
||||
H.looking_elsewhere = FALSE
|
||||
H.handle_vision()
|
||||
|
||||
INVOKE_ASYNC(H.client, H.client.is_preference_enabled(/datum/client_preference/scaling_viewport) ? /client.verb/OnResize : /client.proc/change_view, world.view) // Reset to default
|
||||
|
||||
if(!cannotzoom)
|
||||
user.visible_message("[zoomdevicename ? "[user] looks up from the [src.name]" : "[user] lowers the [src.name]"].")
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ when portals are shortly lived, or when portals are made to be obvious with spec
|
||||
opacity = TRUE
|
||||
plane = TURF_PLANE
|
||||
layer = ABOVE_TURF_LAYER
|
||||
appearance_flags = PIXEL_SCALE|KEEP_TOGETHER // Removed TILE_BOUND so things not visible on the other side stay hidden from the viewer.
|
||||
SET_APPEARANCE_FLAGS(PIXEL_SCALE)
|
||||
|
||||
var/obj/effect/map_effect/portal/counterpart = null // The portal line or master that this is connected to, on the 'other side'.
|
||||
|
||||
|
||||
+1
-7
@@ -18,13 +18,6 @@ GLOBAL_LIST(topic_status_cache)
|
||||
//This happens after the Master subsystem new(s) (it's a global datum)
|
||||
//So subsystems globals exist, but are not initialised
|
||||
/world/New()
|
||||
//! init auxtools
|
||||
var/debug_server = world.GetConfig("env", "AUXTOOLS_DEBUG_DLL")
|
||||
if (debug_server)
|
||||
call(debug_server, "auxtools_init")()
|
||||
enable_debugging()
|
||||
// AUXTOOLS_CHECK(AUXTOOLS_YAML)
|
||||
|
||||
log_world("World loaded at [TIME_STAMP("hh:mm:ss", FALSE)]!")
|
||||
|
||||
var/tempfile = "data/logs/config_error.[GUID()].log" //temporary file used to record errors with loading config, moved to log directory once logging is set
|
||||
@@ -40,6 +33,7 @@ GLOBAL_LIST(topic_status_cache)
|
||||
InitTgs()
|
||||
|
||||
config.Load(params[OVERRIDE_CONFIG_DIRECTORY_PARAMETER])
|
||||
config.update_world_viewsize() //! Since world.view is immutable, we load it here.
|
||||
|
||||
//SetupLogs depends on the RoundID, so lets check
|
||||
//DB schema and set RoundID if we can
|
||||
|
||||
@@ -54,6 +54,12 @@
|
||||
/proc/_ispath(path, type)
|
||||
return ispath(path, type)
|
||||
|
||||
/proc/_json_encode(list/L)
|
||||
return json_encode(L)
|
||||
|
||||
/proc/_json_decode(json)
|
||||
return json_decode(json)
|
||||
|
||||
/proc/_length(E)
|
||||
return length(E)
|
||||
|
||||
@@ -153,9 +159,17 @@
|
||||
/proc/_sin(X)
|
||||
return sin(X)
|
||||
|
||||
/proc/_list2params(L)
|
||||
return list2params(L)
|
||||
|
||||
/proc/_list_construct(...)
|
||||
. = args.Copy()
|
||||
|
||||
/proc/_list_construct_assoc(...)
|
||||
. = list()
|
||||
for(var/i in 1 to (args.len - 1) step 2)
|
||||
.[args[i]] = args[i+1]
|
||||
|
||||
/proc/_list_add(list/L, ...)
|
||||
if (args.len < 2)
|
||||
return
|
||||
|
||||
@@ -831,11 +831,11 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
set name = "Change View Range"
|
||||
set desc = "switches between 1x and custom views"
|
||||
|
||||
var/view = src.view
|
||||
if(view == world.view)
|
||||
view = input("Select view range:", "FUCK YE", 7) in list(1,2,3,4,5,6,7,8,9,10,11,12,13,14,128)
|
||||
if(!using_temporary_viewsize)
|
||||
var/number = input("Select view range:", "FUCK YE", 7) in list(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,18,20,22,24,26,28,30,32,34)
|
||||
set_temporary_view(number * 2 + 1, number * 2 + 1)
|
||||
else
|
||||
SetWindowIconSize(prefs.icon_size)
|
||||
reset_temporary_view()
|
||||
|
||||
log_admin("[key_name(usr)] changed their view range to [view].")
|
||||
//message_admins("<font color=#4F49AF>[key_name_admin(usr)] changed their view range to [view].</font>", 1) //why? removed by order of XSI
|
||||
|
||||
@@ -53,6 +53,35 @@
|
||||
/// the perspective we're currently using
|
||||
var/datum/perspective/using_perspective
|
||||
|
||||
//! Viewport
|
||||
/// what we *think* their current viewport size is in pixels
|
||||
var/assumed_viewport_spx
|
||||
/// what we *think* their current viewport size is in pixels
|
||||
var/assumed_viewport_spy
|
||||
/// what we *think* their current viewport zoom is
|
||||
var/assumed_viewport_zoom
|
||||
/// what we *think* their current viewport letterboxing setting is
|
||||
var/assumed_viewport_box
|
||||
/// current view x - for fast access
|
||||
var/current_viewport_width
|
||||
/// current view y - for fast access
|
||||
var/current_viewport_height
|
||||
/// if things are manipulating the viewport we don't want other things to touch it
|
||||
var/viewport_rwlock = TRUE //! default block so we can release it during init_viewport
|
||||
/// viewport update queued?
|
||||
var/viewport_queued = FALSE
|
||||
/// forced temporary view
|
||||
var/temporary_viewsize_width
|
||||
/// forced temporary view
|
||||
var/temporary_viewsize_height
|
||||
/// temporary view active?
|
||||
var/using_temporary_viewsize = FALSE
|
||||
|
||||
//! menu button statuses
|
||||
var/list/menu_buttons_checked = list()
|
||||
//! menu group statuses
|
||||
var/list/menu_group_status = list()
|
||||
|
||||
////////////////
|
||||
//ADMIN THINGS//
|
||||
////////////////
|
||||
@@ -149,6 +178,3 @@
|
||||
|
||||
/// If this client has been fully initialized or not
|
||||
var/fully_created = FALSE
|
||||
|
||||
/// datum wrapper for client view
|
||||
var/datum/view_data/view_size
|
||||
|
||||
@@ -151,32 +151,38 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
///////////
|
||||
|
||||
/client/New(TopicData)
|
||||
//! pre-connect-ish
|
||||
// set appadmin for profiling or it might not work (?) (this is old code we just assume it's here for a reason)
|
||||
world.SetConfig("APP/admin", ckey, "role=admin")
|
||||
//var/tdata = TopicData //save this for later use
|
||||
TopicData = null //Prevent calls to client.Topic from connect
|
||||
|
||||
if(connection != "seeker" && connection != "web")//Invalid connection type.
|
||||
// block client.Topic() calls from connect
|
||||
TopicData = null
|
||||
// kick out invalid connections
|
||||
if(connection != "seeker" && connection != "web")
|
||||
return null
|
||||
|
||||
// kick out guests
|
||||
if(!config_legacy.guests_allowed && IsGuestKey(key))
|
||||
alert(src,"This server doesn't allow guest accounts to play. Please go to http://www.byond.com/ and register for a key.","Guest","OK")
|
||||
del(src)
|
||||
return
|
||||
|
||||
// pre-connect greeting
|
||||
to_chat(src, "<font color='red'>If the title screen is black, resources are still downloading. Please be patient until the title screen appears.</font>")
|
||||
|
||||
// register in globals
|
||||
GLOB.clients += src
|
||||
GLOB.directory[ckey] = src
|
||||
|
||||
//! Resolve storage datums
|
||||
// resolve persistent data
|
||||
persistent = resolve_client_data(ckey)
|
||||
// todo: move resolve database data up here
|
||||
// todo: move resolve database data up here but above preferences
|
||||
// todo: move preferences up here but above persistent
|
||||
|
||||
//! Setup user interface
|
||||
// todo: move top level menu here, for now it has to be under prefs.
|
||||
// Instantiate tgui panel
|
||||
tgui_panel = new(src, "browseroutput")
|
||||
|
||||
//! Setup admin tooling
|
||||
GLOB.ahelp_tickets.ClientLogin(src)
|
||||
SSserver_maint.UpdateHubStatus()
|
||||
var/connecting_admin = FALSE //because de-admined admins connecting should be treated like admins.
|
||||
//Admin Authorisation
|
||||
holder = admin_datums[ckey]
|
||||
@@ -221,6 +227,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
if(!debug_tools_allowed)
|
||||
world.SetConfig("APP/admin", ckey, null)
|
||||
//END CITADEL EDIT
|
||||
// todo: refactor and hoist
|
||||
//preferences datum - also holds some persistent data for the client (because we may as well keep these datums to a minimum)
|
||||
prefs = GLOB.preferences_datums[ckey]
|
||||
if(!prefs)
|
||||
@@ -228,10 +235,15 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
GLOB.preferences_datums[ckey] = prefs
|
||||
|
||||
prefs.client = src
|
||||
// todo: refactor
|
||||
prefs.last_ip = address //these are gonna be used for banning
|
||||
prefs.last_id = computer_id //these are gonna be used for banning
|
||||
//fps = prefs.clientfps //(prefs.clientfps < 0) ? RECOMMENDED_FPS : prefs.clientfps
|
||||
|
||||
// todo: hoist
|
||||
// build top level menu
|
||||
GLOB.main_window_menu.setup(src)
|
||||
|
||||
var/full_version = "[byond_version].[byond_build ? byond_build : "xxx"]"
|
||||
log_access("Login: [key_name(src)] from [address ? address : "localhost"]-[computer_id] || BYOND v[full_version]")
|
||||
/*
|
||||
@@ -382,6 +394,8 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
|
||||
send_resources()
|
||||
|
||||
//? Startup rendering
|
||||
pre_init_viewport()
|
||||
mob.reload_rendering()
|
||||
|
||||
if(prefs.lastchangelog != GLOB.changelog_hash) //bolds the changelog button on the interface so we know there are updates.
|
||||
@@ -401,8 +415,13 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
if(isnum(account_age) && account_age <= 2)
|
||||
log_and_message_admins("PARANOIA: [key_name(src)] has a very new BYOND account ([account_age] days).")
|
||||
|
||||
//? We are done
|
||||
// set initialized
|
||||
initialized = TRUE
|
||||
// show any migration errors
|
||||
prefs.auto_flush_errors()
|
||||
// update our hub label
|
||||
SSserver_maint.UpdateHubStatus()
|
||||
|
||||
//////////////
|
||||
//DISCONNECT//
|
||||
@@ -744,40 +763,38 @@ GLOBAL_VAR_INIT(log_clicks, FALSE)
|
||||
. = ..()
|
||||
|
||||
/client/proc/change_view(new_size, forced, translocate)
|
||||
if(!is_preference_enabled(/datum/client_preference/scaling_viewport))
|
||||
if (isnull(new_size))
|
||||
CRASH("change_view called without argument.")
|
||||
set waitfor = FALSE // to async temporary view
|
||||
// todo: refactor this, client view changes should be ephemeral.
|
||||
var/list/L = getviewsize(new_size)
|
||||
set_temporary_view(L[1], L[2])
|
||||
|
||||
if(view == new_size)
|
||||
// unnecessary
|
||||
return
|
||||
/**
|
||||
* directly sets our view
|
||||
* you should probably be using perspective datums most of the time instead
|
||||
* WARNING: this is verbatim; aka, view = 7 is 15 width 15 height, NOT 7x7!
|
||||
*
|
||||
* furthermore, this proc is BLOCKING.
|
||||
*/
|
||||
/client/proc/set_temporary_view(width, height)
|
||||
if(!width || !height || width < 0 || height < 0)
|
||||
reset_temporary_view()
|
||||
return
|
||||
using_temporary_viewsize = FALSE
|
||||
temporary_viewsize_width = width
|
||||
temporary_viewsize_height = height
|
||||
request_viewport_update()
|
||||
|
||||
/*
|
||||
if(prefs && !prefs.widescreenpref && new_size == CONFIG_GET(string/default_view))
|
||||
new_size = CONFIG_GET(string/default_view_square)
|
||||
*/
|
||||
|
||||
view = new_size
|
||||
mob.reload_rendering()
|
||||
if(!translocate)
|
||||
reset_perspective()
|
||||
else if(!. || forced)
|
||||
if(!translocate)
|
||||
reset_perspective()
|
||||
mob?.reload_fullscreen()
|
||||
update_clickcatcher()
|
||||
if(forced)
|
||||
view = new_size
|
||||
else
|
||||
INVOKE_ASYNC(src, /client.verb/OnResize)
|
||||
/*
|
||||
mob.reload_fullscreen()
|
||||
if (isliving(mob))
|
||||
var/mob/living/M = mob
|
||||
M.update_damage_hud()
|
||||
if (prefs.auto_fit_viewport)
|
||||
addtimer(CALLBACK(src,.verb/fit_viewport,10)) //Delayed to avoid wingets from Login calls.
|
||||
*/
|
||||
/**
|
||||
* resets our temporary view
|
||||
* you should probably be using perspective datums most of the time instead
|
||||
*
|
||||
* furthermore, this proc is BLOCKING
|
||||
*/
|
||||
/client/proc/reset_temporary_view()
|
||||
using_temporary_viewsize = FALSE
|
||||
temporary_viewsize_height = null
|
||||
temporary_viewsize_width = null
|
||||
request_viewport_update()
|
||||
|
||||
/**
|
||||
* switch perspective - null will cause us to shunt our eye to nullspace!
|
||||
|
||||
@@ -235,49 +235,3 @@
|
||||
if(eyeobj)
|
||||
return eyeobj
|
||||
return src
|
||||
|
||||
/client/verb/fit_viewport()
|
||||
set name = "Fit Viewport"
|
||||
set category = "OOC"
|
||||
set desc = "Fit the width of the map window to match the viewport"
|
||||
|
||||
// Fetch the client's aspect ratio
|
||||
var/view_size = getviewsize(view)
|
||||
var/aspect_ratio = view_size[1] / view_size[2]
|
||||
|
||||
// Calculate desired pixel width using window size and aspect ratio
|
||||
var/sizes = params2list(winget(src, "mainwindow.split;mapwindow", "size"))
|
||||
var/map_size = splittext(sizes["mapwindow.size"], "x")
|
||||
var/height = text2num(map_size[2])
|
||||
var/desired_width = round(height * aspect_ratio)
|
||||
if (text2num(map_size[1]) == desired_width)
|
||||
return // You're already good fam.
|
||||
|
||||
var/split_size = splittext(sizes["mainwindow.split.size"], "x")
|
||||
var/split_width = text2num(split_size[1])
|
||||
|
||||
// Calculate and apply our best estimate
|
||||
// +4 pixels are for the eidth of the splitter's handle
|
||||
var/pct = 100 * (desired_width + 4) / split_width
|
||||
winset(src, "mainwindow.split", "splitter=[pct]")
|
||||
|
||||
// Apply an ever-lowering offset until we finish or fail
|
||||
var/delta
|
||||
for(var/safety in 1 to 10)
|
||||
var/after_size = winget(src, "mapwindow", "size")
|
||||
map_size = splittext(after_size, "x")
|
||||
var/got_width = text2num(map_size[1])
|
||||
|
||||
if (got_width == desired_width)
|
||||
return // Success!
|
||||
|
||||
// Calculate a probable delta value based on the diff
|
||||
else if (isnull(delta))
|
||||
delta = 100 * (desired_width - got_width) / split_width
|
||||
|
||||
// If we overshot, halve the delta and reverse direction
|
||||
else if ((delta > 0 && got_width > desired_width) || (delta < 0 && got_width < desired_width))
|
||||
delta = -delta/2
|
||||
|
||||
pct += delta
|
||||
winset(src, "mainwindow.split", "splitter=[pct]")
|
||||
|
||||
+388
-63
@@ -1,78 +1,401 @@
|
||||
GLOBAL_VAR_INIT(lock_client_view_x, null)
|
||||
GLOBAL_VAR_INIT(lock_client_view_y, null)
|
||||
GLOBAL_LIST_INIT(valid_icon_sizes, list(32, 48, 64, 72, 96, 128))
|
||||
// these two variables control max dynamic resize for viewport
|
||||
GLOBAL_VAR_INIT(max_client_view_x, 19)
|
||||
GLOBAL_VAR_INIT(max_client_view_y, 15)
|
||||
// these two variables **reflect** (config updates, not this!) effective default viewsize for view(), range(), etc.
|
||||
GLOBAL_VAR_INIT(game_view_x, 19)
|
||||
GLOBAL_VAR_INIT(game_view_y, 15)
|
||||
// minimum size viewports can be
|
||||
GLOBAL_VAR_INIT(min_client_view_x, 15)
|
||||
GLOBAL_VAR_INIT(min_client_view_y, 15)
|
||||
// these two variables, if set, lock all clients to a certain viewsize no matter what
|
||||
GLOBAL_VAR(lock_client_view_x)
|
||||
GLOBAL_VAR(lock_client_view_y)
|
||||
|
||||
/datum/preferences
|
||||
var/icon_size = 64
|
||||
|
||||
/client
|
||||
var/last_view_x_dim = 7
|
||||
var/last_view_y_dim = 7
|
||||
|
||||
|
||||
/client/verb/SetCozyViewInwards(val as num|text)
|
||||
set hidden = 1
|
||||
|
||||
if(prefs && val != prefs.icon_size)
|
||||
prefs.icon_size += val
|
||||
SScharacters.queue_preferences_save(prefs)
|
||||
winset(src, "mapwindow.map", "icon-size=[prefs.icon_size]")
|
||||
OnResize()
|
||||
|
||||
/client/verb/SetWindowIconSize(val as num|text)
|
||||
set hidden = 1
|
||||
winset(src, "mapwindow.map", "icon-size=[val]")
|
||||
if(prefs && val != prefs.icon_size)
|
||||
prefs.icon_size = val
|
||||
SScharacters.queue_preferences_save(prefs)
|
||||
OnResize()
|
||||
|
||||
/client/verb/OnResize()
|
||||
set hidden = 1
|
||||
if(!is_preference_enabled(/datum/client_preference/scaling_viewport))
|
||||
return
|
||||
var/divisor = text2num(winget(src, "mapwindow.map", "icon-size")) || world.icon_size
|
||||
if(!isnull(GLOB.lock_client_view_x) && !isnull(GLOB.lock_client_view_y))
|
||||
last_view_x_dim = GLOB.lock_client_view_x
|
||||
last_view_y_dim = GLOB.lock_client_view_y
|
||||
/**
|
||||
* forces world viewsize; use for config VAS
|
||||
*/
|
||||
/datum/controller/configuration/proc/update_world_viewsize()
|
||||
//! BYONd world.view is immutable, for now we're stuck read-onlying it.
|
||||
if(isnum(world.view))
|
||||
GLOB.game_view_x = GLOB.game_view_y = world.view
|
||||
else
|
||||
var/winsize_string = winget(src, "mapwindow.map", "size")
|
||||
last_view_x_dim = GLOB.lock_client_view_x || clamp(ROUND_UP(text2num(winsize_string) / divisor), 15, (CONFIG_GET(number/max_client_view_x)) || (CONFIG_GET(number/max_client_view_x)))
|
||||
last_view_y_dim = GLOB.lock_client_view_y || clamp(ROUND_UP(text2num(copytext(winsize_string,findtext(winsize_string,"x")+1,0)) / divisor), 15, (CONFIG_GET(number/max_client_view_y)) || 41)
|
||||
// is text
|
||||
var/list/viewsize = splittext(world.view, "x")
|
||||
GLOB.game_view_x = viewsize[1]
|
||||
GLOB.game_view_y = viewsize[2]
|
||||
|
||||
if(last_view_x_dim % 2 == 0)
|
||||
last_view_x_dim++
|
||||
if(last_view_y_dim % 2 == 0)
|
||||
last_view_y_dim++
|
||||
/**
|
||||
* forces screensize update; use for config VAS
|
||||
*/
|
||||
/datum/controller/configuration/proc/update_player_viewsize()
|
||||
var/viewsize_raw = CONFIG_GET(string/max_viewport_size)
|
||||
var/list/viewsize = splittext(viewsize_raw, "x")
|
||||
GLOB.max_client_view_x = text2num(viewsize[1])
|
||||
GLOB.max_client_view_y = text2num(viewsize[2])
|
||||
|
||||
for(var/check_icon_size in GLOB.valid_icon_sizes)
|
||||
winset(src, "menu.icon[check_icon_size]", "is-checked=false")
|
||||
winset(src, "menu.icon[divisor]", "is-checked=true")
|
||||
//! Core viewport procs
|
||||
//! These don't obey the read-write lock, and should only be called from the synchronized procs!
|
||||
|
||||
view = "[last_view_x_dim]x[last_view_y_dim]"
|
||||
/**
|
||||
* populates important vars that things may read early before we sleep
|
||||
*/
|
||||
/client/proc/pre_init_viewport()
|
||||
PRIVATE_PROC(TRUE)
|
||||
current_viewport_width = GLOB.max_client_view_x
|
||||
current_viewport_height = GLOB.max_client_view_y
|
||||
|
||||
// Reset eye/perspective
|
||||
reset_perspective()
|
||||
/* var/last_perspective = perspective
|
||||
/**
|
||||
* called on client init to do this without blocking client/New
|
||||
*/
|
||||
/client/proc/init_viewport_blocking()
|
||||
PRIVATE_PROC(TRUE)
|
||||
fetch_viewport()
|
||||
refit_viewsize()
|
||||
// release the initial lock
|
||||
viewport_rwlock = FALSE
|
||||
|
||||
/**
|
||||
* called to manually update viewport vars since the skin macro is only triggered on resize
|
||||
*
|
||||
* return TRUE if changed
|
||||
*/
|
||||
/client/proc/fetch_viewport()
|
||||
PRIVATE_PROC(TRUE)
|
||||
. = FALSE
|
||||
// get vars only; they have to manually refit
|
||||
var/list/got = params2list(winget(src, SKIN_MAP_ID_VIEWPORT, "size;zoom;letterbox"))
|
||||
var/got_zoom = text2num(got["zoom"]) || 0
|
||||
var/got_box = (got["letterbox"] == "true")
|
||||
var/list/split = splittext(got["size"], "x")
|
||||
var/got_spx
|
||||
var/got_spy
|
||||
if(length(split) == 2)
|
||||
got_spx = text2num(split[1]) || (WORLD_ICON_SIZE * GLOB.game_view_x)
|
||||
got_spy = text2num(split[2]) || (WORLD_ICON_SIZE * GLOB.game_view_y)
|
||||
else
|
||||
stack_trace("fetch_viewport failed to get spx/spy")
|
||||
got_spx = (WORLD_ICON_SIZE * GLOB.game_view_x)
|
||||
got_spy = (WORLD_ICON_SIZE * GLOB.game_view_y)
|
||||
if(got_zoom != assumed_viewport_zoom || got_spx != assumed_viewport_spx || got_spy != assumed_viewport_spy || got_box != assumed_viewport_box)
|
||||
. = TRUE
|
||||
assumed_viewport_zoom = got_zoom
|
||||
assumed_viewport_spx = got_spx
|
||||
assumed_viewport_spy = got_spy
|
||||
assumed_viewport_box = got_box
|
||||
|
||||
/**
|
||||
* called to refit our view size as necessary
|
||||
*
|
||||
* this is automatically called every time something modifies us
|
||||
*/
|
||||
/client/proc/refit_viewsize(no_fit)
|
||||
PRIVATE_PROC(TRUE)
|
||||
if(!isnull(GLOB.lock_client_view_x) && !isnull(GLOB.lock_client_view_y))
|
||||
view = "[GLOB.lock_client_view_x]x[GLOB.lock_client_view_y]"
|
||||
on_refit_viewsize(GLOB.lock_client_view_x, GLOB.lock_client_view_y, no_fit)
|
||||
return
|
||||
if(using_temporary_viewsize)
|
||||
view = "[temporary_viewsize_width]x[temporary_viewsize_height]"
|
||||
on_refit_viewsize(temporary_viewsize_width, temporary_viewsize_height, no_fit)
|
||||
return
|
||||
var/widescreen = is_widescreen_enabled()
|
||||
if(!widescreen)
|
||||
// if not widescreen, we should just force to 15 x 15 and their augmented view
|
||||
var/width = 15 + (using_perspective.augment_view_width * 2)
|
||||
var/height = 15 + (using_perspective.augment_view_height * 2)
|
||||
view = "[width]x[height]"
|
||||
on_refit_viewsize(width, height, no_fit)
|
||||
return
|
||||
var/stretch_to_fit = assumed_viewport_zoom == 0
|
||||
using_perspective.ensure_view_cached()
|
||||
var/max_width = using_perspective.cached_view_width
|
||||
var/max_height = using_perspective.cached_view_height
|
||||
if(stretch_to_fit)
|
||||
// option 1: they're stretching to fit
|
||||
if(assumed_viewport_box)
|
||||
// fit everything
|
||||
view = "[max_width]x[max_height]"
|
||||
on_refit_viewsize(max_width, max_height)
|
||||
return
|
||||
// option 2: they're stretching to fit the longest side
|
||||
else
|
||||
// todo: handle horizontally-wider view sizes
|
||||
// for now we only care about horizontal fit
|
||||
var/stretch_pixel_amount = assumed_viewport_spy / max_height
|
||||
var/available_width = assumed_viewport_spx / stretch_pixel_amount
|
||||
available_width = CEILING(available_width, 1)
|
||||
available_width = clamp(available_width, GLOB.min_client_view_x, max_width)
|
||||
view = "[available_width]x[max_height]"
|
||||
on_refit_viewsize(available_width, max_height, no_fit)
|
||||
return
|
||||
// option 3: scale as necessary
|
||||
var/pixels_per_tile = assumed_viewport_zoom * WORLD_ICON_SIZE
|
||||
var/div_x = assumed_viewport_spx / pixels_per_tile
|
||||
var/div_y = assumed_viewport_spy / pixels_per_tile
|
||||
div_x = CEILING(div_x, 1)
|
||||
div_y = CEILING(div_y, 1)
|
||||
var/desired_width = clamp(div_x, GLOB.min_client_view_x, max_width)
|
||||
var/desired_height = clamp(div_y, GLOB.min_client_view_y, max_height)
|
||||
view = "[desired_width]x[desired_height]"
|
||||
on_refit_viewsize(desired_width, desired_height, no_fit)
|
||||
|
||||
/client/proc/on_refit_viewsize(new_width, new_height, no_fit)
|
||||
var/changed = (current_viewport_height != new_height) || (current_viewport_width != new_width)
|
||||
if(changed)
|
||||
current_viewport_width = new_width
|
||||
current_viewport_height = new_height
|
||||
if(!no_fit && is_auto_fit_viewport_enabled())
|
||||
fit_viewport()
|
||||
post_refit_viewsize(changed)
|
||||
|
||||
/**
|
||||
* updates everything when our viewport changes
|
||||
*/
|
||||
/client/proc/post_refit_viewsize(changed)
|
||||
if(!changed)
|
||||
return
|
||||
// force perspective swap for ??? reasons (???)
|
||||
var/old_perspective = perspective
|
||||
perspective = MOB_PERSPECTIVE
|
||||
if(perspective != last_perspective)
|
||||
perspective = last_perspective
|
||||
var/last_eye = eye
|
||||
eye = mob
|
||||
if(eye != last_eye)
|
||||
eye = last_eye
|
||||
if(mob)
|
||||
mob.reload_fullscreen() */
|
||||
update_clickcatcher()
|
||||
if(old_perspective != perspective)
|
||||
perspective = old_perspective
|
||||
// i don't understand the above
|
||||
mob?.refit_rendering()
|
||||
|
||||
/client/verb/force_onresize_view_update()
|
||||
set name = "Force Client View Update"
|
||||
/**
|
||||
* called to fit our viewport to what we **should** have to get our effective view.
|
||||
*/
|
||||
/client/proc/fit_viewport()
|
||||
// by now we already fetched viewport
|
||||
// figure out how big they want it to be based on their settings
|
||||
// note: we only care about horizontal because the splitter.. is, well, horizontal.
|
||||
var/desired_pixel_width
|
||||
// todo: pref
|
||||
// maximum % they're willing to have their map
|
||||
var/maximum_splitter_percent = 80
|
||||
// splitter intrinsic width
|
||||
var/assumed_splitter_width = 4
|
||||
// effective size
|
||||
var/widescreen = is_widescreen_enabled()
|
||||
var/effective_view_width
|
||||
var/effective_view_height
|
||||
// todo: optimize the shit out of this proc and the view system
|
||||
if(!isnull(GLOB.lock_client_view_x) && !isnull(GLOB.lock_client_view_y))
|
||||
effective_view_width = GLOB.lock_client_view_x
|
||||
effective_view_height = GLOB.lock_client_view_y
|
||||
else if(widescreen)
|
||||
effective_view_width = clamp(temporary_viewsize_width || using_perspective.cached_view_width, GLOB.min_client_view_x, 67)
|
||||
effective_view_height = clamp(temporary_viewsize_height || using_perspective.cached_view_height, GLOB.min_client_view_y, 67)
|
||||
else
|
||||
effective_view_width = clamp(temporary_viewsize_width || (15 + (using_perspective.augment_view_width * 2)), GLOB.min_client_view_x, 67)
|
||||
effective_view_height = clamp(temporary_viewsize_height || (15 + (using_perspective.augment_view_height * 2)), GLOB.min_client_view_y, 67)
|
||||
if(assumed_viewport_zoom == 0)
|
||||
// they're stretching to fit; this makes it annoying
|
||||
var/aspect_ratio = effective_view_width / effective_view_height
|
||||
// we have to fit everything
|
||||
// viewport_spy should never change since that's not what the player can drag,
|
||||
// unless they resize the outer window itself.
|
||||
desired_pixel_width = assumed_viewport_spy * aspect_ratio
|
||||
else
|
||||
// they're not using stretch to fit; this makes it very easy
|
||||
desired_pixel_width = WORLD_ICON_SIZE * assumed_viewport_zoom * effective_view_width
|
||||
// grab their screen size (or what counts as it)
|
||||
var/list/fetching = winget(src, SKIN_SPLITTER_ID_MAIN, "size")
|
||||
var/list/parsed = splittext(fetching, "x")
|
||||
var/screen_width = text2num(parsed[1])
|
||||
// grab what percent we should go to
|
||||
var/current_percent = min(100 * ((desired_pixel_width + assumed_splitter_width) / screen_width), maximum_splitter_percent)
|
||||
// initial set
|
||||
winset(src, SKIN_SPLITTER_ID_MAIN, "splitter=[current_percent]")
|
||||
// funny method of correcting for misalignments via binary-search-like behavior
|
||||
var/delta
|
||||
fetching = winget(src, SKIN_MAP_ID_VIEWPORT, "size")
|
||||
parsed = splittext(fetching, "x")
|
||||
var/current_width = text2num(parsed[1])
|
||||
var/last_width = current_width
|
||||
if(current_width == desired_pixel_width)
|
||||
// done
|
||||
return
|
||||
// nope, start adjusting
|
||||
delta = 100 * ((desired_pixel_width - current_width) / screen_width)
|
||||
for(var/safety in 1 to 10)
|
||||
current_percent = min(current_percent + delta, maximum_splitter_percent)
|
||||
winset(src, SKIN_SPLITTER_ID_MAIN, "splitter=[current_percent]")
|
||||
fetching = winget(src, SKIN_MAP_ID_VIEWPORT, "size")
|
||||
parsed = splittext(fetching, "x")
|
||||
current_width = text2num(parsed[1])
|
||||
// done?
|
||||
if(current_width == desired_pixel_width)
|
||||
return
|
||||
// if we're literally down to a pixel how about like Don't
|
||||
if(last_width == current_width)
|
||||
return
|
||||
last_width = current_width
|
||||
// keep adjusting
|
||||
// overshot?
|
||||
if ((delta > 0 && current_width > desired_pixel_width) || (delta < 0 && current_width < desired_pixel_width))
|
||||
// reverse in half
|
||||
delta = -delta / 2
|
||||
|
||||
//! Synchronized procs; calling these from outside is fine.
|
||||
/**
|
||||
* call this when things change to queue an update
|
||||
*
|
||||
* should only be called **in code**, not by the skin!
|
||||
*
|
||||
* warning: this proc doesn't refit instantly, it only queues.
|
||||
* client decides what time is best to refit.
|
||||
*/
|
||||
/client/proc/request_viewport_update()
|
||||
set waitfor = FALSE
|
||||
if(!viewport_rwlock)
|
||||
_request_viewport_update()
|
||||
if(!viewport_queued)
|
||||
viewport_queued = TRUE
|
||||
addtimer(CALLBACK(src, .proc/_request_viewport_update), 0)
|
||||
|
||||
/**
|
||||
* call this when things change to queue an update
|
||||
*
|
||||
* should only be called **in code**, not by the skin!
|
||||
*
|
||||
* blocks until finished
|
||||
*/
|
||||
/client/proc/request_viewport_update_blocking()
|
||||
if(!viewport_rwlock)
|
||||
_request_viewport_update()
|
||||
return
|
||||
if(!viewport_queued)
|
||||
viewport_queued = TRUE
|
||||
addtimer(CALLBACK(src, .proc/_request_viewport_update), 0)
|
||||
UNTIL(!viewport_queued)
|
||||
|
||||
// todo : locks are probably bad when working with request fit
|
||||
/client/proc/_request_viewport_update(no_fit, no_fetch)
|
||||
PRIVATE_PROC(TRUE)
|
||||
// if rwlocked, wait; people should be queuing and not calling this directly
|
||||
UNTIL(!viewport_rwlock)
|
||||
// clear queued
|
||||
viewport_queued = FALSE
|
||||
// lock
|
||||
viewport_rwlock = TRUE
|
||||
if(!no_fetch)
|
||||
fetch_viewport()
|
||||
// refit size based on viewport
|
||||
refit_viewsize(no_fit)
|
||||
// release lock
|
||||
viewport_rwlock = FALSE
|
||||
|
||||
/**
|
||||
* call this to request a viewport fit
|
||||
*/
|
||||
/client/proc/request_viewport_fit(no_recalc)
|
||||
set waitfor = FALSE
|
||||
_request_viewport_fit(no_recalc)
|
||||
|
||||
/**
|
||||
* call this to request a viewport fit
|
||||
* forcefully fits
|
||||
* blocks until finished
|
||||
* don't call this from non-buttons because it blocks and
|
||||
* absolutely can stack and ruin everyone's day.
|
||||
*/
|
||||
/client/proc/viewport_fit_blocking(no_recalc)
|
||||
UNTIL(!viewport_rwlock)
|
||||
return _request_viewport_fit(no_recalc)
|
||||
|
||||
// todo : locks are probably bad when working with request update
|
||||
/client/proc/_request_viewport_fit(no_recalc)
|
||||
PRIVATE_PROC(TRUE)
|
||||
// if viewport is locked, ignore it
|
||||
if(viewport_rwlock)
|
||||
return
|
||||
// acquire lock
|
||||
viewport_rwlock = TRUE
|
||||
// just in case because this is called by a lot of things that are too shitcoded to update (like my own code)
|
||||
fetch_viewport()
|
||||
// fit viewport
|
||||
fit_viewport()
|
||||
// fetch values; we do not trust on-size to trigger
|
||||
fetch_viewport()
|
||||
// then refit the viewsize if needed
|
||||
if(!no_recalc)
|
||||
refit_viewsize()
|
||||
// release lock
|
||||
viewport_rwlock = FALSE
|
||||
|
||||
/**
|
||||
* called directly by the skin when resizing
|
||||
*
|
||||
* @params
|
||||
* - w - width of viewport in pixels
|
||||
* - h - height of viewport in pixels
|
||||
* - z - zoom of viewport
|
||||
* - b - are we letterboxing?
|
||||
*/
|
||||
/client/verb/on_viewport(w as text, h as text, z as num, b as num)
|
||||
set name = ".on_viewport"
|
||||
set hidden = TRUE
|
||||
if(viewport_rwlock) // something is fucking around, don't edit for them
|
||||
return
|
||||
// get vars
|
||||
assumed_viewport_spx = text2num(w)
|
||||
assumed_viewport_spy = text2num(h)
|
||||
assumed_viewport_zoom = z
|
||||
assumed_viewport_box = b
|
||||
// refit
|
||||
_request_viewport_update(TRUE, TRUE)
|
||||
|
||||
/**
|
||||
* automatically fit their viewport to show everything optimally
|
||||
*/
|
||||
/client/verb/user_fit_viewport()
|
||||
set name = "Fit Viewport"
|
||||
set category = "OOC"
|
||||
set desc = "Fit the width of the map window to match the viewport"
|
||||
request_viewport_fit()
|
||||
|
||||
/client/verb/force_map_zoom(n as num)
|
||||
set name = ".viewport_zoom"
|
||||
set hidden = TRUE
|
||||
set src = usr
|
||||
set category = "Debug"
|
||||
OnResize()
|
||||
if(!isnum(n) || n < 0)
|
||||
to_chat(usr, SPAN_WARNING("invalid number"))
|
||||
return
|
||||
if(viewport_rwlock)
|
||||
to_chat(usr, SPAN_WARNING("Viewport is rwlocked; try again later."))
|
||||
return
|
||||
winset(src, SKIN_MAP_ID_VIEWPORT, "zoom=[n]")
|
||||
assumed_viewport_zoom = n
|
||||
request_viewport_update(TRUE)
|
||||
|
||||
/client/verb/force_map_box(n as num)
|
||||
set name = ".viewport_box"
|
||||
set hidden = TRUE
|
||||
set src = usr
|
||||
set category = "Debug"
|
||||
if(viewport_rwlock)
|
||||
to_chat(usr, SPAN_WARNING("Viewport is rwlocked; try again later."))
|
||||
return
|
||||
n = !!n // force bool
|
||||
winset(src, SKIN_MAP_ID_VIEWPORT, "letterbox=[n? "true" : "false"]")
|
||||
assumed_viewport_box = n
|
||||
request_viewport_update(TRUE)
|
||||
|
||||
/client/verb/force_onresize_view_update()
|
||||
set name = ".viewport_update"
|
||||
set hidden = TRUE
|
||||
set src = usr
|
||||
set category = "Debug"
|
||||
if(viewport_rwlock)
|
||||
to_chat(usr, SPAN_WARNING("Viewport is rwlocked; try again later."))
|
||||
return
|
||||
request_viewport_update()
|
||||
|
||||
/client/verb/show_winset_debug_values()
|
||||
set name = "Show Client View Debug Values"
|
||||
set name = ".viewport_debug"
|
||||
set hidden = TRUE
|
||||
set src = usr
|
||||
set category = "Debug"
|
||||
|
||||
@@ -83,3 +406,5 @@ GLOBAL_LIST_INIT(valid_icon_sizes, list(32, 48, 64, 72, 96, 128))
|
||||
to_chat(usr, "Icon size: [divisor]")
|
||||
to_chat(usr, "xDim: [round(text2num(winsize_string) / divisor)]")
|
||||
to_chat(usr, "yDim: [round(text2num(copytext(winsize_string,findtext(winsize_string,"x")+1,0)) / divisor)]")
|
||||
to_chat(usr, "server thinks viewport is:[assumed_viewport_spx]/[assumed_viewport_spy]/[assumed_viewport_zoom]/[assumed_viewport_box]")
|
||||
to_chat(usr, "server thinks view is:[current_viewport_width]x[current_viewport_height]")
|
||||
|
||||
@@ -12,3 +12,6 @@
|
||||
|
||||
/client/proc/_winshow(window, show)
|
||||
winshow(src, window, show)
|
||||
|
||||
/client/proc/_command(str)
|
||||
winset(src, null, "command=[str]")
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
/obj/map_helper/network_builder/power_cable/build()
|
||||
if(!network_directions)
|
||||
return
|
||||
var/knot = KNOT_FORCED || (KNOT_AUTO && detect_knot())
|
||||
var/knot = (src.knot == KNOT_FORCED) || ((src.knot == KNOT_AUTO) && detect_knot())
|
||||
if(knot)
|
||||
for(var/i in GLOB.cardinal)
|
||||
if(!(network_directions & i))
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
voice_name = "unknown"
|
||||
icon = 'icons/effects/effects.dmi' //We have an ultra-complex update icons that overlays everything, don't load some stupid random male human
|
||||
icon_state = "nothing"
|
||||
SET_APPEARANCE_FLAGS(TILE_BOUND | PIXEL_SCALE | KEEP_TOGETHER)
|
||||
|
||||
/// To check if we've need to roll for damage on movement while an item is imbedded in us.
|
||||
var/embedded_flag
|
||||
|
||||
@@ -19,9 +19,6 @@ GLOBAL_DATUM_INIT(lobby_image, /obj/effect/lobby_image, new)
|
||||
icon_state = known_icon_states[1]
|
||||
. = ..()
|
||||
|
||||
/mob/new_player
|
||||
var/client/my_client // Need to keep track of this ourselves, since by the time Logout() is called the client has already been nulled
|
||||
|
||||
/mob/new_player/Login()
|
||||
update_Login_details() //handles setting lastKnownIP and computer_id for use by the ban systems as well as checking for multikeying
|
||||
|
||||
@@ -37,7 +34,6 @@ GLOBAL_DATUM_INIT(lobby_image, /obj/effect/lobby_image, new)
|
||||
mind.current = src
|
||||
|
||||
loc = null
|
||||
my_client = client
|
||||
GLOB.player_list |= src
|
||||
|
||||
new_player_panel()
|
||||
@@ -45,5 +41,4 @@ GLOBAL_DATUM_INIT(lobby_image, /obj/effect/lobby_image, new)
|
||||
if(client)
|
||||
handle_privacy_poll()
|
||||
client.playtitlemusic()
|
||||
client.is_preference_enabled(/datum/client_preference/scaling_viewport) ? client.OnResize() : client.change_view(world.view)
|
||||
return ..()
|
||||
|
||||
@@ -21,11 +21,11 @@
|
||||
// check enter
|
||||
if(!T2.Enter(src, T))
|
||||
return FALSE
|
||||
|
||||
|
||||
// uh oh, second loop, check exits
|
||||
for(var/turf/T as anything in locs)
|
||||
if(!(T in moving_to))
|
||||
if(!T.Exit(src, get_step(T, stepdir)))
|
||||
return FALSE
|
||||
|
||||
|
||||
return TRUE
|
||||
|
||||
@@ -227,6 +227,7 @@
|
||||
bottom_turf.plane = src.plane
|
||||
bottom_turf.color = below.color
|
||||
bottom_turf.copy_overlays(below)
|
||||
// todo: zmimic
|
||||
bottom_turf.appearance_flags = KEEP_TOGETHER
|
||||
underlays = list(bottom_turf)
|
||||
|
||||
|
||||
@@ -40,6 +40,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
var/list/character
|
||||
/// global data
|
||||
var/list/options
|
||||
/// data for byond skin - checkboxes and whatnot; this is ENTIRELY synchronized by the skin system.
|
||||
var/list/skin
|
||||
|
||||
//! ## Game Preferences
|
||||
var/tgui_fancy = TRUE
|
||||
@@ -252,6 +254,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
|
||||
load_path(client.ckey)
|
||||
if(load_preferences())
|
||||
if(load_character())
|
||||
load_skin()
|
||||
sanitize_everything()
|
||||
player_setup.sanitize_setup()
|
||||
client.update_movement_keys()
|
||||
|
||||
@@ -268,3 +268,11 @@
|
||||
for(var/key in skipped)
|
||||
errors?.Add("Skipping key [key] - no datum found.")
|
||||
return TRUE
|
||||
|
||||
//! Skin stuff
|
||||
/datum/preferences/proc/set_skin_data(key, value)
|
||||
skin[key] = value
|
||||
save_skin()
|
||||
|
||||
/datum/preferences/proc/get_skin_data(key)
|
||||
return skin[key]
|
||||
|
||||
@@ -293,13 +293,6 @@ var/list/_client_preferences_by_type
|
||||
disabled_description = "Hide"
|
||||
enabled_by_default = TRUE
|
||||
|
||||
/datum/client_preference/scaling_viewport
|
||||
description = "Scaling Viewport"
|
||||
key = "scaling_viewport"
|
||||
enabled_description = "Show"
|
||||
disabled_description = "Hide"
|
||||
enabled_by_default = TRUE
|
||||
|
||||
/********************
|
||||
* Staff Preferences *
|
||||
********************/
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
if(!path)
|
||||
return FALSE
|
||||
// check DOS guard
|
||||
if(world.time < loadprefcooldown) //This is done before checking if the file exists to ensure that the server can't hang on read attempts
|
||||
if(initialized && world.time < loadprefcooldown) //This is done before checking if the file exists to ensure that the server can't hang on read attempts
|
||||
if(istype(client))
|
||||
to_chat(client, "<span class='warning'>You're attempting to load your preferences a little too fast. Wait half a second, then try again.</span>")
|
||||
return FALSE
|
||||
@@ -48,7 +48,7 @@
|
||||
if(!path)
|
||||
return FALSE
|
||||
// check DOS guard
|
||||
if(world.time < saveprefcooldown)
|
||||
if(initialized && world.time < saveprefcooldown)
|
||||
if(istype(client))
|
||||
to_chat(client, "<span class='warning'>You're attempting to save your preferences a little too fast. Wait half a second, then try again.</span>")
|
||||
return FALSE
|
||||
@@ -69,12 +69,42 @@
|
||||
auto_flush_errors()
|
||||
return TRUE
|
||||
|
||||
/datum/preferences/proc/save_skin()
|
||||
if(!path)
|
||||
return FALSE
|
||||
// heyooo no interruptions please
|
||||
if(initialized)
|
||||
UNTIL(world.time >= saveprefcooldown)
|
||||
var/savefile/S = new /savefile(path)
|
||||
if(!S)
|
||||
return FALSE
|
||||
S.cd = "/"
|
||||
skin = sanitize_islist(skin)
|
||||
WRITE_FILE(S["skin"], skin)
|
||||
return TRUE
|
||||
|
||||
/datum/preferences/proc/load_skin()
|
||||
if(!path)
|
||||
return FALSE
|
||||
// heyooo no interruptions please
|
||||
if(initialized)
|
||||
UNTIL(world.time >= loadprefcooldown)
|
||||
if(!fexists(path))
|
||||
return FALSE
|
||||
var/savefile/S = new /savefile(path)
|
||||
if(!S)
|
||||
return FALSE
|
||||
S.cd = "/"
|
||||
READ_FILE(S["skin"], skin)
|
||||
skin = sanitize_islist(skin)
|
||||
return TRUE
|
||||
|
||||
/datum/preferences/proc/load_character(slot)
|
||||
// todo: storage handler datums...
|
||||
if(!path)
|
||||
return FALSE
|
||||
// check DOS guard
|
||||
if(world.time < loadcharcooldown)
|
||||
if(initialized && world.time < loadcharcooldown)
|
||||
if(istype(client))
|
||||
to_chat(client, "<span class='warning'>You're attempting to load your character a little too fast. Wait half a second, then try again.</span>")
|
||||
return FALSE
|
||||
@@ -134,7 +164,7 @@
|
||||
if(!path)
|
||||
return FALSE
|
||||
// check DOS guard
|
||||
if(world.time < savecharcooldown)
|
||||
if(initialized && world.time < savecharcooldown)
|
||||
if(istype(client))
|
||||
to_chat(client, "<span class='warning'>You're attempting to save your character a little too fast. Wait half a second, then try again.</span>")
|
||||
return FALSE
|
||||
|
||||
@@ -306,19 +306,6 @@
|
||||
|
||||
feedback_add_details("admin_verb","TOHChat")
|
||||
|
||||
/client/verb/toggle_scaling_viewport()
|
||||
set name = "Toggle Scaling Viewport"
|
||||
set category = "Preferences"
|
||||
set desc = "Enable/Disable Viewport Scaling."
|
||||
|
||||
var/pref_path = /datum/client_preference/scaling_viewport
|
||||
toggle_preference(pref_path)
|
||||
SScharacters.queue_preferences_save(prefs)
|
||||
|
||||
to_chat(src, "You will now [(is_preference_enabled(/datum/client_preference/scaling_viewport)) ? "see" : "not see"] more...")
|
||||
is_preference_enabled(/datum/client_preference/scaling_viewport) ? OnResize() : change_view(world.view)
|
||||
feedback_add_details("admin_verb","TOHChat")
|
||||
|
||||
//Toggles for Staff
|
||||
//Developers
|
||||
|
||||
|
||||
@@ -430,9 +430,8 @@
|
||||
var/y = text2num(screen_loc_Y[1]) * 32 + text2num(screen_loc_Y[2]) - 32
|
||||
|
||||
//Calculate the "resolution" of screen based on client's view and world's icon size. This will work if the user can view more tiles than average.
|
||||
var/list/screenview = user.client? getviewsize(user.client.view) : world.view
|
||||
var/screenviewX = screenview[1] * world.icon_size
|
||||
var/screenviewY = screenview[2] * world.icon_size
|
||||
var/screenviewX = user.client.current_viewport_width * world.icon_size
|
||||
var/screenviewY = user.client.current_viewport_height * world.icon_size
|
||||
|
||||
var/ox = round(screenviewX/2) - user.client.pixel_x //"origin" x
|
||||
var/oy = round(screenviewY/2) - user.client.pixel_y //"origin" y
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
|
||||
// Regular ghosts can always at least view if in range.
|
||||
if(user.client)
|
||||
var/clientviewlist = getviewsize(user.client.view)
|
||||
if(get_dist(src_object, user) < max(clientviewlist[1], clientviewlist[2]))
|
||||
// todo: in view range for zooming
|
||||
if(get_dist(src_object, user) < max(CEILING(user.client.current_viewport_width / 2, 1), CEILING(user.client.current_viewport_height / 2, 1)))
|
||||
. = max(., UI_UPDATE)
|
||||
|
||||
// Check if the state allows interaction
|
||||
|
||||
@@ -31,8 +31,8 @@ GLOBAL_DATUM_INIT(default_state, /datum/ui_state/default, new)
|
||||
return
|
||||
|
||||
// Robots can interact with anything they can see.
|
||||
var/list/clientviewlist = getviewsize(client.view)
|
||||
if(get_dist(src, src_object) <= min(clientviewlist[1],clientviewlist[2]))
|
||||
// todo: in view range for zooming
|
||||
if(get_dist(src, src_object) <= min(CEILING(client.current_viewport_width / 2, 1), CEILING(client.current_viewport_height / 2, 1)))
|
||||
return UI_INTERACTIVE
|
||||
return UI_DISABLED // Otherwise they can keep the UI open.
|
||||
|
||||
|
||||
@@ -35,8 +35,7 @@
|
||||
// Regular ghosts can always at least view if in range.
|
||||
var/datum/client_interface/client = GET_CLIENT(user)
|
||||
if(client)
|
||||
var/clientviewlist = getviewsize(client.view)
|
||||
if(get_dist(source, user) < max(clientviewlist[1], clientviewlist[2]))
|
||||
if(get_dist(source, user) < max(client.current_viewport_width, client.current_viewport_height))
|
||||
return UI_UPDATE
|
||||
|
||||
return UI_CLOSE
|
||||
@@ -74,8 +73,8 @@
|
||||
|
||||
/mob/living/silicon/robot/get_ui_access(atom/source)
|
||||
// Robots can interact with anything they can see.
|
||||
var/list/clientviewlist = getviewsize(client.view)
|
||||
if(get_dist(src, source) <= min(clientviewlist[1],clientviewlist[2]))
|
||||
// todo: in view range for zooming
|
||||
if(get_dist(src, source) <= min(CEILING(client.current_viewport_width / 2, 1), CEILING(client.current_viewport_height / 2, 1)))
|
||||
return UI_INTERACTIVE
|
||||
return UI_DISABLED // Otherwise they can keep the UI open.
|
||||
|
||||
|
||||
@@ -75,8 +75,7 @@ Notes:
|
||||
params = {"{ "cursor": "[params]", "screenLoc": "[thing.screen_loc]" }"}
|
||||
|
||||
//Send stuff to the tooltip
|
||||
var/view_size = getviewsize(owner.view)
|
||||
owner << output(list2params(list(params, view_size[1] , view_size[2], "[title][content]", theme, special)), "[control]:tooltip.update")
|
||||
owner << output(list2params(list(params, owner.current_viewport_width, owner.current_viewport_height, "[title][content]", theme, special)), "[control]:tooltip.update")
|
||||
|
||||
//If a hide() was hit while we were showing, run hide() again to avoid stuck tooltips
|
||||
showing = 0
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
## Max distance for clients to view with widescren mode enabled. Maximum: 35 in either dimension.
|
||||
MAX_VIEWPORT_SIZE 19x15
|
||||
## Effective distance used for world.view, affects stuff like AI target aquisition. Maximum: 35 in either dimension.
|
||||
## GAME_VIEWPORT_SIZE 15x19
|
||||
## AT THE CURRENT TIME, BYOND WORLD.VIEW IS READ-ONLY
|
||||
## THIS CONFIGURATION IS LEFT HERE AS A TODO.
|
||||
|
||||
## Set to 0 to disable holidays (you monster)
|
||||
ALLOW_HOLIDAYS
|
||||
|
||||
@@ -10,7 +17,3 @@ ENGINE_SUBMAP EngineSubmap_RUST 40
|
||||
ENGINE_SUBMAP EngineSubmap_Tesla 20
|
||||
## Singulo
|
||||
ENGINE_SUBMAP EngineSubmap_Singulo 20
|
||||
|
||||
## Max distance for clients to view with widescren mode enabled.
|
||||
MAX_CLIENT_VIEW_X 21
|
||||
MAX_CLIENT_VIEW_Y 15
|
||||
|
||||
@@ -0,0 +1,334 @@
|
||||
//! skin menus
|
||||
/**
|
||||
* dynamic in-code menu system with blackjack and hookers
|
||||
*/
|
||||
/datum/skin_menu
|
||||
/// id - used for both skin and savefiles
|
||||
var/id
|
||||
/// id of window to bind to; we will OVERWRITE ANY EXISTING MENU.
|
||||
var/bind_to
|
||||
/// category datum types - transformed into datums at runtime
|
||||
var/list/datum/skin_menu_category/categories
|
||||
/// during initial build, we will construct groups list, group name associated to button id for default
|
||||
var/list/button_groups
|
||||
|
||||
/datum/skin_menu/New()
|
||||
init_categories()
|
||||
|
||||
/datum/skin_menu/Destroy()
|
||||
QDEL_LIST(categories)
|
||||
button_groups = null
|
||||
return ..()
|
||||
|
||||
/datum/skin_menu/proc/init_categories()
|
||||
button_groups = list()
|
||||
for(var/i in 1 to categories.len)
|
||||
if(ispath(categories[i]))
|
||||
var/path = categories[i]
|
||||
var/datum/skin_menu_category/C = new path(src)
|
||||
categories[i] = C
|
||||
// category will init in /New(), so...
|
||||
for(var/datum/skin_menu_entry/E as anything in C.entries)
|
||||
// again let it runtime if it's bad, we WANT it to runtime so integration tests fail
|
||||
if(E.group)
|
||||
button_groups |= E.group
|
||||
if(E.is_default)
|
||||
button_groups[E.group] = E.id
|
||||
else
|
||||
continue // wtf? let it runtime later
|
||||
// verify
|
||||
for(var/group in button_groups)
|
||||
if(!button_groups[group])
|
||||
stack_trace("no default for group [group]")
|
||||
|
||||
/datum/skin_menu/proc/creation_list(client/C)
|
||||
. = list()
|
||||
// create categories after
|
||||
for(var/datum/skin_menu_category/cat as anything in categories)
|
||||
. |= cat.creation_list(C)
|
||||
|
||||
/datum/skin_menu/proc/setup(client/C, load = TRUE)
|
||||
create_and_bind(C)
|
||||
if(load)
|
||||
load_settings(C)
|
||||
|
||||
/datum/skin_menu/proc/all_entries()
|
||||
. = list()
|
||||
for(var/datum/skin_menu_category/C as anything in categories)
|
||||
for(var/datum/skin_menu_entry/E as anything in C.entries)
|
||||
if(istype(C, /datum/skin_menu_entry/spacer))
|
||||
continue
|
||||
. += E
|
||||
|
||||
/datum/skin_menu/proc/load_settings(client/C)
|
||||
// let's like, not do that before they load
|
||||
UNTIL(C.prefs.initialized)
|
||||
// basically we need to load saved settings, and default if not
|
||||
for(var/datum/skin_menu_entry/E as anything in all_entries())
|
||||
if(!E.checkbox || !E.is_saved)
|
||||
continue // don't care
|
||||
// don't load groups, they only load enable, not disable
|
||||
if(E.group)
|
||||
// we, do, however, want to load *unchecking* it.
|
||||
winset(C, E.id, "is-checked=false")
|
||||
continue
|
||||
// load anything else
|
||||
var/enabled = C.prefs.skin[E.id]
|
||||
if(isnull(enabled))
|
||||
// default
|
||||
enabled = E.is_default
|
||||
// save it while we're at it
|
||||
E.save(C, enabled)
|
||||
E.load(C, enabled)
|
||||
// we do need to load groups if possible
|
||||
for(var/group in button_groups)
|
||||
var/choice = C.prefs.skin[group]
|
||||
var/datum/skin_menu_entry/E
|
||||
if(isnull(choice) || !GLOB.skin_menu_entries[choice])
|
||||
// default if null or if choice doesn't exist anymore
|
||||
E = GLOB.skin_menu_entries[button_groups[group]]
|
||||
// save it while we're at it
|
||||
E.save(C, TRUE)
|
||||
else
|
||||
E = GLOB.skin_menu_entries[choice]
|
||||
E.load(C, TRUE)
|
||||
|
||||
/datum/skin_menu/proc/create_and_bind(client/C)
|
||||
// menu creation is special
|
||||
// we must winclone; skin must not have a control named "menu"
|
||||
winclone(C, SKIN_ID_ABSTRACT_MENU, id)
|
||||
var/list/creation = creation_list(C)
|
||||
for(var/id in creation)
|
||||
winset(C, id, creation[id])
|
||||
winset(C, bind_to, "menu=[id]")
|
||||
|
||||
//! skin menu categories
|
||||
/datum/skin_menu_category
|
||||
/// id - used for both skin and savefiles
|
||||
var/id
|
||||
/// name
|
||||
var/name
|
||||
/// entry datum types - transformed into datums at runtime; insert a null to create a divider
|
||||
var/list/datum/skin_menu_entry/entries
|
||||
/// menu we belong to
|
||||
var/datum/skin_menu/menu
|
||||
|
||||
/datum/skin_menu_category/New(datum/skin_menu/menu)
|
||||
src.menu = menu
|
||||
init_entries()
|
||||
|
||||
/datum/skin_menu_category/Destroy()
|
||||
QDEL_LIST(entries)
|
||||
return ..()
|
||||
|
||||
/datum/skin_menu_category/proc/init_entries()
|
||||
for(var/i in 1 to entries.len)
|
||||
var/path = entries[i]
|
||||
var/datum/skin_menu_entry/entry
|
||||
if(isnull(path))
|
||||
entry = new /datum/skin_menu_entry/spacer(src)
|
||||
else if(ispath(path))
|
||||
entry = new path(src)
|
||||
else
|
||||
continue // wtf? let it runtime later
|
||||
entries[i] = entry
|
||||
|
||||
/datum/skin_menu_category/proc/creation_list(client/C)
|
||||
. = list()
|
||||
// create us first
|
||||
.[id] = list2params(list(
|
||||
"parent" = menu.id,
|
||||
"name" = name,
|
||||
))
|
||||
// create our children
|
||||
for(var/datum/skin_menu_entry/E as anything in entries)
|
||||
.[E.id] = E.cached_constructor
|
||||
|
||||
//! skin menu entries
|
||||
/// lookup for skin menu entries
|
||||
GLOBAL_LIST_EMPTY(skin_menu_entries)
|
||||
/datum/skin_menu_entry
|
||||
/// id - used for both skin and savefiles
|
||||
var/id
|
||||
/// name
|
||||
var/name
|
||||
/**
|
||||
* command to execute; \n to execute multiple.
|
||||
* this datum will also inject our own command for synchronization automatically.
|
||||
* generate_command() overrides this.
|
||||
*/
|
||||
var/command
|
||||
/// do we have a button group? checkbox is required for this; we will NOT load disabled for groups!
|
||||
var/group
|
||||
/// default enabled for checkable? only one in a group can have this!! infact, only one in a group **MUST** have tihs!!
|
||||
var/is_default = FALSE
|
||||
/// checkable?
|
||||
var/checkbox = FALSE
|
||||
/// command to execute, if any, when loading prefs if we're checked
|
||||
var/load_command_enabled
|
||||
/// command to execute, if any, when loading prefs if we're unchecked
|
||||
var/load_command_disabled
|
||||
/// use proc for load command
|
||||
var/load_command_proc = FALSE
|
||||
/// default load_command_enabled to command
|
||||
var/load_command_default = FALSE
|
||||
/// is saved? only applicable for checkboxes
|
||||
var/is_saved = TRUE
|
||||
/// cached creation parameters
|
||||
var/cached_constructor
|
||||
/// category we belong to
|
||||
var/datum/skin_menu_category/category
|
||||
|
||||
/datum/skin_menu_entry/New(datum/skin_menu_category/category)
|
||||
src.category = category
|
||||
cache_constructor()
|
||||
if(load_command_default)
|
||||
load_command_enabled = generate_command(TRUE)
|
||||
register()
|
||||
|
||||
/datum/skin_menu_entry/Destroy()
|
||||
unregister()
|
||||
return ..()
|
||||
|
||||
/datum/skin_menu_entry/proc/register()
|
||||
if(GLOB.skin_menu_entries[id])
|
||||
stack_trace("warning: collision on [id] between [src] and [GLOB.skin_menu_entries[id]]; overwriting...")
|
||||
GLOB.skin_menu_entries[id] = src
|
||||
|
||||
/datum/skin_menu_entry/proc/unregister()
|
||||
GLOB.skin_menu_entries -= id
|
||||
|
||||
/datum/skin_menu_entry/proc/load(client/C, enabled)
|
||||
if(!checkbox || !is_saved)
|
||||
return // why do we care?
|
||||
var/command
|
||||
if(load_command_proc)
|
||||
if(enabled)
|
||||
command = load_command_enabled(C)
|
||||
else
|
||||
command = load_command_enabled(C)
|
||||
else
|
||||
if(enabled)
|
||||
command = load_command_enabled
|
||||
else
|
||||
command = load_command_disabled
|
||||
if(command)
|
||||
C.menu_run_command(command)
|
||||
if(enabled)
|
||||
C.menu_buttons_checked[id] = TRUE
|
||||
if(group)
|
||||
C.menu_group_status[group] = id
|
||||
else
|
||||
C.menu_buttons_checked -= id
|
||||
// we assume group is taken care of by the other item overwriting it.
|
||||
winset(C, id, "is-checked=[enabled? "true" : "false"]")
|
||||
|
||||
/datum/skin_menu_entry/proc/save(client/C, enabled)
|
||||
if(!checkbox || !is_saved)
|
||||
return // we don't care
|
||||
if(group)
|
||||
C.prefs.set_skin_data(group, id)
|
||||
else
|
||||
C.prefs.set_skin_data(id, enabled)
|
||||
|
||||
/**
|
||||
* called when someone presses us; using usr here is fine as this should only be called from verb anyways!
|
||||
*/
|
||||
/datum/skin_menu_entry/proc/pressed(client/C, new_checked)
|
||||
save(C, new_checked)
|
||||
if(!checkbox)
|
||||
return // don't care
|
||||
if(group && new_checked)
|
||||
C.menu_group_status[group] = id
|
||||
else
|
||||
if(new_checked)
|
||||
C.menu_buttons_checked[id] = TRUE
|
||||
else
|
||||
C.menu_buttons_checked -= id
|
||||
|
||||
/datum/skin_menu_entry/proc/load_command_enabled(client/C)
|
||||
CRASH("why did the proc get called without an override?")
|
||||
|
||||
/datum/skin_menu_entry/proc/load_command_disabled(client/C)
|
||||
CRASH("why did the proc get called without an override?")
|
||||
|
||||
/**
|
||||
* generates our normal command
|
||||
*
|
||||
* ! WARNING !
|
||||
* While loading, you CANNOT use chained commands with \n.
|
||||
*/
|
||||
/datum/skin_menu_entry/proc/generate_command(loading)
|
||||
return command
|
||||
|
||||
/**
|
||||
* should omit id, that'll be set separately
|
||||
*/
|
||||
/datum/skin_menu_entry/proc/creation_parameters()
|
||||
var/list/params = list()
|
||||
params["parent"] = category.id
|
||||
params["command"] = ".menutrigger \"[id]\" \[\[is-checked\]\]\n[generate_command()]"
|
||||
params["name"] = name
|
||||
if(group)
|
||||
params["group"] = group
|
||||
params["is-checked"] = is_default? "true" : "false"
|
||||
params["can-check"] = checkbox? "true" : "false"
|
||||
return list2params(params)
|
||||
|
||||
/datum/skin_menu_entry/proc/cache_constructor()
|
||||
cached_constructor = creation_parameters()
|
||||
|
||||
/**
|
||||
* the empty entry used as a spacer
|
||||
*/
|
||||
/datum/skin_menu_entry/spacer
|
||||
id = null
|
||||
name = null
|
||||
/// next id
|
||||
var/static/next_id = 0
|
||||
|
||||
/datum/skin_menu_entry/spacer/New()
|
||||
..()
|
||||
id = "menubutton_spacer_[++next_id]"
|
||||
|
||||
/datum/skin_menu_entry/spacer/register()
|
||||
return
|
||||
|
||||
/datum/skin_menu_entry/spacer/unregister()
|
||||
return
|
||||
|
||||
/datum/skin_menu_entry/spacer/creation_parameters()
|
||||
return list2params(list(
|
||||
parent = category.id,
|
||||
name = ""
|
||||
))
|
||||
|
||||
//! client stuff needed to make this work
|
||||
/client/verb/menu_button_triggered(id as text, checked as num)
|
||||
set name = ".menutrigger"
|
||||
set hidden = TRUE
|
||||
|
||||
var/datum/skin_menu_entry/E = GLOB.skin_menu_entries[id]
|
||||
if(!E)
|
||||
stack_trace("no entry found for [id], triggered by [src]")
|
||||
to_chat(usr, SPAN_WARNING("error: no menu entry found; this is a bug. id: [id]"))
|
||||
return
|
||||
E.pressed(src, checked)
|
||||
|
||||
/**
|
||||
* gets which button of a group we have selected
|
||||
*/
|
||||
/client/proc/menu_group_query(group)
|
||||
return menu_group_status[group]
|
||||
|
||||
/**
|
||||
* gets if a button is checked
|
||||
*/
|
||||
/client/proc/menu_button_checked(id)
|
||||
return menu_buttons_checked[id]
|
||||
|
||||
/**
|
||||
* executes a command
|
||||
*/
|
||||
/client/proc/menu_run_command(str)
|
||||
winset(src, null, list2params(list("command" = str)))
|
||||
@@ -0,0 +1,229 @@
|
||||
GLOBAL_DATUM_INIT(main_window_menu, /datum/skin_menu/main, new)
|
||||
|
||||
/datum/skin_menu/main
|
||||
id = SKIN_ID_MAIN_MENU
|
||||
bind_to = SKIN_WINDOW_ID_MAIN
|
||||
categories = list(
|
||||
/datum/skin_menu_category/main_file,
|
||||
/datum/skin_menu_category/main_zoom,
|
||||
/datum/skin_menu_category/main_scaling,
|
||||
/datum/skin_menu_category/main_help,
|
||||
)
|
||||
|
||||
/datum/skin_menu_category/main_file
|
||||
id = SKIN_ID_MENU_CATEGORY_FILE
|
||||
name = "File"
|
||||
entries = list(
|
||||
/datum/skin_menu_entry/quick_screenshot,
|
||||
/datum/skin_menu_entry/screenshot,
|
||||
/datum/skin_menu_entry/ping,
|
||||
/datum/skin_menu_entry/reconnect,
|
||||
/datum/skin_menu_entry/quit,
|
||||
)
|
||||
|
||||
/datum/skin_menu_category/main_zoom
|
||||
id = SKIN_ID_MENU_CATEGORY_ZOOM
|
||||
name = "Zoom"
|
||||
entries = list(
|
||||
/datum/skin_menu_entry/widescreen/automatic,
|
||||
/datum/skin_menu_entry/widescreen/legacy,
|
||||
null,
|
||||
/datum/skin_menu_entry/auto_fit,
|
||||
/datum/skin_menu_entry/fit_viewport,
|
||||
null,
|
||||
/datum/skin_menu_entry/zoom/stretch_to_fit,
|
||||
/datum/skin_menu_entry/zoom/stretch_to_fill,
|
||||
)
|
||||
|
||||
/datum/skin_menu_category/main_zoom/init_entries()
|
||||
. = ..()
|
||||
var/static/list/auto_sizes = list(
|
||||
32,
|
||||
48,
|
||||
64,
|
||||
72,
|
||||
96,
|
||||
128,
|
||||
)
|
||||
for(var/size in auto_sizes)
|
||||
entries += new /datum/skin_menu_entry/zoom/specific(src, size)
|
||||
|
||||
/datum/skin_menu_category/main_scaling
|
||||
id = SKIN_ID_MENU_CATEGORY_SCALING
|
||||
name = "Scaling"
|
||||
entries = list(
|
||||
/datum/skin_menu_entry/scaling/sharp,
|
||||
/datum/skin_menu_entry/scaling/normal,
|
||||
/datum/skin_menu_entry/scaling/blur,
|
||||
)
|
||||
|
||||
/datum/skin_menu_category/main_help
|
||||
id = SKIN_ID_MENU_CATEGORY_HELP
|
||||
name = "Help"
|
||||
entries = list(
|
||||
/datum/skin_menu_entry/adminhelp,
|
||||
)
|
||||
|
||||
//! file
|
||||
/datum/skin_menu_entry/quick_screenshot
|
||||
id = SKIN_ID_MENU_BUTTON_SCREENSHOT_QUICK
|
||||
name = "Quick Screenshot"
|
||||
command = ".screenshot auto"
|
||||
|
||||
/datum/skin_menu_entry/screenshot
|
||||
id = SKIN_ID_MENU_BUTTON_SCREENSHOT
|
||||
name = "Screenshot..."
|
||||
command = ".screenshot"
|
||||
|
||||
/datum/skin_menu_entry/quit
|
||||
id = SKIN_ID_MENU_BUTTON_QUIT
|
||||
name = "Quit"
|
||||
command = ".quit"
|
||||
|
||||
/datum/skin_menu_entry/reconnect
|
||||
id = SKIN_ID_MENU_BUTTON_RECONNECT
|
||||
name = "Reconnect"
|
||||
command = ".reconnect"
|
||||
|
||||
/datum/skin_menu_entry/ping
|
||||
id = SKIN_ID_MENU_BUTTON_PING
|
||||
name = "Ping (legacy chat)"
|
||||
command = ".ping"
|
||||
|
||||
//! zoom
|
||||
/datum/skin_menu_entry/zoom
|
||||
group = SKIN_BUTTON_GROUP_MAP_ZOOM
|
||||
load_command_default = TRUE
|
||||
checkbox = TRUE
|
||||
|
||||
/datum/skin_menu_entry/zoom/pressed(client/C, new_checked)
|
||||
. = ..()
|
||||
if(C.is_auto_fit_viewport_enabled())
|
||||
C.request_viewport_fit()
|
||||
C.request_viewport_update()
|
||||
|
||||
/datum/skin_menu_entry/zoom/load(client/C, enabled)
|
||||
. = ..()
|
||||
if(C.is_auto_fit_viewport_enabled())
|
||||
C.request_viewport_fit()
|
||||
C.request_viewport_update()
|
||||
|
||||
/datum/skin_menu_entry/zoom/stretch_to_fit
|
||||
name = "Stretch to Fit"
|
||||
id = SKIN_ID_MENU_BUTTON_STRETCH_TO_FIT
|
||||
is_default = TRUE
|
||||
|
||||
/datum/skin_menu_entry/zoom/stretch_to_fit/generate_command(loading)
|
||||
if(loading)
|
||||
return ".winset \"[SKIN_MAP_ID_VIEWPORT].zoom=0;[SKIN_MAP_ID_VIEWPORT].letterbox=true\""
|
||||
return ".winset \"[SKIN_MAP_ID_VIEWPORT].zoom=0;[SKIN_MAP_ID_VIEWPORT].letterbox=true\"\n.update_viewport"
|
||||
|
||||
/datum/skin_menu_entry/zoom/stretch_to_fill
|
||||
name = "Stretch to Fill"
|
||||
id = SKIN_ID_MENU_BUTTON_STRETCH_NO_LETTERBOX
|
||||
|
||||
/datum/skin_menu_entry/zoom/stretch_to_fill/generate_command(loading)
|
||||
if(loading)
|
||||
return ".winset \"[SKIN_MAP_ID_VIEWPORT].zoom=0;[SKIN_MAP_ID_VIEWPORT].letterbox=false\""
|
||||
return ".winset \"[SKIN_MAP_ID_VIEWPORT].zoom=0;[SKIN_MAP_ID_VIEWPORT].letterbox=false\"\n.update_viewport"
|
||||
|
||||
//? the normal sizes are created by main_zoom category
|
||||
/datum/skin_menu_entry/zoom/specific
|
||||
/// our pixel size
|
||||
var/pixel_size
|
||||
|
||||
/datum/skin_menu_entry/zoom/specific/New(datum/skin_menu_category/category, pixel_size)
|
||||
src.pixel_size = pixel_size
|
||||
src.id = SKIN_ID_MENU_BUTTON_FOR_RESOLUTION(pixel_size)
|
||||
src.name = "[pixel_size]x[pixel_size]"
|
||||
..()
|
||||
|
||||
/datum/skin_menu_entry/zoom/specific/generate_command(loading)
|
||||
var/zoom = pixel_size / WORLD_ICON_SIZE
|
||||
if(loading)
|
||||
return ".winset \"[SKIN_MAP_ID_VIEWPORT].zoom=[zoom]\""
|
||||
return ".winset \"[SKIN_MAP_ID_VIEWPORT].zoom=[zoom]\"\n.update_viewport"
|
||||
|
||||
//! widescreen
|
||||
/datum/skin_menu_entry/widescreen
|
||||
group = SKIN_BUTTON_GROUP_MAP_WIDESCREEN
|
||||
checkbox = TRUE
|
||||
|
||||
/datum/skin_menu_entry/widescreen/pressed(client/C, new_checked)
|
||||
. = ..()
|
||||
if(C.is_auto_fit_viewport_enabled())
|
||||
C.request_viewport_fit()
|
||||
C.request_viewport_update()
|
||||
|
||||
/datum/skin_menu_entry/widescreen/load(client/C, enabled)
|
||||
. = ..()
|
||||
if(C.is_auto_fit_viewport_enabled())
|
||||
C.request_viewport_fit()
|
||||
C.request_viewport_update()
|
||||
|
||||
/datum/skin_menu_entry/widescreen/automatic
|
||||
id = SKIN_ID_MENU_BUTTON_WIDESCREEN_ENABLED
|
||||
name = "Automatic Widescreen"
|
||||
is_default = TRUE
|
||||
|
||||
/datum/skin_menu_entry/widescreen/legacy
|
||||
id = SKIN_ID_MENU_BUTTON_WIDESCREEN_DISABLED
|
||||
name = "Lock to 15x15 (Legacy)"
|
||||
|
||||
/client/proc/is_widescreen_enabled()
|
||||
return menu_group_query(SKIN_BUTTON_GROUP_MAP_WIDESCREEN) == SKIN_ID_MENU_BUTTON_WIDESCREEN_ENABLED
|
||||
|
||||
//! misc zoom
|
||||
/datum/skin_menu_entry/auto_fit
|
||||
id = SKIN_ID_MENU_BUTTON_AUTO_FIT_VIEWPORT
|
||||
name = "Automatically Fit Viewport (EXPERIMENTAL)"
|
||||
checkbox = TRUE
|
||||
is_default = FALSE
|
||||
|
||||
/datum/skin_menu_entry/auto_fit/load(client/C, enabled)
|
||||
. = ..()
|
||||
if(enabled)
|
||||
C.request_viewport_fit()
|
||||
|
||||
/client/proc/is_auto_fit_viewport_enabled()
|
||||
return menu_button_checked(SKIN_ID_MENU_BUTTON_AUTO_FIT_VIEWPORT)
|
||||
|
||||
/datum/skin_menu_entry/fit_viewport
|
||||
id = SKIN_ID_MENU_BUTTON_FIT_VIEWPORT
|
||||
name = "Fit Viewport"
|
||||
|
||||
/datum/skin_menu_entry/fit_viewport/pressed(client/C, new_checked)
|
||||
. = ..()
|
||||
C.request_viewport_fit()
|
||||
|
||||
//! scaling
|
||||
/datum/skin_menu_entry/scaling
|
||||
group = SKIN_BUTTON_GROUP_MAP_SCALING
|
||||
checkbox = TRUE
|
||||
load_command_default = TRUE
|
||||
var/zoom_mode
|
||||
|
||||
/datum/skin_menu_entry/scaling/generate_command(loading)
|
||||
return ".winset \"[SKIN_MAP_ID_VIEWPORT].zoom-mode=[zoom_mode]\""
|
||||
|
||||
/datum/skin_menu_entry/scaling/sharp
|
||||
id = SKIN_ID_MENU_BUTTON_NEAREST_NEIGHBOR
|
||||
name = "Nearest Neighbor (Sharp)"
|
||||
zoom_mode = "distort"
|
||||
is_default = TRUE
|
||||
|
||||
/datum/skin_menu_entry/scaling/normal
|
||||
id = SKIN_ID_MENU_BUTTON_POINT_SAMPLE
|
||||
name = "Point Sampling (Normal)"
|
||||
zoom_mode = "normal"
|
||||
|
||||
/datum/skin_menu_entry/scaling/blur
|
||||
id = SKIN_ID_MENU_BUTTON_BILINEAR
|
||||
name = "Bilinear (Blurry)"
|
||||
zoom_mode = "blur"
|
||||
|
||||
//! help
|
||||
/datum/skin_menu_entry/adminhelp
|
||||
id = SKIN_ID_MENU_BUTTON_ADMINHELP
|
||||
name = "Admin Help (F1)"
|
||||
command = "adminhelp"
|
||||
+32
-270
@@ -1,284 +1,59 @@
|
||||
macro "default"
|
||||
|
||||
|
||||
menu "menu"
|
||||
elem
|
||||
name = "&File"
|
||||
command = ""
|
||||
saved-params = "is-checked"
|
||||
elem
|
||||
name = "&Quick screenshot\tF2"
|
||||
command = ".screenshot auto"
|
||||
category = "&File"
|
||||
saved-params = "is-checked"
|
||||
elem
|
||||
name = "&Save screenshot as...\tShift+F2"
|
||||
command = ".screenshot"
|
||||
category = "&File"
|
||||
saved-params = "is-checked"
|
||||
elem
|
||||
name = ""
|
||||
command = ""
|
||||
category = "&File"
|
||||
saved-params = "is-checked"
|
||||
elem
|
||||
name = "&Reconnect"
|
||||
command = ".reconnect"
|
||||
category = "&File"
|
||||
saved-params = "is-checked"
|
||||
elem
|
||||
name = "&Check ping"
|
||||
command = ".ping"
|
||||
category = "&File"
|
||||
saved-params = "is-checked"
|
||||
elem
|
||||
name = "&Quit"
|
||||
command = ".quit"
|
||||
category = "&File"
|
||||
saved-params = "is-checked"
|
||||
elem
|
||||
name = "&Size"
|
||||
command = ""
|
||||
saved-params = "is-checked"
|
||||
elem "stretch"
|
||||
name = "&Round up and lock to size"
|
||||
command = ".winset \"mapwindow.map.icon-size=0\""
|
||||
category = "&Size"
|
||||
is-checked = true
|
||||
can-check = true
|
||||
group = "size"
|
||||
saved-params = "is-checked"
|
||||
elem "cozyin"
|
||||
name = "Get Cozy Inwards"
|
||||
command = "SetCozyViewInwards 8"
|
||||
category = "&Size"
|
||||
can-check = false
|
||||
group = "size"
|
||||
saved-params = "is-checked"
|
||||
elem "icon128"
|
||||
name = "&128x128 (4K)"
|
||||
command = "SetWindowIconSize 128"
|
||||
category = "&Size"
|
||||
can-check = true
|
||||
group = "size"
|
||||
saved-params = "is-checked"
|
||||
elem "icon96"
|
||||
name = "&96x96"
|
||||
command = "SetWindowIconSize 96"
|
||||
category = "&Size"
|
||||
can-check = true
|
||||
group = "size"
|
||||
saved-params = "is-checked"
|
||||
elem "icon72"
|
||||
name = "&72x72 (Cozy 1080p)"
|
||||
command = "SetWindowIconSize 72"
|
||||
category = "&Size"
|
||||
is-checked = true
|
||||
can-check = true
|
||||
group = "size"
|
||||
saved-params = "is-checked"
|
||||
elem "icon64"
|
||||
name = "&64x64 (1080p)"
|
||||
command = "SetWindowIconSize 64"
|
||||
category = "&Size"
|
||||
is-checked = true
|
||||
can-check = true
|
||||
group = "size"
|
||||
saved-params = "is-checked"
|
||||
elem "icon48"
|
||||
name = "&48x48"
|
||||
command = "SetWindowIconSize 48"
|
||||
category = "&Size"
|
||||
can-check = true
|
||||
group = "size"
|
||||
saved-params = "is-checked"
|
||||
elem "icon32"
|
||||
name = "&32x32"
|
||||
command = "SetWindowIconSize 32"
|
||||
category = "&Size"
|
||||
can-check = true
|
||||
group = "size"
|
||||
saved-params = "is-checked"
|
||||
elem
|
||||
name = "&Scaling"
|
||||
command = ""
|
||||
saved-params = "is-checked"
|
||||
elem "ZM"
|
||||
name = "&Smooth Scaling"
|
||||
command = ".winset \"zoommode.is-checked=true?map.zoom-mode=normal:map.zoom-mode=distort\""
|
||||
category = "&Scaling"
|
||||
is-checked = true
|
||||
can-check = true
|
||||
group = "scale"
|
||||
saved-params = "is-checked"
|
||||
elem "NN"
|
||||
name = "&Nearest Neighbor"
|
||||
command = ".winset \"mapwindow.map.zoom-mode=distort\""
|
||||
category = "&Scaling"
|
||||
can-check = true
|
||||
group = "scale"
|
||||
saved-params = "is-checked"
|
||||
elem "PS"
|
||||
name = "&Point Sampling"
|
||||
command = ".winset \"mapwindow.map.zoom-mode=normal\""
|
||||
category = "&Scaling"
|
||||
can-check = true
|
||||
group = "scale"
|
||||
saved-params = "is-checked"
|
||||
elem "BL"
|
||||
name = "&Bilinear"
|
||||
command = ".winset \"mapwindow.map.zoom-mode=blur\""
|
||||
category = "&Scaling"
|
||||
can-check = true
|
||||
group = "scale"
|
||||
saved-params = "is-checked"
|
||||
elem
|
||||
name = "&Help"
|
||||
command = ""
|
||||
saved-params = "is-checked"
|
||||
elem
|
||||
name = "&Admin help\tF1"
|
||||
command = "adminhelp"
|
||||
category = "&Help"
|
||||
saved-params = "is-checked"
|
||||
elem
|
||||
name = "&Hotkeys"
|
||||
command = "hotkeys-help"
|
||||
category = "&Help"
|
||||
saved-params = "is-checked"
|
||||
|
||||
|
||||
window "Telecomms IDE"
|
||||
elem "Telecomms IDE"
|
||||
type = MAIN
|
||||
pos = 281,0
|
||||
size = 569x582
|
||||
anchor1 = none
|
||||
anchor2 = none
|
||||
background-color = #ffffff
|
||||
is-visible = false
|
||||
saved-params = "pos;size;is-minimized;is-maximized"
|
||||
title = "TCS IDE"
|
||||
statusbar = false
|
||||
on-close = "exittcs"
|
||||
elem "button5"
|
||||
type = BUTTON
|
||||
pos = 209,464
|
||||
size = 70x20
|
||||
anchor1 = 37,80
|
||||
anchor2 = 49,83
|
||||
saved-params = "is-checked"
|
||||
text = "Clear Memory"
|
||||
command = "tcsclearmem"
|
||||
elem "button4"
|
||||
type = BUTTON
|
||||
pos = 157,464
|
||||
size = 52x20
|
||||
anchor1 = 28,80
|
||||
anchor2 = 37,83
|
||||
saved-params = "is-checked"
|
||||
text = "Revert"
|
||||
command = "tcsrevert"
|
||||
elem "button3"
|
||||
type = BUTTON
|
||||
pos = 105,464
|
||||
size = 52x20
|
||||
anchor1 = 18,80
|
||||
anchor2 = 28,83
|
||||
saved-params = "is-checked"
|
||||
text = "Execute"
|
||||
command = "tcsrun"
|
||||
elem "tcserror"
|
||||
type = OUTPUT
|
||||
pos = 0,488
|
||||
size = 566x94
|
||||
anchor1 = 0,84
|
||||
anchor2 = 99,100
|
||||
font-family = "sans-serif"
|
||||
font-size = 9
|
||||
saved-params = "max-lines"
|
||||
elem "button2"
|
||||
type = BUTTON
|
||||
pos = 53,464
|
||||
size = 52x20
|
||||
anchor1 = 9,80
|
||||
anchor2 = 18,83
|
||||
saved-params = "is-checked"
|
||||
text = "Compile"
|
||||
command = "tcscompile"
|
||||
elem "button1"
|
||||
type = BUTTON
|
||||
pos = 0,464
|
||||
size = 53x20
|
||||
anchor1 = 0,80
|
||||
anchor2 = 9,83
|
||||
saved-params = "is-checked"
|
||||
text = "Apply"
|
||||
command = "tcssave"
|
||||
elem "tcscode"
|
||||
type = INPUT
|
||||
pos = 0,0
|
||||
size = 569x464
|
||||
anchor1 = 0,0
|
||||
anchor2 = 100,80
|
||||
font-family = "Courier"
|
||||
font-size = 10
|
||||
saved-params = ""
|
||||
command = "cancel"
|
||||
multi-line = true
|
||||
no-command = true
|
||||
|
||||
window "mainwindow"
|
||||
elem "mainwindow"
|
||||
type = MAIN
|
||||
pos = 0,0
|
||||
size = 640x440
|
||||
anchor1 = none
|
||||
anchor2 = none
|
||||
size = 640x480
|
||||
anchor1 = -1,-1
|
||||
anchor2 = -1,-1
|
||||
background-color = none
|
||||
is-default = true
|
||||
saved-params = "pos;size;is-minimized;is-maximized"
|
||||
icon = 'icons\\CS13.png'
|
||||
macro = "default"
|
||||
menu = "menu"
|
||||
on-size = "OnResize"
|
||||
outer-size = 656x538
|
||||
inner-size = 640x499
|
||||
elem "split"
|
||||
type = CHILD
|
||||
pos = 3,0
|
||||
size = 640x440
|
||||
pos = 0,0
|
||||
size = 640x480
|
||||
anchor1 = 0,0
|
||||
anchor2 = 100,100
|
||||
background-color = none
|
||||
saved-params = "splitter"
|
||||
left = "mapwindow"
|
||||
right = "infowindow"
|
||||
is-vert = true
|
||||
on-size = "OnResize"
|
||||
elem "asset_cache_browser"
|
||||
type = BROWSER
|
||||
pos = 0,0
|
||||
size = 200x200
|
||||
anchor1 = none
|
||||
anchor2 = none
|
||||
anchor1 = -1,-1
|
||||
anchor2 = -1,-1
|
||||
background-color = none
|
||||
is-visible = false
|
||||
saved-params = ""
|
||||
elem "tooltip"
|
||||
type = BROWSER
|
||||
pos = 0,0
|
||||
size = 999x999
|
||||
anchor1 = none
|
||||
anchor2 = none
|
||||
anchor1 = -1,-1
|
||||
anchor2 = -1,-1
|
||||
background-color = none
|
||||
is-visible = false
|
||||
saved-params = ""
|
||||
|
||||
window "mapwindow"
|
||||
elem "mapwindow"
|
||||
type = MAIN
|
||||
pos = 0,0
|
||||
pos = 281,0
|
||||
size = 640x480
|
||||
anchor1 = none
|
||||
anchor2 = none
|
||||
anchor1 = -1,-1
|
||||
anchor2 = -1,-1
|
||||
saved-params = "pos;size;is-minimized;is-maximized"
|
||||
is-pane = true
|
||||
on-size = "OnResize"
|
||||
elem "map"
|
||||
type = MAP
|
||||
pos = 0,0
|
||||
@@ -287,9 +62,9 @@ window "mapwindow"
|
||||
anchor2 = 100,100
|
||||
font-family = "Arial"
|
||||
font-size = 7
|
||||
text-color = none
|
||||
is-default = true
|
||||
saved-params = "zoom;letterbox;zoom-mode"
|
||||
saved-params = ""
|
||||
on-size = ".on_viewport [[width]] [[height]] [[zoom]] [[letterbox]]"
|
||||
style = ".center { text-align: center; } .maptext { font-family: 'Small Fonts'; font-size: 7px; -dm-text-outline: 1px black; color: white; line-height: 1.1; } .command_headset { font-weight: bold;\tfont-size: 8px; } .small { font-size: 6px; } .big { font-size: 8px; } .reallybig { font-size: 8px; } .extremelybig { font-size: 8px; } .greentext { color: #00FF00; font-size: 7px; } .redtext { color: #FF0000; font-size: 7px; } .clown { color: #FF69Bf; font-size: 7px; font-weight: bold; } .his_grace { color: #15D512; } .hypnophrase { color: #0d0d0d; font-weight: bold; } .yell { font-weight: bold; } .italics { font-size: 6px; }"
|
||||
|
||||
window "preferences_window"
|
||||
@@ -297,8 +72,8 @@ window "preferences_window"
|
||||
type = MAIN
|
||||
pos = 281,0
|
||||
size = 1000x800
|
||||
anchor1 = none
|
||||
anchor2 = none
|
||||
anchor1 = -1,-1
|
||||
anchor2 = -1,-1
|
||||
is-visible = false
|
||||
saved-params = "pos;size;is-minimized;is-maximized"
|
||||
statusbar = false
|
||||
@@ -323,20 +98,16 @@ window "infowindow"
|
||||
type = MAIN
|
||||
pos = 418,0
|
||||
size = 640x480
|
||||
anchor1 = none
|
||||
anchor2 = none
|
||||
background-color = none
|
||||
anchor1 = -1,-1
|
||||
anchor2 = -1,-1
|
||||
saved-params = "pos;size;is-minimized;is-maximized"
|
||||
is-pane = true
|
||||
outer-size = 662x561
|
||||
inner-size = 640x505
|
||||
elem "mediapanel"
|
||||
type = BROWSER
|
||||
pos = 88,216
|
||||
size = 200x200
|
||||
anchor1 = none
|
||||
anchor2 = none
|
||||
background-color = none
|
||||
anchor1 = -1,-1
|
||||
anchor2 = -1,-1
|
||||
is-visible = false
|
||||
saved-params = ""
|
||||
elem "info"
|
||||
@@ -345,7 +116,6 @@ window "infowindow"
|
||||
size = 640x445
|
||||
anchor1 = 0,0
|
||||
anchor2 = 100,100
|
||||
background-color = none
|
||||
saved-params = "splitter"
|
||||
left = "statwindow"
|
||||
right = "outputwindow"
|
||||
@@ -356,7 +126,6 @@ window "infowindow"
|
||||
size = 104x20
|
||||
anchor1 = 3,0
|
||||
anchor2 = 19,0
|
||||
background-color = none
|
||||
saved-params = "is-checked"
|
||||
text = "Changelog"
|
||||
command = "changelog"
|
||||
@@ -366,7 +135,6 @@ window "infowindow"
|
||||
size = 100x20
|
||||
anchor1 = 19,0
|
||||
anchor2 = 34,0
|
||||
background-color = none
|
||||
saved-params = "is-checked"
|
||||
text = "Rules"
|
||||
command = "rules"
|
||||
@@ -376,7 +144,6 @@ window "infowindow"
|
||||
size = 100x20
|
||||
anchor1 = 34,0
|
||||
anchor2 = 50,0
|
||||
background-color = none
|
||||
saved-params = "is-checked"
|
||||
text = "Wiki"
|
||||
command = "wiki"
|
||||
@@ -386,7 +153,6 @@ window "infowindow"
|
||||
size = 100x20
|
||||
anchor1 = 50,0
|
||||
anchor2 = 66,0
|
||||
background-color = none
|
||||
saved-params = "is-checked"
|
||||
text = "Forum"
|
||||
command = "forum"
|
||||
@@ -396,7 +162,6 @@ window "infowindow"
|
||||
size = 100x20
|
||||
anchor1 = 66,0
|
||||
anchor2 = 81,0
|
||||
background-color = none
|
||||
saved-params = "is-checked"
|
||||
text = "Github"
|
||||
command = "github"
|
||||
@@ -406,7 +171,6 @@ window "infowindow"
|
||||
size = 100x20
|
||||
anchor1 = 81,0
|
||||
anchor2 = 97,0
|
||||
background-color = none
|
||||
saved-params = "is-checked"
|
||||
text = "Report Issue"
|
||||
command = "report-issue"
|
||||
@@ -416,8 +180,8 @@ window "outputwindow"
|
||||
type = MAIN
|
||||
pos = 0,0
|
||||
size = 640x480
|
||||
anchor1 = none
|
||||
anchor2 = none
|
||||
anchor1 = -1,-1
|
||||
anchor2 = -1,-1
|
||||
saved-params = "pos;size;is-minimized;is-maximized"
|
||||
is-pane = true
|
||||
elem "browseroutput"
|
||||
@@ -436,7 +200,6 @@ window "outputwindow"
|
||||
size = 40x20
|
||||
anchor1 = 100,100
|
||||
anchor2 = -1,-1
|
||||
background-color = none
|
||||
saved-params = "is-checked"
|
||||
text = "Chat"
|
||||
command = ".winset \"saybutton.is-checked=true?input.command=\"!say \\\"\" macrobutton.is-checked=false:input.command=\""
|
||||
@@ -457,7 +220,6 @@ window "outputwindow"
|
||||
size = 80x20
|
||||
anchor1 = 100,100
|
||||
anchor2 = -1,-1
|
||||
background-color = none
|
||||
saved-params = ""
|
||||
text = "Hotkey Toggle"
|
||||
command = ".winset \"mainwindow.macro!=macro ? mainwindow.macro=macro hotkey_toggle.is-checked=false input.focus=true : mainwindow.macro=hotkeymode hotkey_toggle.is-checked=true mapwindow.map.focus=true\""
|
||||
@@ -474,8 +236,8 @@ window "outputwindow"
|
||||
type = BROWSER
|
||||
pos = 0,0
|
||||
size = 200x200
|
||||
anchor1 = none
|
||||
anchor2 = none
|
||||
anchor1 = -1,-1
|
||||
anchor2 = -1,-1
|
||||
is-visible = false
|
||||
saved-params = ""
|
||||
|
||||
@@ -484,8 +246,8 @@ window "statwindow"
|
||||
type = MAIN
|
||||
pos = 372,0
|
||||
size = 640x480
|
||||
anchor1 = none
|
||||
anchor2 = none
|
||||
anchor1 = -1,-1
|
||||
anchor2 = -1,-1
|
||||
saved-params = "pos;size;is-minimized;is-maximized"
|
||||
is-pane = true
|
||||
elem "statbrowser"
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
anchored = 1
|
||||
plane = TURF_PLANE
|
||||
layer = ABOVE_TURF_LAYER
|
||||
appearance_flags = PIXEL_SCALE|KEEP_TOGETHER
|
||||
SET_APPEARANCE_FLAGS(TILE_BOUND)
|
||||
|
||||
var/_stair_tag //Make this match another one and they'll connect!
|
||||
|
||||
|
||||
@@ -132,10 +132,10 @@ export const setClientTheme = name => {
|
||||
// Say, OOC, me Buttons etc.
|
||||
'saybutton.background-color': COLOR_DARK_BG,
|
||||
'saybutton.text-color': COLOR_DARK_TEXT,
|
||||
'oocbutton.background-color': COLOR_DARK_BG,
|
||||
'oocbutton.text-color': COLOR_DARK_TEXT,
|
||||
'mebutton.background-color': COLOR_DARK_BG,
|
||||
'mebutton.text-color': COLOR_DARK_TEXT,
|
||||
// 'oocbutton.background-color': COLOR_DARK_BG,
|
||||
// 'oocbutton.text-color': COLOR_DARK_TEXT,
|
||||
// 'mebutton.background-color': COLOR_DARK_BG,
|
||||
// 'mebutton.text-color': COLOR_DARK_TEXT,
|
||||
'asset_cache_browser.background-color': COLOR_DARK_BG,
|
||||
'asset_cache_browser.text-color': COLOR_DARK_TEXT,
|
||||
'tooltip.background-color': COLOR_DARK_BG,
|
||||
@@ -182,10 +182,10 @@ export const setClientTheme = name => {
|
||||
// Say, OOC, me Buttons etc.
|
||||
'saybutton.background-color': COLOR_DARK_BG,
|
||||
'saybutton.text-color': COLOR_DARK_TEXT,
|
||||
'oocbutton.background-color': COLOR_DARK_BG,
|
||||
'oocbutton.text-color': COLOR_DARK_TEXT,
|
||||
'mebutton.background-color': COLOR_DARK_BG,
|
||||
'mebutton.text-color': COLOR_DARK_TEXT,
|
||||
// 'oocbutton.background-color': COLOR_DARK_BG,
|
||||
// 'oocbutton.text-color': COLOR_DARK_TEXT,
|
||||
// 'mebutton.background-color': COLOR_DARK_BG,
|
||||
// 'mebutton.text-color': COLOR_DARK_TEXT,
|
||||
'asset_cache_browser.background-color': COLOR_DARK_BG,
|
||||
'asset_cache_browser.text-color': COLOR_DARK_TEXT,
|
||||
'tooltip.background-color': COLOR_DARK_BG,
|
||||
|
||||
Reference in New Issue
Block a user