mirror of
https://github.com/Citadel-Station-13/Citadel-Station-13-RP.git
synced 2026-08-22 02:06:35 +01:00
169 lines
6.2 KiB
Plaintext
169 lines
6.2 KiB
Plaintext
//* This file is explicitly licensed under the MIT license. *//
|
|
//* Copyright (c) 2024 Citadel Station Developers *//
|
|
|
|
// todo: mob.generate_simulated_clickchain(...) to generate a simulated click
|
|
|
|
/**
|
|
* used to hold data about a click (melee/ranged/other) action
|
|
*
|
|
* * The click may be real or fake.
|
|
* * Clickchain flags are deliberately not stored in here; you're supposed to modify and return them a ton, so it's inefficient to put it in here.
|
|
* * This is required for item swings / interaction, usually, not just base /event_args/actor.
|
|
* While it's technically called a clickchain, it also stores a lot of other data like targeting.
|
|
* * **This should always be clone()'d if you are invoking, semantically, a new attack from an existing attack.**
|
|
* Otherwise, modifiers might apply twice and all kinds of fuckery can occur.
|
|
*
|
|
* todo: helpers for true clickchain event generation / simulation
|
|
*/
|
|
/datum/event_args/actor/clickchain
|
|
//* Using Data *//
|
|
|
|
/// (optional) action intent
|
|
var/using_intent
|
|
/// (optional) hand index
|
|
var/using_hand_index
|
|
|
|
/// (optional) using weapon
|
|
/// * not for tools; this is only for melee
|
|
var/obj/item/using_melee_weapon
|
|
/// (optional) using melee style
|
|
/// * not for tools; this is only for melee
|
|
var/datum/melee_attack/using_melee_attack
|
|
|
|
//* Click Data *//
|
|
|
|
/// optional: click params
|
|
var/list/click_params
|
|
/// did we unpack click params?
|
|
var/tmp/click_params_unpacked = FALSE
|
|
/// pixel x on tile clicked
|
|
var/tmp/click_params_tile_px
|
|
/// pixel y on tile clicked
|
|
var/tmp/click_params_tile_py
|
|
/// tile x from bottom left of screen, starting at 1
|
|
var/tmp/click_params_screen_tx
|
|
/// tile y from bottom left of screen, starting at 1
|
|
var/tmp/click_params_screen_ty
|
|
|
|
/// clickdelay base out
|
|
var/click_cooldown_base = 0
|
|
/// clickdelay multiplier out
|
|
/// * the proc that invoked the clickchain handling this event_args should
|
|
/// handle this. clickchain will not handle clickdelay itself!
|
|
var/click_cooldown_multiplier = 1
|
|
|
|
//* Target Data *//
|
|
|
|
/// optional: target atom
|
|
var/atom/target
|
|
/// optional: target zone
|
|
var/target_zone
|
|
|
|
//* Attack Data *//
|
|
|
|
/// Overall damage multiplier
|
|
///
|
|
/// * Allowed to be changed by shieldcalls and other intercepts
|
|
var/attack_melee_multiplier = 1
|
|
/// Overall impact multiplier
|
|
///
|
|
/// * Allowed to be changed by shieldcalls and other intercepts
|
|
/// * Unlike 'attack melee multiplier', this will block everything else too.
|
|
/// This is for shieldcalls to inject into to say 'hey, we blocked any contact, not just dampened damage'.
|
|
var/attack_contact_multiplier = 1
|
|
|
|
//* Resolved Data *//
|
|
|
|
/// Resolved angle from performer
|
|
/// * This is in degrees clockwise of north.
|
|
var/tmp/resolved_angle_from_performer
|
|
|
|
//* Out Data *//
|
|
|
|
/// total damage inflicted; set by target
|
|
var/out_damage_inflicted = 0
|
|
|
|
/datum/event_args/actor/clickchain/New(mob/performer, mob/initiator, atom/target, list/params, intent)
|
|
..()
|
|
// using //
|
|
src.using_intent = intent
|
|
// click //
|
|
src.click_params = params || list()
|
|
// target //
|
|
src.target = target
|
|
|
|
//! LEGACY AUTO FILL !//
|
|
if(isnull(src.using_intent))
|
|
src.using_intent = performer?.a_intent
|
|
if(isnull(src.target_zone))
|
|
src.target_zone = performer?.zone_sel?.selecting || BP_TORSO
|
|
//! END !//
|
|
|
|
/datum/event_args/actor/clickchain/clone()
|
|
var/datum/event_args/actor/clickchain/cloning = ..()
|
|
cloning.using_intent = using_intent
|
|
cloning.using_hand_index = using_hand_index
|
|
cloning.using_melee_attack = using_melee_attack
|
|
cloning.using_melee_weapon = using_melee_weapon
|
|
cloning.click_params = click_params
|
|
cloning.click_cooldown_base = click_cooldown_base
|
|
cloning.click_cooldown_multiplier = click_cooldown_multiplier
|
|
cloning.target = target
|
|
cloning.target_zone = target_zone
|
|
cloning.attack_melee_multiplier = attack_melee_multiplier
|
|
cloning.attack_contact_multiplier = attack_contact_multiplier
|
|
cloning.out_damage_inflicted = out_damage_inflicted
|
|
return cloning
|
|
|
|
/**
|
|
* Resolves the angle of the clicked pixel from a given entity.
|
|
*
|
|
* * This defaults to the clickchain's performer.
|
|
* * This means that this proc should correctly offset the effective angle if the entity is not the center of the
|
|
* initiator's screen!
|
|
* * Calling this with no arguments or with the clickchain's performer will also resolve the pixel x/y
|
|
* of the click
|
|
*
|
|
* @return degrees clockwise from north, or null if failed to resolve
|
|
*/
|
|
/datum/event_args/actor/clickchain/proc/resolve_click_angle(atom/from_entity = performer)
|
|
if((from_entity == performer) && !isnull(resolved_angle_from_performer))
|
|
return resolved_angle_from_performer
|
|
// todo: this relies on a client existing. this shouldn't be necessary for a true click simulation!
|
|
if(!initiator?.client)
|
|
return
|
|
if(!click_params)
|
|
return
|
|
unpack_click_params()
|
|
// target x/y from bottom left of screen
|
|
var/target_x = click_params_screen_tx * WORLD_ICON_SIZE + click_params_tile_px - WORLD_ICON_SIZE
|
|
var/target_y = click_params_screen_ty * WORLD_ICON_SIZE + click_params_tile_py - WORLD_ICON_SIZE
|
|
// origin x/y of the performing mob on the screen
|
|
// todo: this doesn't take into account if the performer isn't the eye of the initiator's client!
|
|
// that'll need to be added for remote control to work.
|
|
var/origin_x = (initiator.client.current_viewport_width * WORLD_ICON_SIZE * 0.5) - initiator.client.pixel_x
|
|
var/origin_y = (initiator.client.current_viewport_height * WORLD_ICON_SIZE * 0.5) - initiator.client.pixel_y
|
|
// atan args are reversed for clockwise from north instead of counterclockwise from east
|
|
. = arctan(target_y - origin_y, target_x - origin_x)
|
|
if(from_entity == performer)
|
|
resolved_angle_from_performer = .
|
|
|
|
/datum/event_args/actor/clickchain/proc/unpack_click_params()
|
|
if(click_params_unpacked)
|
|
return
|
|
click_params_unpacked = TRUE
|
|
if(!click_params)
|
|
return
|
|
// Handle `screen-loc`, specified as "tile_x:pixel_x,tile_y:pixel_y"
|
|
var/list/x_y_split = splittext(click_params["screen-loc"], ",")
|
|
if(length(x_y_split))
|
|
var/list/x_split = splittext(x_y_split[1], ":")
|
|
var/list/y_split = splittext(x_y_split[2], ":")
|
|
click_params_screen_tx = text2num(x_split[1])
|
|
click_params_screen_ty = text2num(y_split[1])
|
|
click_params_tile_px = text2num(x_split[2])
|
|
click_params_tile_py = text2num(y_split[2])
|
|
|
|
/datum/event_args/actor/clickchain/proc/legacy_get_target_zone()
|
|
return initiator?.zone_sel?.selecting
|