Flags and adjacency work (#20259)

Added a bunch of flags for passflags on things that were previously
missing them.
Removed snowflake passthrow var, it's a passflag now.
Updated ClickCross and Adjacency code.
It's now possible to interact with things that are adjacent but
otherwise have a machine (or other appropriate items) blocking them, eg.
think of an APC on the wall with a machine in front of it.
This commit is contained in:
Fluffy
2024-12-24 16:05:30 +00:00
committed by GitHub
parent 67360a9bea
commit 727eb2d261
21 changed files with 147 additions and 94 deletions
+57 -67
View File
@@ -10,11 +10,11 @@
Note that in all cases the neighbor is handled simply; this is usually the user's mob, in which case it is up to you
to check that the mob is not inside of something
*/
/atom/proc/Adjacent(var/atom/neighbor) // basic inheritance, unused
return 0
/atom/proc/Adjacent(atom/neighbor, atom/target, atom/movable/mover) // basic inheritance, unused
return
// Not a sane use of the function and (for now) indicative of an error elsewhere
/area/Adjacent(var/atom/neighbor)
/area/Adjacent(atom/neighbor, atom/target, atom/movable/mover)
CRASH("Call to /area/Adjacent(), unimplemented proc")
@@ -25,37 +25,41 @@
* If you are diagonally adjacent, ensure you can pass through at least one of the mutually adjacent square.
* Passing through in this case ignores anything with the throwpass flag, such as tables, racks, and morgue trays.
*/
/turf/Adjacent(var/atom/neighbor, var/atom/target = null)
/turf/Adjacent(atom/neighbor, atom/target, atom/movable/mover)
var/turf/T0 = get_turf(neighbor)
if(T0 == src)
return 1
if(!T0 || T0.z != z)
return 0
if(get_dist(src,T0) > 1)
return 0
if(T0 == src) //same turf
return TRUE
if(get_dist(src, T0) > 1 || z != T0.z) //too far
return FALSE
// Non diagonal case
if(T0.x == x || T0.y == y)
// Check for border blockages
return T0.ClickCross(get_dir(T0,src), border_only = 1) && src.ClickCross(get_dir(src,T0), border_only = 1, target_atom = target)
return T0.ClickCross(get_dir(T0, src), TRUE, target, mover) && ClickCross(get_dir(src, T0), TRUE, target, mover)
// Not orthagonal
var/in_dir = get_dir(neighbor,src) // eg. northwest (1+8)
var/d1 = in_dir&(in_dir-1) // eg west (1+8)&(8) = 8
var/d2 = in_dir - d1 // eg north (1+8) - 8 = 1
// Diagonal case
var/in_dir = get_dir(T0,src) // eg. northwest (1+8) = 9 (00001001)
var/d1 = in_dir&3 // eg. north (1+8)&3 (0000 0011) = 1 (0000 0001)
var/d2 = in_dir&12 // eg. west (1+8)&12 (0000 1100) = 8 (0000 1000)
for(var/d in list(d1,d2))
if(!T0.ClickCross(d, border_only = 1))
if(!T0.ClickCross(d, TRUE, target, mover))
continue // could not leave T0 in that direction
var/turf/T1 = get_step(T0,d)
if(!T1 || T1.density || !T1.ClickCross(get_dir(T1,T0) | get_dir(T1,src), border_only = 0))
if(!T1 || T1.density)
continue
if(!T1.ClickCross(get_dir(T1, src), FALSE, target, mover) || !T1.ClickCross(get_dir(T1, T0), FALSE, target, mover))
continue // couldn't enter or couldn't leave T1
if(!src.ClickCross(get_dir(src,T1), border_only = 1, target_atom = target))
if(!ClickCross(get_dir(src, T1), TRUE, target, mover))
continue // could not enter src
return 1 // we don't care about our own density
return 0
return TRUE // we don't care about our own density
return FALSE
/*
Quick adjacency (to turf):
@@ -75,73 +79,59 @@ Quick adjacency (to turf):
/*
Adjacency (to anything else):
* Must be on a turf
* In the case of a multiple-tile object, all valid locations are checked for adjacency.
Note: Multiple-tile objects are created when the bound_width and bound_height are creater than the tile size.
This is not used in stock /tg/station currently.
*/
/atom/movable/Adjacent(var/atom/neighbor)
if(neighbor == loc) return 1
if(!isturf(loc)) return 0
for(var/turf/T in locs)
if(isnull(T)) continue
if(T.Adjacent(neighbor,src)) return 1
return 0
/atom/movable/Adjacent(atom/neighbor, atom/target, atom/movable/mover)
if(neighbor == loc)
return TRUE
if(neighbor?.loc == src)
return TRUE
var/turf/T = loc
if(!istype(T))
return FALSE
if(T.Adjacent(neighbor,target = neighbor, mover = src))
return TRUE
return FALSE
// This is necessary for storage items not on your person.
/obj/item/Adjacent(var/atom/neighbor, var/recurse = 1)
if(neighbor == loc) return 1
if(istype(loc,/obj/item))
/obj/item/Adjacent(atom/neighbor, atom/target, atom/movable/mover, recurse = 1)
if(neighbor == loc)
return TRUE
if(neighbor?.loc == src)
return TRUE
if(isitem(loc))
if(recurse > 0)
return loc.Adjacent(neighbor,recurse - 1)
return 0
return loc.Adjacent(neighbor, target, mover, recurse - 1)
return FALSE
return ..()
/*
Special case: This allows you to reach a door when it is visally on top of,
but technically behind, a fire door
You could try to rewrite this to be faster, but I'm not sure anything would be.
This can be safely removed if border firedoors are ever moved to be on top of doors
so they can be interacted with without opening the door.
*/
/*/obj/machinery/door/Adjacent(var/atom/neighbor)
var/obj/machinery/door/firedoor/border_only/BOD = locate() in loc
if(BOD)
BOD.throwpass = 1 // allow click to pass
. = ..()
BOD.throwpass = 0
return .
return ..()*/
/*
This checks if you there is uninterrupted airspace between that turf and this one.
This is defined as any dense ATOM_FLAG_CHECKS_BORDER object, or any dense object without throwpass.
The border_only flag allows you to not objects (for source and destination squares)
*/
/turf/proc/ClickCross(var/target_dir, var/border_only, var/target_atom = null)
/turf/proc/ClickCross(target_dir, border_only, target, atom/movable/mover)
for(var/obj/O in src)
if(!O.density || O == target_atom || O.throwpass)
continue // throwpass is used for anything you can click through
if((mover && O.CanPass(mover, target_dir)) || (!mover && !O.density))
continue
//If there's a dense object on the turf, only allow the click to pass if you can throw items over it or it has a special flag.
if(O == target || O == mover || (O.pass_flags_self & (LETPASSTHROW|LETPASSCLICKS)))
continue
if(O.atom_flags & ATOM_FLAG_CHECKS_BORDER) // windows have throwpass but are on border, check them first
if(O.dir & target_dir || O.dir & (O.dir - 1)) // full tile windows are just diagonals mechanically
if(istype(target_atom, /obj/structure/window))
var/obj/structure/window/W = target_atom
/*** START AURORA SNOWFLAKE CODE ***/
if(istype(target, /obj/structure/window))
var/obj/structure/window/W = target
if(!W.is_fulltile()) //exception for breaking full tile windows on top of single pane windows
return FALSE
if(O.atom_flags & ATOM_FLAG_ALWAYS_ALLOW_PICKUP)
return TRUE
return FALSE
/*** END AURORA SNOWFLAKE CODE ***/
else if(!border_only) // dense, not on border, cannot pass over
return FALSE
return TRUE
/*
Aside: throwpass does not do what I thought it did originally, and is only used for checking whether or not
a thrown object should stop after already successfully entering a square. Currently the throw code involved
only seems to affect hitting mobs, because the checks performed against objects are already performed when
entering or leaving the square. Since throwpass isn't used on mobs, but only on objects, it is effectively
useless. Throwpass may later need to be removed and replaced with a passcheck (bitfield on movable atom passflags).
Since I don't want to complicate the click code rework by messing with unrelated systems it won't be changed here.
*/
return TRUE
-1
View File
@@ -38,7 +38,6 @@
var/blood_color
var/last_bumped = 0
var/pass_flags = 0
var/throwpass = 0
var/germ_level = GERM_LEVEL_AMBIENT // The higher the germ level, the more germ on the atom.
var/simulated = 1 // Filter for actions. Used by lighting overlays.
var/fluorescent // Shows up under a UV light.
+1 -1
View File
@@ -249,7 +249,7 @@
continue
throw_impact(A, speed)
if(isobj(A))
if(A.density && !A.throwpass && !A.CanPass(src, target))
if(A.density && !A.CanPass(src, target))
src.throw_impact(A,speed)
// Prevents robots dropping their modules
@@ -86,7 +86,7 @@
src.close(M)
return 1
/obj/item/storage/internal/Adjacent(var/atom/neighbor)
/obj/item/storage/internal/Adjacent(atom/neighbor, atom/target, atom/movable/mover)
var/obj/item/real_master_item = special_master_item_handling ? get_master_item() : master_item
return real_master_item.Adjacent(neighbor)
+1
View File
@@ -3,6 +3,7 @@
w_class = WEIGHT_CLASS_GIGANTIC
layer = STRUCTURE_LAYER
blocks_emissive = EMISSIVE_BLOCK_GENERIC
pass_flags_self = PASSSTRUCTURE
var/material_alteration = MATERIAL_ALTERATION_ALL // Overrides for material shit. Set them manually if you don't want colors etc. See wood chairs/office chairs.
var/climbable
@@ -3,7 +3,6 @@
climbable = TRUE
anchored = TRUE
density = TRUE
throwpass = TRUE //You can throw objects over this, despite its density.
atom_flags = ATOM_FLAG_CHECKS_BORDER
var/stack_type //The type of stack the barricade dropped when disassembled if any.
@@ -6,7 +6,7 @@
density = TRUE
build_amt = 2
slowdown = 5
pass_flags_self = PASSTRACE
pass_flags_self = PASSSTRUCTURE | LETPASSCLICKS | PASSTRACE
var/icon_door = null
/// Override to have open overlay use icon different to its base's
+1
View File
@@ -8,6 +8,7 @@
icon_state = "grille"
density = TRUE
anchored = TRUE
pass_flags_self = PASSGRILLE
obj_flags = OBJ_FLAG_CONDUCTABLE | OBJ_FLAG_MOVES_UNSUPPORTED
explosion_resistance = 1
layer = BELOW_WINDOW_LAYER
+1 -1
View File
@@ -143,7 +143,7 @@
icon_state = "morguet"
density = TRUE
anchored = TRUE
throwpass = TRUE
pass_flags_self = PASSSTRUCTURE | LETPASSTHROW
layer = BELOW_OBJ_LAYER
obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED
var/obj/structure/morgue/connected = null
+3 -2
View File
@@ -3,8 +3,9 @@
desc = "Completely impassable - or are they?"
icon = 'icons/obj/structure/plasticflaps.dmi'
icon_state = "plasticflaps_preview"
density = 0
anchored = 1
density = FALSE
anchored = TRUE
pass_flags_self = PASSSTRUCTURE | PASSFLAPS
layer = UNDERDOOR
explosion_resistance = 5
build_amt = 4
-1
View File
@@ -4,7 +4,6 @@
icon = 'icons/obj/structure/blocker/railing_basic.dmi'
icon_state = "railing0-1"
density = TRUE
throwpass = TRUE
climbable = TRUE
layer = OBJ_LAYER
anchored = FALSE
+4 -4
View File
@@ -431,9 +431,9 @@ ABSTRACT_TYPE(/obj/structure/stairs/urban/road_ramp)
icon = 'icons/obj/structure/urban/blockers.dmi'
icon_state = "rod_railing"
density = TRUE
throwpass = TRUE
climbable = TRUE
anchored = TRUE
pass_flags_self = PASSSTRUCTURE | LETPASSTHROW
climbable = TRUE
/obj/structure/rod_railing/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
if(mover?.movement_type & PHASING)
@@ -463,8 +463,8 @@ ABSTRACT_TYPE(/obj/structure/stairs/urban/road_ramp)
icon = 'icons/obj/structure/urban/blockers.dmi'
icon_state = "dam1"
density = TRUE
throwpass = TRUE
anchored = TRUE
pass_flags_self = PASSSTRUCTURE | LETPASSTHROW
/obj/structure/road_barrier
name = "roadway barrier"
@@ -472,7 +472,7 @@ ABSTRACT_TYPE(/obj/structure/stairs/urban/road_ramp)
icon = 'icons/obj/structure/urban/road_edges.dmi'
icon_state = "guard"
density = TRUE
throwpass = TRUE
pass_flags_self = PASSSTRUCTURE | LETPASSTHROW
climbable = TRUE
anchored = TRUE
+1
View File
@@ -11,6 +11,7 @@
icon_state = "window"
alpha = 196
density = TRUE
pass_flags_self = PASSWINDOW
w_class = WEIGHT_CLASS_NORMAL
layer = SIDE_WINDOW_LAYER
anchored = TRUE
+1
View File
@@ -8,6 +8,7 @@
opacity = TRUE
density = TRUE
blocks_air = TRUE
pass_flags_self = PASSCLOSEDTURF
thermal_conductivity = WALL_HEAT_TRANSFER_COEFFICIENT
heat_capacity = 312500 //a little over 5 cm thick , 312500 for 1 m by 2.5 m by 0.25 m plasteel wall
canSmoothWith = list(
+1
View File
@@ -5,6 +5,7 @@
opacity = TRUE
density = TRUE
blocks_air = TRUE
pass_flags_self = PASSCLOSEDTURF
/turf/unsimulated/wall/fakeglass
name = "window"
@@ -1,10 +1,10 @@
/obj/structure/dueling_table
name = "dueling table"
icon = 'icons/obj/battle_monsters/furniture.dmi'
anchored = 1
density = 1
anchored = TRUE
density = TRUE
climbable = TRUE
throwpass = 1
pass_flags_self = PASSSTRUCTURE | LETPASSTHROW
/obj/structure/dueling_table/no_collide
density = 0
+3 -3
View File
@@ -331,9 +331,9 @@
desc = "Boom, Shakalaka!"
icon = 'icons/obj/basketball.dmi'
icon_state = "hoop"
anchored = 1
density = 1
throwpass = 1
anchored = TRUE
density = TRUE
pass_flags_self = PASSSTRUCTURE | LETPASSTHROW
/obj/structure/holohoop/attackby(obj/item/attacking_item, mob/user)
if (istype(attacking_item, /obj/item/grab) && get_dist(src,user)<2)
+3 -4
View File
@@ -3,10 +3,9 @@
icon = 'icons/obj/makeshift_workstation.dmi'
icon_state = "workstation"
desc = "It's a makeshift workstation for grinding, chopping, and heating."
density = 1
anchored = 1
throwpass = 1
density = TRUE
anchored = TRUE
pass_flags_self = PASSSTRUCTURE | LETPASSTHROW
var/obj/item/device/analyzer/analyzer
var/transfer_out = 0
+1
View File
@@ -5,6 +5,7 @@
movable_flags = MOVABLE_FLAG_PROXMOVE
sight = DEFAULT_SIGHT
blocks_emissive = EMISSIVE_BLOCK_GENERIC
pass_flags_self = PASSMOB
var/datum/mind/mind
var/static/next_mob_id = 0
+3 -4
View File
@@ -3,14 +3,13 @@
icon = 'icons/obj/structure/tables/table.dmi'
icon_state = "frame"
desc = "It's a table, for putting things on. Or standing on, if you really want to."
density = 1
anchored = 1
density = TRUE
anchored = TRUE
pass_flags_self = PASSTABLE | LETPASSTHROW
climbable = TRUE
layer = TABLE_LAYER
throwpass = 1
breakable = TRUE
build_amt = 1
pass_flags_self = PASSTABLE | LETPASSTHROW
//Preset shit
var/table_mat
@@ -0,0 +1,61 @@
################################
# Example Changelog File
#
# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
#
# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
# When it is, any changes listed below will disappear.
#
# Valid Prefixes:
# bugfix
# - (fixes bugs)
# wip
# - (work in progress)
# qol
# - (quality of life)
# soundadd
# - (adds a sound)
# sounddel
# - (removes a sound)
# rscadd
# - (adds a feature)
# rscdel
# - (removes a feature)
# imageadd
# - (adds an image or sprite)
# imagedel
# - (removes an image or sprite)
# spellcheck
# - (fixes spelling or grammar)
# experiment
# - (experimental change)
# balance
# - (balance changes)
# code_imp
# - (misc internal code change)
# refactor
# - (refactors code)
# config
# - (makes a change to the config files)
# admin
# - (makes changes to administrator tools)
# server
# - (miscellaneous changes to server)
#################################
# Your name.
author: FluffyGhost
# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
delete-after: True
# Any changes you've made. See valid prefix list above.
# INDENT WITH TWO SPACES. NOT TABS. SPACES.
# SCREW THIS UP AND IT WON'T WORK.
# Also, this gets changed to [] after reading. Just remove the brackets when you add new shit.
# Please surround your changes in double quotes ("). It works without them, but if you use certain characters it screws up compiling. The quotes will not show up in the changelog.
changes:
- code_imp: "Added a bunch of flags for passflags on things that were previously missing them."
- refactor: "Removed snowflake passthrow var, it's a passflag now."
- refactor: "Updated ClickCross and Adjacency code."
- rscadd: "It's now possible to interact with things that are adjacent but otherwise have a machine (or other appropriate items) blocking them, eg. think of an APC on the wall with a machine in front of it."