mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-10 02:09:41 +00:00
Co-authored-by: Cameron Lennox <killer65311@gmail.com> Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com>
141 lines
5.0 KiB
Plaintext
141 lines
5.0 KiB
Plaintext
///Component that updates the icon_state of an item when something approaches.
|
|
///NOTE: This uses the initial icon of the object, meaning it will not work properly with items that change their icon_state for other reasons.
|
|
/datum/component/reactive_icon_update
|
|
dupe_mode = COMPONENT_DUPE_UNIQUE
|
|
///What we want to append to our icon_state when our conditions are filled
|
|
var/icon_prefix
|
|
///List of which directions we want to be valid. Can be NORTH/SOUTH/EAST/WEST along with NORTHEAST/SOUTHEAST/SOUTHWEST/NORTHWEST
|
|
var/list/directions
|
|
///Range that we want it to look out for.
|
|
var/range
|
|
///What type of mobs trigger the icon change.
|
|
var/list/triggering_mobs = list(/mob/living)
|
|
|
|
/datum/component/reactive_icon_update/Initialize(icon_prefix, list/directions, range, triggering_mobs)
|
|
if(!isobj(parent) || !isnum(range) || (!directions || !LAZYLEN(directions)) || (triggering_mobs && !LAZYLEN(triggering_mobs)))
|
|
return COMPONENT_INCOMPATIBLE
|
|
|
|
src.icon_prefix = icon_prefix
|
|
src.directions = directions
|
|
src.range = range
|
|
if(triggering_mobs)
|
|
src.triggering_mobs = triggering_mobs
|
|
|
|
var/static/list/connections = list(
|
|
COMSIG_ATOM_ENTERED = PROC_REF(update_proximity_icon),
|
|
)
|
|
AddComponent(/datum/component/connect_range, parent, connections, range)
|
|
|
|
/datum/component/reactive_icon_update/UnregisterFromParent()
|
|
|
|
directions.Cut()
|
|
triggering_mobs.Cut()
|
|
|
|
/datum/component/reactive_icon_update/proc/update_proximity_icon(atom/current_loc, atom/movable/AM, atom/old_loc)
|
|
SIGNAL_HANDLER
|
|
SHOULD_NOT_OVERRIDE(TRUE)
|
|
var/obj/our_item = parent
|
|
if(!ismob(AM) || !mob_check(AM))
|
|
return
|
|
var/mob/M = AM
|
|
if(M == our_item.loc) //Ignore the mob wearing us
|
|
return
|
|
|
|
///What direction the mob is relative to us.
|
|
var/mob_direction_x
|
|
var/mob_direction_y
|
|
var/actual_direction
|
|
|
|
///First, we get the X and Y coordinates
|
|
var/x
|
|
var/y
|
|
if(our_item.x && our_item.y)
|
|
x = our_item.x
|
|
y = our_item.y
|
|
if(our_item.x == 0 || our_item.y == 0) //We're inside of something! Clothing is a great example of this.
|
|
if(our_item.loc)
|
|
x = our_item.loc.x
|
|
y = our_item.loc.y
|
|
if(x == 0 || y == 0) //We're two layers deep, just give up.
|
|
return
|
|
if(M.x > x)
|
|
mob_direction_x = EAST
|
|
else if(M.x < x)
|
|
mob_direction_x = WEST
|
|
else
|
|
mob_direction_x = null //Same X as us
|
|
|
|
if(M.y > y)
|
|
mob_direction_y = NORTH
|
|
else if(M.y < y)
|
|
mob_direction_y = SOUTH
|
|
else
|
|
mob_direction_y = null //Same Y as us
|
|
|
|
///Then we combine them to get our actual direction, not just cardinals.
|
|
if(mob_direction_x == EAST && mob_direction_y == SOUTH) //Diagonals first
|
|
actual_direction = SOUTHEAST
|
|
else if(mob_direction_x == EAST && mob_direction_y == NORTH)
|
|
actual_direction = NORTHEAST
|
|
else if(mob_direction_x == WEST && mob_direction_y == SOUTH)
|
|
actual_direction = SOUTHWEST
|
|
else if(mob_direction_x == WEST && mob_direction_y == NORTH)
|
|
actual_direction = NORTHWEST
|
|
else if(mob_direction_x) //Only horizontal
|
|
actual_direction = mob_direction_x
|
|
else if(mob_direction_y) //Only vertical
|
|
actual_direction = mob_direction_y
|
|
else //Exactly ontop of us, so we don't care about direction.
|
|
return
|
|
|
|
///We then make sure the actual_direction is in our directions list.
|
|
if(actual_direction && !(actual_direction in directions)) //Not a valid direction. Convert to N/E/S/W
|
|
//East and west take priority because those are generally the most visually striking.
|
|
if((WEST in directions) && (actual_direction == (NORTHWEST || SOUTHWEST)))
|
|
actual_direction = WEST
|
|
else if((EAST in directions) && (actual_direction == (NORTHEAST || SOUTHEAST)))
|
|
actual_direction = EAST
|
|
else if((SOUTH in directions) && (actual_direction == (SOUTHWEST || SOUTHEAST)))
|
|
actual_direction = SOUTH
|
|
else if((NORTH in directions) && (actual_direction == (NORTHWEST || NORTHEAST)))
|
|
actual_direction = NORTH
|
|
else
|
|
return
|
|
var/directional_name
|
|
switch(actual_direction)
|
|
if(NORTH)
|
|
directional_name = "north"
|
|
if(EAST)
|
|
directional_name = "east"
|
|
if(SOUTH)
|
|
directional_name = "south"
|
|
if(WEST)
|
|
directional_name = "west"
|
|
if(NORTHEAST)
|
|
directional_name = "northeast"
|
|
if(SOUTHEAST)
|
|
directional_name = "southeast"
|
|
if(SOUTHWEST)
|
|
directional_name = "southwest"
|
|
if(NORTHWEST)
|
|
directional_name = "northwest"
|
|
//We then update our icon state. For example:
|
|
//We have an item that has the icon_state of "cloak" and the prefix of "_direction" and we're facing NORTH
|
|
//The icon_state will be changed to cloak_direction_north
|
|
our_item.icon_state = initial(our_item.icon_state) + icon_prefix + "_" + directional_name
|
|
|
|
//Example item for testing directions.
|
|
/obj/item/tool/screwdriver/test_driver
|
|
icon = 'icons/obj/directional_test.dmi'
|
|
|
|
/obj/item/tool/screwdriver/test_driver/Initialize(mapload)
|
|
..()
|
|
icon_state = "screwdriver"
|
|
AddComponent(/datum/component/reactive_icon_update, directions = list(NORTH, EAST, SOUTH, WEST, SOUTHWEST, SOUTHEAST, NORTHEAST, NORTHWEST), range = 3)
|
|
|
|
/datum/component/reactive_icon_update/proc/mob_check(mob/triggering_mob)
|
|
SHOULD_NOT_OVERRIDE(TRUE)
|
|
if(is_type_in_list(triggering_mob, triggering_mobs))
|
|
return TRUE
|
|
return FALSE
|