mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-23 05:00:55 +01:00
[MIRROR] Field of View and Blindness improvements [bounty + upstream push] [MDB IGNORE] (#10060)
* Field of View and Blindness improvements [bounty + upstream push] * Update death.dm * almost done * Update fov_handler.dm * Face mouse when in combat mode, fix * Fixes the category for the fov admin verb. #63401 * Fixes objects with bad planes and FoV bugs #63412 * pain * there we go * face pref Co-authored-by: Azarak <azarak10@gmail.com>
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
/// An element to add a FOV trait to the wearer, removing it when an item is unequipped, but only as long as the visor is up.
|
||||
/datum/component/clothing_fov_visor
|
||||
/// What's the FOV angle of the trait we're applying to the wearer
|
||||
var/fov_angle
|
||||
/// Keeping track of the visor of our clothing.
|
||||
var/visor_up = FALSE
|
||||
/// Because of clothing code not being too good, we need keep track whether we are worn.
|
||||
var/is_worn = FALSE
|
||||
|
||||
/datum/component/clothing_fov_visor/Initialize(fov_angle)
|
||||
. = ..()
|
||||
if(!isclothing(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
var/obj/item/clothing/clothing_parent = parent
|
||||
src.fov_angle = fov_angle
|
||||
src.visor_up = clothing_parent.up //Initial values could vary, so we need to get it.
|
||||
|
||||
/datum/component/clothing_fov_visor/RegisterWithParent()
|
||||
RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, .proc/on_equip)
|
||||
RegisterSignal(parent, COMSIG_ITEM_DROPPED, .proc/on_drop)
|
||||
RegisterSignal(parent, COMSIG_CLOTHING_VISOR_TOGGLE, .proc/on_visor_toggle)
|
||||
|
||||
/datum/component/clothing_fov_visor/UnregisterFromParent()
|
||||
UnregisterSignal(parent, list(COMSIG_ITEM_EQUIPPED, COMSIG_ITEM_DROPPED, COMSIG_CLOTHING_VISOR_TOGGLE))
|
||||
return ..()
|
||||
|
||||
/// On dropping the item, remove the FoV trait if visor was down.
|
||||
/datum/component/clothing_fov_visor/proc/on_drop(datum/source, mob/living/dropper)
|
||||
SIGNAL_HANDLER
|
||||
is_worn = FALSE
|
||||
if(visor_up)
|
||||
return
|
||||
dropper.remove_fov_trait(source.type, fov_angle)
|
||||
dropper.update_fov()
|
||||
|
||||
/// On equipping the item, add the FoV trait if visor isn't up.
|
||||
/datum/component/clothing_fov_visor/proc/on_equip(obj/item/source, mob/living/equipper, slot)
|
||||
SIGNAL_HANDLER
|
||||
if(!(source.slot_flags & slot)) //If EQUIPPED TO HANDS FOR EXAMPLE
|
||||
return
|
||||
is_worn = TRUE
|
||||
if(visor_up)
|
||||
return
|
||||
equipper.add_fov_trait(source.type, fov_angle)
|
||||
equipper.update_fov()
|
||||
|
||||
/// On toggling the visor, we may want to add or remove FOV trait from the wearer.
|
||||
/datum/component/clothing_fov_visor/proc/on_visor_toggle(datum/source, visor_state)
|
||||
SIGNAL_HANDLER
|
||||
visor_up = visor_state
|
||||
if(!is_worn)
|
||||
return
|
||||
var/obj/item/clothing/clothing_parent = parent
|
||||
var/mob/living/wearer = clothing_parent.loc //This has to be the case due to equip/dropped keeping track.
|
||||
if(visor_up)
|
||||
wearer.remove_fov_trait(source.type, fov_angle)
|
||||
wearer.update_fov()
|
||||
else
|
||||
wearer.add_fov_trait(source.type, fov_angle)
|
||||
wearer.update_fov()
|
||||
@@ -0,0 +1,142 @@
|
||||
/// Component which handles Field of View masking for clients. FoV attributes are at /mob/living
|
||||
/datum/component/fov_handler
|
||||
/// Currently applied x size of the fov masks
|
||||
var/current_fov_x = BASE_FOV_MASK_X_DIMENSION
|
||||
/// Currently applied y size of the fov masks
|
||||
var/current_fov_y = BASE_FOV_MASK_Y_DIMENSION
|
||||
/// Whether we are applying the masks now
|
||||
var/applied_mask = FALSE
|
||||
/// The angle of the mask we are applying
|
||||
var/fov_angle = FOV_180_DEGREES
|
||||
/// The blocker mask applied to a client's screen
|
||||
var/atom/movable/screen/fov_blocker/blocker_mask
|
||||
/// The shadow mask applied to a client's screen
|
||||
var/atom/movable/screen/fov_shadow/visual_shadow
|
||||
|
||||
/datum/component/fov_handler/Initialize(fov_type = FOV_180_DEGREES)
|
||||
if(!isliving(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
var/mob/living/mob_parent = parent
|
||||
var/client/parent_client = mob_parent.client
|
||||
if(!parent_client) //Love client volatility!!
|
||||
qdel(src) //no QDEL hint for components, and we dont want this to print a warning regarding bad component application
|
||||
return
|
||||
|
||||
blocker_mask = new
|
||||
visual_shadow = new
|
||||
//visual_shadow.alpha = parent_client?.prefs.read_preference(/datum/preference/numeric/fov_darkness) //SKYRAT EDIT REMOVAL
|
||||
update_visual_shadow_alpha() //SKYRAT EDIT ADDITION
|
||||
set_fov_angle(fov_type)
|
||||
on_dir_change(mob_parent, mob_parent.dir, mob_parent.dir)
|
||||
update_fov_size()
|
||||
update_mask()
|
||||
|
||||
/datum/component/fov_handler/Destroy()
|
||||
if(applied_mask)
|
||||
remove_mask()
|
||||
if(blocker_mask) // In a case of early deletion due to volatile client
|
||||
QDEL_NULL(blocker_mask)
|
||||
if(visual_shadow) // In a case of early deletion due to volatile client
|
||||
QDEL_NULL(visual_shadow)
|
||||
return ..()
|
||||
|
||||
/datum/component/fov_handler/proc/set_fov_angle(new_angle)
|
||||
fov_angle = new_angle
|
||||
blocker_mask.icon_state = "[fov_angle]"
|
||||
visual_shadow.icon_state = "[fov_angle]_v"
|
||||
|
||||
/// Updates the size of the FOV masks by comparing them to client view size.
|
||||
/datum/component/fov_handler/proc/update_fov_size()
|
||||
SIGNAL_HANDLER
|
||||
var/mob/parent_mob = parent
|
||||
var/client/parent_client = parent_mob.client
|
||||
if(!parent_client) //Love client volatility!!
|
||||
return
|
||||
var/list/view_size = getviewsize(parent_client.view)
|
||||
if(view_size[1] == current_fov_x && view_size[2] == current_fov_y)
|
||||
return
|
||||
current_fov_x = BASE_FOV_MASK_X_DIMENSION
|
||||
current_fov_y = BASE_FOV_MASK_Y_DIMENSION
|
||||
var/matrix/new_matrix = new
|
||||
var/x_shift = view_size[1] - current_fov_x
|
||||
var/y_shift = view_size[2] - current_fov_y
|
||||
var/x_scale = view_size[1] / current_fov_x
|
||||
var/y_scale = view_size[2] / current_fov_y
|
||||
current_fov_x = view_size[1]
|
||||
current_fov_y = view_size[2]
|
||||
visual_shadow.transform = blocker_mask.transform = new_matrix.Scale(x_scale, y_scale)
|
||||
visual_shadow.transform = blocker_mask.transform = new_matrix.Translate(x_shift * 16, y_shift * 16)
|
||||
|
||||
/// Updates the mask application to client by checking `stat` and `eye`
|
||||
/datum/component/fov_handler/proc/update_mask()
|
||||
SIGNAL_HANDLER
|
||||
var/mob/parent_mob = parent
|
||||
var/client/parent_client = parent_mob.client
|
||||
if(!parent_client) //Love client volatility!!
|
||||
return
|
||||
var/user_living = parent_mob != DEAD
|
||||
var/atom/top_most_atom = get_atom_on_turf(parent_mob)
|
||||
var/user_extends_eye = parent_client.eye != top_most_atom
|
||||
var/should_apply_mask = user_living && !user_extends_eye
|
||||
|
||||
if(should_apply_mask == applied_mask)
|
||||
return
|
||||
|
||||
if(should_apply_mask)
|
||||
add_mask()
|
||||
else
|
||||
remove_mask()
|
||||
|
||||
/datum/component/fov_handler/proc/remove_mask()
|
||||
var/mob/parent_mob = parent
|
||||
var/client/parent_client = parent_mob.client
|
||||
if(!parent_client) //Love client volatility!!
|
||||
return
|
||||
applied_mask = FALSE
|
||||
parent_client.screen -= blocker_mask
|
||||
parent_client.screen -= visual_shadow
|
||||
|
||||
/datum/component/fov_handler/proc/add_mask()
|
||||
var/mob/parent_mob = parent
|
||||
var/client/parent_client = parent_mob.client
|
||||
if(!parent_client) //Love client volatility!!
|
||||
return
|
||||
applied_mask = TRUE
|
||||
parent_client.screen += blocker_mask
|
||||
parent_client.screen += visual_shadow
|
||||
|
||||
/// When a direction of the user changes, so do the masks
|
||||
/datum/component/fov_handler/proc/on_dir_change(mob/source, old_dir, new_dir)
|
||||
SIGNAL_HANDLER
|
||||
blocker_mask.dir = new_dir
|
||||
visual_shadow.dir = new_dir
|
||||
|
||||
/// When a mob logs out, delete the component
|
||||
/datum/component/fov_handler/proc/mob_logout(mob/source)
|
||||
SIGNAL_HANDLER
|
||||
qdel(src)
|
||||
|
||||
/datum/component/fov_handler/RegisterWithParent()
|
||||
. = ..()
|
||||
RegisterSignal(parent, COMSIG_ATOM_DIR_CHANGE, .proc/on_dir_change)
|
||||
RegisterSignal(parent, COMSIG_LIVING_DEATH, .proc/update_mask)
|
||||
RegisterSignal(parent, COMSIG_LIVING_REVIVE, .proc/update_mask)
|
||||
RegisterSignal(parent, COMSIG_MOB_CLIENT_CHANGE_VIEW, .proc/update_fov_size)
|
||||
RegisterSignal(parent, COMSIG_MOB_RESET_PERSPECTIVE, .proc/update_mask)
|
||||
RegisterSignal(parent, COMSIG_MOB_LOGOUT, .proc/mob_logout)
|
||||
RegisterSignal(parent, COMSIG_LIVING_COMBAT_MODE_TOGGLE, .proc/update_visual_shadow_alpha) //SKYRAT EDIT ADDITION
|
||||
|
||||
/datum/component/fov_handler/UnregisterFromParent()
|
||||
. = ..()
|
||||
UnregisterSignal(parent, list(COMSIG_MOB_RESET_PERSPECTIVE, COMSIG_ATOM_DIR_CHANGE, COMSIG_LIVING_DEATH, COMSIG_LIVING_REVIVE, COMSIG_MOB_LOGOUT))
|
||||
UnregisterSignal(parent, COMSIG_LIVING_COMBAT_MODE_TOGGLE) //SKYRAT EDIT ADDITION
|
||||
|
||||
//SKYRAT EDIT ADDITION BEGIN
|
||||
/// When toggling combat mode, we update the alpha of the shadow mask
|
||||
/datum/component/fov_handler/proc/update_visual_shadow_alpha()
|
||||
SIGNAL_HANDLER
|
||||
var/mob/living/parent_mob = parent
|
||||
var/pref_to_read = parent_mob.combat_mode ? /datum/preference/numeric/fov_darkness : /datum/preference/numeric/out_of_combat_fov_darkness
|
||||
var/target_alpha = parent_mob.client.prefs.read_preference(pref_to_read)
|
||||
visual_shadow.alpha = target_alpha
|
||||
//SKYRAT EDIT ADDITION END
|
||||
Reference in New Issue
Block a user