mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-01-17 12:35:26 +00:00
## About The Pull Request This PR introduces a limited set of camera components that can be used by surveillance security consoles and the PDA/laptop camera app. <img width="366" alt="components" src="https://github.com/tgstation/tgstation/assets/80724828/0e628863-9998-46d6-8822-e0a44543b4c2"> There is four camera components, each limited to a specified shell circuit type. Additionally, drone circuit shells can now use the recharge stations too, much like how mobs with BCIs can recharge. ### New Components <img width="136" alt="drone camera" src="https://github.com/tgstation/tgstation/assets/80724828/fd045871-56bf-44a6-bb4f-ebe895d56d3d"> * Drone Camera This camera component captures the surrounding area. It has an option to set the camera range (near 5x5/far 14x14). <img width="136" alt="bci camera" src="https://github.com/tgstation/tgstation/assets/80724828/16bf2dd1-823b-4d66-8249-5d0f1bb1b779"> * BCI Camera This camera component uses the active user's eyes as a camera function. If the user's sights are damaged, the range will be forced to the near setting. If the user is unconscious/dead/blinded or has no eyes, the stream will be cut off. It has an option to set the camera range (near 5x5/far 14x14). <img width="136" alt="polaroid camera" src="https://github.com/tgstation/tgstation/assets/80724828/7c4d53df-b4af-4f7c-8942-a63842510720"> * Polaroid Camera Add-On This camera component streams to a camera network. The camera range is hardcoded to the near setting (5x5). <img width="136" alt="airlock camera" src="https://github.com/tgstation/tgstation/assets/80724828/5d9e9d55-49fc-45a7-99c8-aaf1ae08f6d1"> * Airlock Camera This camera component streams to a camera network. The camera range is hardcoded to the near setting (5x5). ### Features * The cameras can be EMP'd and will be disabled for 90 seconds if successful * When the cameras are active, they will actively drain the cell's power per second (near range uses 3kJ & far range uses 8kJ) * Advance camera console/AIs can use these cameras, however the camera light is disabled (they will be useless in dark areas) ### Screenshots In Action <details> This is the drone camera viewed on a security camera console<br> <img width="425" alt="near" src="https://github.com/tgstation/tgstation/assets/80724828/e5247828-0fee-4552-9e70-5e5ee897c117"><br> This is the same drone, now set to the far range setting<br> <img width="425" alt="far" src="https://github.com/tgstation/tgstation/assets/80724828/e58e3e85-aa90-4f1a-9dff-957c65764b77"><br> </details> ## Why It's Good For The Game This promotes emergent gameplay and improves the overall usefulness for drones as they can be 100% used remotely. ## Changelog 🆑 add: Added new circuit camera components qol: Circuit drones can now recharge at recharge stations /🆑 --------- Co-authored-by: Watermelon914 <37270891+Watermelon914@users.noreply.github.com>
121 lines
3.6 KiB
Plaintext
121 lines
3.6 KiB
Plaintext
/**
|
|
* # Drone
|
|
*
|
|
* A movable mob that can be fed inputs on which direction to travel.
|
|
*/
|
|
/mob/living/circuit_drone
|
|
name = "drone"
|
|
icon = 'icons/obj/science/circuits.dmi'
|
|
icon_state = "setup_medium_med"
|
|
maxHealth = 300
|
|
health = 300
|
|
living_flags = 0
|
|
light_system = OVERLAY_LIGHT_DIRECTIONAL
|
|
light_on = FALSE
|
|
|
|
/mob/living/circuit_drone/Initialize(mapload)
|
|
. = ..()
|
|
AddComponent(/datum/component/shell, list(
|
|
new /obj/item/circuit_component/bot_circuit(),
|
|
new /obj/item/circuit_component/remotecam/drone()
|
|
), SHELL_CAPACITY_LARGE)
|
|
|
|
/mob/living/circuit_drone/examine(mob/user)
|
|
. = ..()
|
|
if(health < maxHealth)
|
|
if(health > maxHealth/3)
|
|
. += "[src]'s parts look loose."
|
|
else
|
|
. += "[src]'s parts look very loose!"
|
|
else
|
|
. += "[src] is in pristine condition."
|
|
|
|
/mob/living/circuit_drone/updatehealth()
|
|
. = ..()
|
|
if(health < 0)
|
|
gib()
|
|
|
|
/mob/living/circuit_drone/welder_act(mob/living/user, obj/item/tool)
|
|
. = ..()
|
|
if(health == maxHealth)
|
|
balloon_alert(user, "already at maximum integrity!")
|
|
return TRUE
|
|
if(tool.use_tool(src, user, 1 SECONDS, volume = 50))
|
|
heal_overall_damage(50, 50)
|
|
return TRUE
|
|
|
|
/mob/living/circuit_drone/spawn_gibs()
|
|
new /obj/effect/gibspawner/robot(drop_location(), src, get_static_viruses())
|
|
|
|
/obj/item/circuit_component/bot_circuit
|
|
display_name = "Drone"
|
|
desc = "Used to send movement output signals to the drone shell."
|
|
|
|
/// The inputs to allow for the drone to move
|
|
var/datum/port/input/north
|
|
var/datum/port/input/east
|
|
var/datum/port/input/south
|
|
var/datum/port/input/west
|
|
|
|
// Done like this so that travelling diagonally is more simple
|
|
COOLDOWN_DECLARE(north_delay)
|
|
COOLDOWN_DECLARE(east_delay)
|
|
COOLDOWN_DECLARE(south_delay)
|
|
COOLDOWN_DECLARE(west_delay)
|
|
|
|
/// Delay between each movement
|
|
var/move_delay = 0.2 SECONDS
|
|
|
|
/obj/item/circuit_component/bot_circuit/register_shell(atom/movable/shell)
|
|
. = ..()
|
|
if(ismob(shell))
|
|
RegisterSignal(shell, COMSIG_PROCESS_BORGCHARGER_OCCUPANT, PROC_REF(on_borg_charge))
|
|
|
|
/obj/item/circuit_component/bot_circuit/unregister_shell(atom/movable/shell)
|
|
UnregisterSignal(shell, COMSIG_PROCESS_BORGCHARGER_OCCUPANT)
|
|
return ..()
|
|
|
|
/obj/item/circuit_component/bot_circuit/proc/on_borg_charge(datum/source, datum/callback/charge_cell, seconds_per_tick)
|
|
SIGNAL_HANDLER
|
|
if (isnull(parent.cell))
|
|
return
|
|
charge_cell.Invoke(parent.cell, seconds_per_tick)
|
|
|
|
/obj/item/circuit_component/bot_circuit/populate_ports()
|
|
north = add_input_port("Move North", PORT_TYPE_SIGNAL)
|
|
east = add_input_port("Move East", PORT_TYPE_SIGNAL)
|
|
south = add_input_port("Move South", PORT_TYPE_SIGNAL)
|
|
west = add_input_port("Move West", PORT_TYPE_SIGNAL)
|
|
|
|
/obj/item/circuit_component/bot_circuit/input_received(datum/port/input/port)
|
|
|
|
var/mob/living/shell = parent.shell
|
|
if(!istype(shell) || shell.stat)
|
|
return
|
|
|
|
var/direction
|
|
|
|
if(COMPONENT_TRIGGERED_BY(north, port) && COOLDOWN_FINISHED(src, north_delay))
|
|
direction = NORTH
|
|
COOLDOWN_START(src, north_delay, move_delay)
|
|
else if(COMPONENT_TRIGGERED_BY(east, port) && COOLDOWN_FINISHED(src, east_delay))
|
|
direction = EAST
|
|
COOLDOWN_START(src, east_delay, move_delay)
|
|
else if(COMPONENT_TRIGGERED_BY(south, port) && COOLDOWN_FINISHED(src, south_delay))
|
|
direction = SOUTH
|
|
COOLDOWN_START(src, south_delay, move_delay)
|
|
else if(COMPONENT_TRIGGERED_BY(west, port) && COOLDOWN_FINISHED(src, west_delay))
|
|
direction = WEST
|
|
COOLDOWN_START(src, west_delay, move_delay)
|
|
|
|
if(!direction)
|
|
return
|
|
|
|
if(ismovable(shell.loc)) //Inside an object, tell it we moved
|
|
var/atom/loc_atom = shell.loc
|
|
loc_atom.relaymove(shell, direction)
|
|
return
|
|
|
|
if(shell.Process_Spacemove(direction))
|
|
shell.Move(get_step(shell, direction), direction)
|