Files
Yogstation/code/__HELPERS/icon_smoothing.dm
alexkar598 2333d64f09 Adds support for 513(and unicode), additionally drops supports for 512 in the process and updates dreamchecker(turdis) and casually fixes about 90 bugs in the codebase (#8324)
* Cherry picks the unicode part 2 PR from TG

* Things

* drop 512 support

* TAN --> tan

* Manually does the things that was in renamed files

* CLAMP --> clamp

* ismovableatom -> ismovable

* bugfixes, tg is bad

* Ports sanitize_name

* Bumps checks

* Fixes new linter errors (#48126)

About The Pull Request

This fixes the errors raised by the new feature I'm adding to the linter: SpaceManiac/SpacemanDMM#119

* Update SpacemanDMM suite to 1.2 (#48785)

* Update SpacemanDMM suite to 1.2

* Fix new lint errors

* Removes unreachable code (#48143)

About The Pull Request

As detected by SpaceManiac/SpacemanDMM#123

* casually fixes 50 bugs

* stoopid evil dreamchecker

* stoopid evil dreamchecker

* stoopid evil dreamchecker

* almost the same thing

* Makes all UIs UTF-8

* Fixes bugs

* Fixes runtimes, some related to 513, some not

* Fixes agent ids

Co-authored-by: MrPerson <spamtaffic@gmail.com>
Co-authored-by: alexkar598 <>
Co-authored-by: spookydonut <github@spooksoftware.com>
2020-05-02 00:43:42 -04:00

403 lines
12 KiB
Plaintext

//generic (by snowflake) tile smoothing code; smooth your icons with this!
/*
Each tile is divided in 4 corners, each corner has an appearance associated to it; the tile is then overlayed by these 4 appearances
To use this, just set your atom's 'smooth' var to 1. If your atom can be moved/unanchored, set its 'can_be_unanchored' var to 1.
If you don't want your atom's icon to smooth with anything but atoms of the same type, set the list 'canSmoothWith' to null;
Otherwise, put all types you want the atom icon to smooth with in 'canSmoothWith' INCLUDING THE TYPE OF THE ATOM ITSELF.
Each atom has its own icon file with all the possible corner states. See 'smooth_wall.dmi' for a template.
DIAGONAL SMOOTHING INSTRUCTIONS
To make your atom smooth diagonally you need all the proper icon states (see 'smooth_wall.dmi' for a template) and
to add the 'SMOOTH_DIAGONAL' flag to the atom's smooth var (in addition to either SMOOTH_TRUE or SMOOTH_MORE).
For turfs, what appears under the diagonal corners depends on the turf that was in the same position previously: if you make a wall on
a plating floor, you will see plating under the diagonal wall corner, if it was space, you will see space.
If you wish to map a diagonal wall corner with a fixed underlay, you must configure the turf's 'fixed_underlay' list var, like so:
fixed_underlay = list("icon"='icon_file.dmi', "icon_state"="iconstatename")
A non null 'fixed_underlay' list var will skip copying the previous turf appearance and always use the list. If the list is
not set properly, the underlay will default to regular floor plating.
To see an example of a diagonal wall, see '/turf/closed/wall/mineral/titanium' and its subtypes.
*/
//Redefinitions of the diagonal directions so they can be stored in one var without conflicts
#define N_NORTH (1<<1)
#define N_SOUTH (1<<2)
#define N_EAST (1<<4)
#define N_WEST (1<<8)
#define N_NORTHEAST (1<<5)
#define N_NORTHWEST (1<<9)
#define N_SOUTHEAST (1<<6)
#define N_SOUTHWEST (1<<10)
#define SMOOTH_FALSE 0 //not smooth
#define SMOOTH_TRUE (1<<0) //smooths with exact specified types or just itself
#define SMOOTH_MORE (1<<1) //smooths with all subtypes of specified types or just itself (this value can replace SMOOTH_TRUE)
#define SMOOTH_DIAGONAL (1<<2) //if atom should smooth diagonally, this should be present in 'smooth' var
#define SMOOTH_BORDER (1<<3) //atom will smooth with the borders of the map
#define SMOOTH_QUEUED (1<<4) //atom is currently queued to smooth.
#define NULLTURF_BORDER 123456789
#define DEFAULT_UNDERLAY_ICON 'icons/turf/floors.dmi'
#define DEFAULT_UNDERLAY_ICON_STATE "plating"
/atom/var/smooth = SMOOTH_FALSE
/atom/var/top_left_corner
/atom/var/top_right_corner
/atom/var/bottom_left_corner
/atom/var/bottom_right_corner
/atom/var/list/canSmoothWith = null // TYPE PATHS I CAN SMOOTH WITH~~~~~ If this is null and atom is smooth, it smooths only with itself
/atom/movable/var/can_be_unanchored = FALSE
/turf/var/list/fixed_underlay = null
/proc/calculate_adjacencies(atom/A)
if(!A.loc)
return 0
var/adjacencies = 0
var/atom/movable/AM
if(ismovable(A))
AM = A
if(AM.can_be_unanchored && !AM.anchored)
return 0
for(var/direction in GLOB.cardinals)
AM = find_type_in_direction(A, direction)
if(AM == NULLTURF_BORDER)
if((A.smooth & SMOOTH_BORDER))
adjacencies |= 1 << direction
else if( (AM && !istype(AM)) || (istype(AM) && AM.anchored) )
adjacencies |= 1 << direction
if(adjacencies & N_NORTH)
if(adjacencies & N_WEST)
AM = find_type_in_direction(A, NORTHWEST)
if(AM == NULLTURF_BORDER)
if((A.smooth & SMOOTH_BORDER))
adjacencies |= N_NORTHWEST
else if( (AM && !istype(AM)) || (istype(AM) && AM.anchored) )
adjacencies |= N_NORTHWEST
if(adjacencies & N_EAST)
AM = find_type_in_direction(A, NORTHEAST)
if(AM == NULLTURF_BORDER)
if((A.smooth & SMOOTH_BORDER))
adjacencies |= N_NORTHEAST
else if( (AM && !istype(AM)) || (istype(AM) && AM.anchored) )
adjacencies |= N_NORTHEAST
if(adjacencies & N_SOUTH)
if(adjacencies & N_WEST)
AM = find_type_in_direction(A, SOUTHWEST)
if(AM == NULLTURF_BORDER)
if((A.smooth & SMOOTH_BORDER))
adjacencies |= N_SOUTHWEST
else if( (AM && !istype(AM)) || (istype(AM) && AM.anchored) )
adjacencies |= N_SOUTHWEST
if(adjacencies & N_EAST)
AM = find_type_in_direction(A, SOUTHEAST)
if(AM == NULLTURF_BORDER)
if((A.smooth & SMOOTH_BORDER))
adjacencies |= N_SOUTHEAST
else if( (AM && !istype(AM)) || (istype(AM) && AM.anchored) )
adjacencies |= N_SOUTHEAST
return adjacencies
//do not use, use queue_smooth(atom)
/proc/smooth_icon(atom/A)
if(!A || !A.smooth)
return
A.smooth &= ~SMOOTH_QUEUED
if (!A.z)
return
if(QDELETED(A))
return
if(A.smooth & (SMOOTH_TRUE | SMOOTH_MORE))
var/adjacencies = calculate_adjacencies(A)
if(A.smooth & SMOOTH_DIAGONAL)
A.diagonal_smooth(adjacencies)
else
cardinal_smooth(A, adjacencies)
/atom/proc/diagonal_smooth(adjacencies)
switch(adjacencies)
if(N_NORTH|N_WEST)
replace_smooth_overlays("d-se","d-se-0")
if(N_NORTH|N_EAST)
replace_smooth_overlays("d-sw","d-sw-0")
if(N_SOUTH|N_WEST)
replace_smooth_overlays("d-ne","d-ne-0")
if(N_SOUTH|N_EAST)
replace_smooth_overlays("d-nw","d-nw-0")
if(N_NORTH|N_WEST|N_NORTHWEST)
replace_smooth_overlays("d-se","d-se-1")
if(N_NORTH|N_EAST|N_NORTHEAST)
replace_smooth_overlays("d-sw","d-sw-1")
if(N_SOUTH|N_WEST|N_SOUTHWEST)
replace_smooth_overlays("d-ne","d-ne-1")
if(N_SOUTH|N_EAST|N_SOUTHEAST)
replace_smooth_overlays("d-nw","d-nw-1")
else
cardinal_smooth(src, adjacencies)
return
icon_state = ""
return adjacencies
//only walls should have a need to handle underlays
/turf/closed/wall/diagonal_smooth(adjacencies)
adjacencies = reverse_ndir(..())
if(adjacencies)
var/mutable_appearance/underlay_appearance = mutable_appearance(layer = TURF_LAYER, plane = FLOOR_PLANE)
var/list/U = list(underlay_appearance)
if(fixed_underlay)
if(fixed_underlay["space"])
underlay_appearance.icon = 'icons/turf/space.dmi'
underlay_appearance.icon_state = SPACE_ICON_STATE
underlay_appearance.plane = PLANE_SPACE
else
underlay_appearance.icon = fixed_underlay["icon"]
underlay_appearance.icon_state = fixed_underlay["icon_state"]
else
var/turned_adjacency = turn(adjacencies, 180)
var/turf/T = get_step(src, turned_adjacency)
if(!T.get_smooth_underlay_icon(underlay_appearance, src, turned_adjacency))
T = get_step(src, turn(adjacencies, 135))
if(!T.get_smooth_underlay_icon(underlay_appearance, src, turned_adjacency))
T = get_step(src, turn(adjacencies, 225))
//if all else fails, ask our own turf
if(!T.get_smooth_underlay_icon(underlay_appearance, src, turned_adjacency) && !get_smooth_underlay_icon(underlay_appearance, src, turned_adjacency))
underlay_appearance.icon = DEFAULT_UNDERLAY_ICON
underlay_appearance.icon_state = DEFAULT_UNDERLAY_ICON_STATE
underlays = U
// Drop posters which were previously placed on this wall.
for(var/obj/structure/sign/poster/P in src)
P.roll_and_drop(src)
/proc/cardinal_smooth(atom/A, adjacencies)
//NW CORNER
var/nw = "1-i"
if((adjacencies & N_NORTH) && (adjacencies & N_WEST))
if(adjacencies & N_NORTHWEST)
nw = "1-f"
else
nw = "1-nw"
else
if(adjacencies & N_NORTH)
nw = "1-n"
else if(adjacencies & N_WEST)
nw = "1-w"
//NE CORNER
var/ne = "2-i"
if((adjacencies & N_NORTH) && (adjacencies & N_EAST))
if(adjacencies & N_NORTHEAST)
ne = "2-f"
else
ne = "2-ne"
else
if(adjacencies & N_NORTH)
ne = "2-n"
else if(adjacencies & N_EAST)
ne = "2-e"
//SW CORNER
var/sw = "3-i"
if((adjacencies & N_SOUTH) && (adjacencies & N_WEST))
if(adjacencies & N_SOUTHWEST)
sw = "3-f"
else
sw = "3-sw"
else
if(adjacencies & N_SOUTH)
sw = "3-s"
else if(adjacencies & N_WEST)
sw = "3-w"
//SE CORNER
var/se = "4-i"
if((adjacencies & N_SOUTH) && (adjacencies & N_EAST))
if(adjacencies & N_SOUTHEAST)
se = "4-f"
else
se = "4-se"
else
if(adjacencies & N_SOUTH)
se = "4-s"
else if(adjacencies & N_EAST)
se = "4-e"
var/list/New
if(A.top_left_corner != nw)
A.cut_overlay(A.top_left_corner)
A.top_left_corner = nw
LAZYADD(New, nw)
if(A.top_right_corner != ne)
A.cut_overlay(A.top_right_corner)
A.top_right_corner = ne
LAZYADD(New, ne)
if(A.bottom_right_corner != sw)
A.cut_overlay(A.bottom_right_corner)
A.bottom_right_corner = sw
LAZYADD(New, sw)
if(A.bottom_left_corner != se)
A.cut_overlay(A.bottom_left_corner)
A.bottom_left_corner = se
LAZYADD(New, se)
if(New)
A.add_overlay(New)
/proc/find_type_in_direction(atom/source, direction)
var/turf/target_turf = get_step(source, direction)
if(!target_turf)
return NULLTURF_BORDER
var/area/target_area = get_area(target_turf)
var/area/source_area = get_area(source)
if(source_area.canSmoothWithAreas && !is_type_in_typecache(target_area, source_area.canSmoothWithAreas))
return null
if(target_area.canSmoothWithAreas && !is_type_in_typecache(source_area, target_area.canSmoothWithAreas))
return null
if(source.canSmoothWith)
var/atom/A
if(source.smooth & SMOOTH_MORE)
for(var/a_type in source.canSmoothWith)
if( istype(target_turf, a_type) )
return target_turf
A = locate(a_type) in target_turf
if(A)
return A
return null
for(var/a_type in source.canSmoothWith)
if(a_type == target_turf.type)
return target_turf
A = locate(a_type) in target_turf
if(A && A.type == a_type)
return A
return null
else
if(isturf(source))
return source.type == target_turf.type ? target_turf : null
var/atom/A = locate(source.type) in target_turf
return A && A.type == source.type ? A : null
//Icon smoothing helpers
/proc/smooth_zlevel(var/zlevel, now = FALSE)
var/list/away_turfs = block(locate(1, 1, zlevel), locate(world.maxx, world.maxy, zlevel))
for(var/V in away_turfs)
var/turf/T = V
if(T.smooth)
if(now)
smooth_icon(T)
else
queue_smooth(T)
for(var/R in T)
var/atom/A = R
if(A.smooth)
if(now)
smooth_icon(A)
else
queue_smooth(A)
/atom/proc/clear_smooth_overlays()
cut_overlay(top_left_corner)
top_left_corner = null
cut_overlay(top_right_corner)
top_right_corner = null
cut_overlay(bottom_right_corner)
bottom_right_corner = null
cut_overlay(bottom_left_corner)
bottom_left_corner = null
/atom/proc/replace_smooth_overlays(nw, ne, sw, se)
clear_smooth_overlays()
var/list/O = list()
top_left_corner = nw
O += nw
top_right_corner = ne
O += ne
bottom_left_corner = sw
O += sw
bottom_right_corner = se
O += se
add_overlay(O)
/proc/reverse_ndir(ndir)
switch(ndir)
if(N_NORTH)
return NORTH
if(N_SOUTH)
return SOUTH
if(N_WEST)
return WEST
if(N_EAST)
return EAST
if(N_NORTHWEST)
return NORTHWEST
if(N_NORTHEAST)
return NORTHEAST
if(N_SOUTHEAST)
return SOUTHEAST
if(N_SOUTHWEST)
return SOUTHWEST
if(N_NORTH|N_WEST)
return NORTHWEST
if(N_NORTH|N_EAST)
return NORTHEAST
if(N_SOUTH|N_WEST)
return SOUTHWEST
if(N_SOUTH|N_EAST)
return SOUTHEAST
if(N_NORTH|N_WEST|N_NORTHWEST)
return NORTHWEST
if(N_NORTH|N_EAST|N_NORTHEAST)
return NORTHEAST
if(N_SOUTH|N_WEST|N_SOUTHWEST)
return SOUTHWEST
if(N_SOUTH|N_EAST|N_SOUTHEAST)
return SOUTHEAST
else
return 0
//SSicon_smooth
/proc/queue_smooth_neighbors(atom/A)
for(var/V in orange(1,A))
var/atom/T = V
if(T.smooth)
queue_smooth(T)
//SSicon_smooth
/proc/queue_smooth(atom/A)
if(!A.smooth || A.smooth & SMOOTH_QUEUED)
return
SSicon_smooth.smooth_queue += A
SSicon_smooth.can_fire = 1
A.smooth |= SMOOTH_QUEUED
//Example smooth wall
/turf/closed/wall/smooth
name = "smooth wall"
icon = 'icons/turf/smooth_wall.dmi'
icon_state = "smooth"
smooth = SMOOTH_TRUE|SMOOTH_DIAGONAL|SMOOTH_BORDER
canSmoothWith = null