Merge pull request #1031 from Citadel-Station-13/upstream-merge-27234
[MIRROR] [READY]Peacekeeper cyborg projectile dampening fields, attempt three
This commit is contained in:
@@ -407,3 +407,7 @@ GLOBAL_LIST_INIT(ghost_others_options, list(GHOST_OTHERS_SIMPLE, GHOST_OTHERS_DE
|
||||
|
||||
//Error handler defines
|
||||
#define ERROR_USEFUL_LEN 2
|
||||
|
||||
#define NO_FIELD 0
|
||||
#define FIELD_TURF 1
|
||||
#define FIELD_EDGE 2
|
||||
|
||||
27
code/controllers/subsystem/fields.dm
Normal file
27
code/controllers/subsystem/fields.dm
Normal file
@@ -0,0 +1,27 @@
|
||||
|
||||
SUBSYSTEM_DEF(fields)
|
||||
name = "Fields"
|
||||
wait = 2
|
||||
priority = 40
|
||||
flags = SS_KEEP_TIMING
|
||||
var/list/datum/proximity_monitor/advanced/running = list()
|
||||
var/list/datum/proximity_monitor/advanced/currentrun = list()
|
||||
|
||||
/datum/controller/subsystem/fields/fire(resumed = 0)
|
||||
if(!resumed)
|
||||
src.currentrun = running.Copy()
|
||||
var/list/currentrun = src.currentrun
|
||||
while(currentrun.len)
|
||||
var/datum/proximity_monitor/advanced/F = currentrun[currentrun.len]
|
||||
currentrun.len--
|
||||
if(!F.requires_processing)
|
||||
continue
|
||||
F.process()
|
||||
if(MC_TICK_CHECK)
|
||||
return
|
||||
|
||||
/datum/controller/subsystem/fields/proc/register_new_field(datum/proximity_monitor/advanced/F)
|
||||
running += F
|
||||
|
||||
/datum/controller/subsystem/fields/proc/unregister_field(datum/proximity_monitor/advanced/F)
|
||||
running -= F
|
||||
@@ -504,6 +504,113 @@
|
||||
S.change_head_color(color2)
|
||||
dropped = TRUE
|
||||
|
||||
//Peacekeeper Cyborg Projectile Dampenening Field
|
||||
/obj/item/borg/projectile_dampen
|
||||
name = "Hyperkinetic Dampening projector"
|
||||
desc = "A device that projects a dampening field that weakens kinetic energy above a certain threshold. <span class='boldnotice'>Projects a field that drains power per second \
|
||||
while active, that will weaken and slow damaging projectiles inside its field.</span> Still being a prototype, it tends to induce a charge on ungrounded metallic surfaces."
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "shield"
|
||||
var/maxenergy = 1500
|
||||
var/energy = 1500
|
||||
var/energy_recharge = 7.5
|
||||
var/energy_recharge_cyborg_drain_coefficient = 0.4
|
||||
var/cyborg_cell_critical_percentage = 0.05
|
||||
var/mob/living/silicon/robot/host = null
|
||||
var/datum/proximity_monitor/advanced/dampening_field
|
||||
var/projectile_damage_coefficient = 0.5
|
||||
var/projectile_damage_tick_ecost_coefficient = 2 //Lasers get half their damage chopped off, drains 50 power/tick. Note that fields are processed 5 times per second.
|
||||
var/projectile_speed_coefficient = 1.5 //Higher the coefficient slower the projectile.
|
||||
var/projectile_tick_speed_ecost = 15
|
||||
var/current_damage_dampening = 0
|
||||
var/list/obj/item/projectile/tracked
|
||||
var/image/projectile_effect
|
||||
var/field_radius = 3
|
||||
|
||||
/obj/item/borg/projectile_dampen/debug
|
||||
maxenergy = 50000
|
||||
energy = 50000
|
||||
energy_recharge = 5000
|
||||
|
||||
/obj/item/borg/projectile_dampen/Initialize()
|
||||
. = ..()
|
||||
projectile_effect = image('icons/effects/fields.dmi', "projectile_dampen_effect")
|
||||
tracked = list()
|
||||
icon_state = "shield0"
|
||||
START_PROCESSING(SSfastprocess, src)
|
||||
|
||||
/obj/item/borg/projectile_dampen/Destroy()
|
||||
STOP_PROCESSING(SSfastprocess, src)
|
||||
return ..()
|
||||
|
||||
/obj/item/borg/projectile_dampen/attack_self(mob/user)
|
||||
var/active = FALSE
|
||||
if(!istype(dampening_field))
|
||||
activate_field()
|
||||
active = TRUE
|
||||
else
|
||||
deactivate_field()
|
||||
active = FALSE
|
||||
to_chat(user, "<span class='boldnotice'>You [active? "activate":"deactivate"] the [src].</span>")
|
||||
icon_state = "[initial(icon_state)][active]"
|
||||
|
||||
/obj/item/borg/projectile_dampen/proc/activate_field()
|
||||
if(!istype(dampening_field))
|
||||
dampening_field = make_field(/datum/proximity_monitor/advanced/peaceborg_dampener, list("current_range" = field_radius, "host" = src, "projector" = src))
|
||||
|
||||
/obj/item/borg/projectile_dampen/proc/deactivate_field()
|
||||
QDEL_NULL(dampening_field)
|
||||
visible_message("<span class='warning'>The [src] shuts off!</span>")
|
||||
for(var/obj/item/projectile/P in tracked)
|
||||
restore_projectile(P)
|
||||
|
||||
/obj/item/borg/projectile_dampen/process()
|
||||
process_recharge()
|
||||
process_usage()
|
||||
update_location()
|
||||
|
||||
/obj/item/borg/projectile_dampen/proc/update_location()
|
||||
if(dampening_field)
|
||||
dampening_field.HandleMove()
|
||||
|
||||
/obj/item/borg/projectile_dampen/proc/process_usage()
|
||||
var/usage = 0
|
||||
for(var/I in tracked)
|
||||
if(!tracked[I]) //No damage
|
||||
continue
|
||||
usage += projectile_tick_speed_ecost
|
||||
usage += (current_damage_dampening * projectile_damage_tick_ecost_coefficient)
|
||||
energy = Clamp(energy - usage, 0, maxenergy)
|
||||
if(energy <= 0)
|
||||
deactivate_field()
|
||||
visible_message("<span class='warning'>The [src] blinks \"ENERGY DEPLETED\"</span>")
|
||||
|
||||
/obj/item/borg/projectile_dampen/proc/process_recharge()
|
||||
if(!istype(host))
|
||||
energy = Clamp(energy + energy_recharge, 0, maxenergy)
|
||||
return
|
||||
if((host.cell.charge >= (host.cell.maxcharge * cyborg_cell_critical_percentage)) && (energy < maxenergy))
|
||||
host.cell.use(energy_recharge*energy_recharge_cyborg_drain_coefficient)
|
||||
energy += energy_recharge
|
||||
|
||||
/obj/item/borg/projectile_dampen/proc/dampen_projectile(obj/item/projectile/P, track_projectile = TRUE)
|
||||
if(tracked[P])
|
||||
return
|
||||
if(track_projectile)
|
||||
tracked[P] = P.damage
|
||||
current_damage_dampening += P.damage
|
||||
P.damage *= projectile_damage_coefficient
|
||||
P.speed *= projectile_speed_coefficient
|
||||
P.add_overlay(projectile_effect)
|
||||
|
||||
/obj/item/borg/projectile_dampen/proc/restore_projectile(obj/item/projectile/P)
|
||||
tracked -= P
|
||||
P.damage *= (1/projectile_damage_coefficient)
|
||||
P.speed *= (1/projectile_speed_coefficient)
|
||||
P.cut_overlay(projectile_effect)
|
||||
current_damage_dampening -= P.damage
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
HUD/SIGHT things
|
||||
***********************************************************************/
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
|
||||
if (opacity)
|
||||
has_opaque_atom = TRUE
|
||||
|
||||
|
||||
return INITIALIZE_HINT_NORMAL
|
||||
|
||||
/turf/open/space/attack_ghost(mob/dead/observer/user)
|
||||
@@ -177,7 +177,7 @@
|
||||
ChangeTurf(/turf/open/floor/plating)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
|
||||
/turf/open/space/ReplaceWithLattice()
|
||||
var/dest_x = destination_x
|
||||
var/dest_y = destination_y
|
||||
@@ -186,4 +186,4 @@
|
||||
destination_x = dest_x
|
||||
destination_y = dest_y
|
||||
destination_z = dest_z
|
||||
|
||||
|
||||
|
||||
@@ -92,39 +92,39 @@
|
||||
LC.attackby(C,user)
|
||||
return
|
||||
coil.place_turf(src, user)
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
/turf/CanPass(atom/movable/mover, turf/target, height=1.5)
|
||||
if(!target) return 0
|
||||
if(!target) return FALSE
|
||||
|
||||
if(istype(mover)) // turf/Enter(...) will perform more advanced checks
|
||||
return !density
|
||||
|
||||
else // Now, doing more detailed checks for air movement and air group formation
|
||||
if(target.blocks_air||blocks_air)
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
for(var/obj/obstacle in src)
|
||||
if(!obstacle.CanPass(mover, target, height))
|
||||
return 0
|
||||
return FALSE
|
||||
for(var/obj/obstacle in target)
|
||||
if(!obstacle.CanPass(mover, src, height))
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/turf/Enter(atom/movable/mover as mob|obj, atom/forget as mob|obj|turf|area)
|
||||
if (!mover)
|
||||
return 1
|
||||
return TRUE
|
||||
// First, make sure it can leave its square
|
||||
if(isturf(mover.loc))
|
||||
// Nothing but border objects stop you from leaving a tile, only one loop is needed
|
||||
for(var/obj/obstacle in mover.loc)
|
||||
if(!obstacle.CheckExit(mover, src) && obstacle != mover && obstacle != forget)
|
||||
mover.Bump(obstacle, 1)
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
var/list/large_dense = list()
|
||||
//Next, check objects to block entry that are on the border
|
||||
@@ -132,14 +132,14 @@
|
||||
if(border_obstacle.flags & ON_BORDER)
|
||||
if(!border_obstacle.CanPass(mover, mover.loc, 1) && (forget != border_obstacle))
|
||||
mover.Bump(border_obstacle, 1)
|
||||
return 0
|
||||
return FALSE
|
||||
else
|
||||
large_dense += border_obstacle
|
||||
|
||||
//Then, check the turf itself
|
||||
if (!src.CanPass(mover, src))
|
||||
mover.Bump(src, 1)
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
//Finally, check objects/mobs to block entry that are not on the border
|
||||
var/atom/movable/tompost_bump
|
||||
@@ -151,8 +151,9 @@
|
||||
top_layer = obstacle.layer
|
||||
if(tompost_bump)
|
||||
mover.Bump(tompost_bump,1)
|
||||
return 0
|
||||
return 1 //Nothing found to block so return success!
|
||||
return FALSE
|
||||
|
||||
return TRUE //Nothing found to block so return success!
|
||||
|
||||
/turf/Entered(atom/movable/AM)
|
||||
if(explosion_level && AM.ex_check(explosion_id))
|
||||
@@ -185,7 +186,7 @@
|
||||
O.make_unfrozen()
|
||||
|
||||
/turf/proc/is_plasteel_floor()
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
/turf/proc/levelupdate()
|
||||
for(var/obj/O in src)
|
||||
@@ -303,7 +304,7 @@
|
||||
if(src_object.contents.len)
|
||||
to_chat(usr, "<span class='notice'>You start dumping out the contents...</span>")
|
||||
if(!do_after(usr,20,target=src_object))
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
var/list/things = src_object.contents.Copy()
|
||||
var/datum/progressbar/progress = new(user, things.len, src)
|
||||
@@ -311,7 +312,7 @@
|
||||
sleep(1)
|
||||
qdel(progress)
|
||||
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
//////////////////////////////
|
||||
//Distance procs
|
||||
@@ -325,7 +326,7 @@
|
||||
// possible. It results in more efficient (CPU-wise) pathing
|
||||
// for bots and anything else that only moves in cardinal dirs.
|
||||
/turf/proc/Distance_cardinal(turf/T)
|
||||
if(!src || !T) return 0
|
||||
if(!src || !T) return FALSE
|
||||
return abs(x - T.x) + abs(y - T.y)
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
@@ -341,7 +342,7 @@
|
||||
return(2)
|
||||
|
||||
/turf/proc/can_have_cabling()
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
/turf/proc/can_lay_cable()
|
||||
return can_have_cabling() & !intact
|
||||
|
||||
309
code/modules/fields/fields.dm
Normal file
309
code/modules/fields/fields.dm
Normal file
@@ -0,0 +1,309 @@
|
||||
|
||||
//Movable and easily code-modified fields! Allows for custom AOE effects that affect movement and anything inside of them, and can do custom turf effects!
|
||||
//Supports automatic recalculation/reset on movement.
|
||||
//If there's any way to make this less CPU intensive than I've managed, gimme a call or do it yourself! - kevinz000
|
||||
|
||||
//Field shapes
|
||||
#define FIELD_NO_SHAPE 0 //Does not update turfs automatically
|
||||
#define FIELD_SHAPE_RADIUS_SQUARE 1 //Uses current_range and square_depth_up/down
|
||||
#define FIELD_SHAPE_CUSTOM_SQUARE 2 //Uses square_height and square_width and square_depth_up/down
|
||||
|
||||
//Proc to make fields. make_field(field_type, field_params_in_associative_list)
|
||||
/proc/make_field(field_type, list/field_params, override_checks = FALSE, start_field = TRUE)
|
||||
var/datum/proximity_monitor/advanced/F = new field_type()
|
||||
if(!F.assume_params(field_params) && !override_checks)
|
||||
QDEL_NULL(F)
|
||||
if(!F.check_variables() && !override_checks)
|
||||
QDEL_NULL(F)
|
||||
if(start_field && (F || override_checks))
|
||||
F.Initialize()
|
||||
return F
|
||||
|
||||
/datum/proximity_monitor/advanced
|
||||
var/name = "\improper Energy Field"
|
||||
//Field setup specifications
|
||||
var/field_shape = FIELD_NO_SHAPE
|
||||
var/square_height = 0
|
||||
var/square_width = 0
|
||||
var/square_depth_up = 0
|
||||
var/square_depth_down = 0
|
||||
//Processing
|
||||
var/requires_processing = FALSE
|
||||
var/process_inner_turfs = FALSE //Don't do this unless it's absolutely necessary
|
||||
var/process_edge_turfs = FALSE //Don't do this either unless it's absolutely necessary, you can just track what things are inside manually or on the initial setup.
|
||||
var/setup_edge_turfs = FALSE //Setup edge turfs/all field turfs. Set either or both to ON when you need it, it's defaulting to off unless you do to save CPU.
|
||||
var/setup_field_turfs = FALSE
|
||||
|
||||
var/list/turf/field_turfs = list()
|
||||
var/list/turf/edge_turfs = list()
|
||||
var/list/turf/field_turfs_new = list()
|
||||
var/list/turf/edge_turfs_new = list()
|
||||
|
||||
/datum/proximity_monitor/advanced/New()
|
||||
SSfields.register_new_field(src)
|
||||
|
||||
/datum/proximity_monitor/advanced/Destroy()
|
||||
SSfields.unregister_field(src)
|
||||
full_cleanup()
|
||||
return ..()
|
||||
|
||||
/datum/proximity_monitor/advanced/proc/assume_params(list/field_params)
|
||||
var/pass_check = TRUE
|
||||
for(var/param in field_params)
|
||||
if(vars[param] || isnull(vars[param]) || (param in vars))
|
||||
vars[param] = field_params[param]
|
||||
else
|
||||
pass_check = FALSE
|
||||
return pass_check
|
||||
|
||||
/datum/proximity_monitor/advanced/proc/check_variables()
|
||||
var/pass = TRUE
|
||||
if(field_shape == FIELD_NO_SHAPE) //If you're going to make a manually updated field you shouldn't be using automatic checks so don't.
|
||||
pass = FALSE
|
||||
if(current_range < 0 || square_height < 0 || square_width < 0 || square_depth_up < 0 || square_depth_down < 0)
|
||||
pass = FALSE
|
||||
if(!istype(host))
|
||||
pass = FALSE
|
||||
return pass
|
||||
|
||||
/datum/proximity_monitor/advanced/process()
|
||||
if(process_inner_turfs)
|
||||
for(var/turf/T in field_turfs)
|
||||
process_inner_turf(T)
|
||||
CHECK_TICK //Really crappy lagchecks, needs improvement once someone starts using processed fields.
|
||||
if(process_edge_turfs)
|
||||
for(var/turf/T in edge_turfs)
|
||||
process_edge_turf(T)
|
||||
CHECK_TICK //Same here.
|
||||
|
||||
/datum/proximity_monitor/advanced/proc/process_inner_turf(turf/T)
|
||||
|
||||
/datum/proximity_monitor/advanced/proc/process_edge_turf(turf/T)
|
||||
|
||||
/datum/proximity_monitor/advanced/proc/Initialize()
|
||||
setup_field()
|
||||
post_setup_field()
|
||||
|
||||
/datum/proximity_monitor/advanced/proc/full_cleanup() //Full cleanup for when you change something that would require complete resetting.
|
||||
for(var/turf/T in edge_turfs)
|
||||
cleanup_edge_turf(T)
|
||||
for(var/turf/T in field_turfs)
|
||||
cleanup_field_turf(T)
|
||||
|
||||
/datum/proximity_monitor/advanced/proc/recalculate_field(ignore_movement_check = FALSE) //Call every time the field moves (done automatically if you use update_center) or a setup specification is changed.
|
||||
if(!(ignore_movement_check || ((host.loc != last_host_loc) && (field_shape != FIELD_NO_SHAPE))))
|
||||
return
|
||||
update_new_turfs()
|
||||
var/list/turf/needs_setup = field_turfs_new.Copy()
|
||||
if(setup_field_turfs)
|
||||
for(var/turf/T in field_turfs)
|
||||
if(!(T in needs_setup))
|
||||
cleanup_field_turf(T)
|
||||
else
|
||||
needs_setup -= T
|
||||
CHECK_TICK
|
||||
for(var/turf/T in needs_setup)
|
||||
setup_field_turf(T)
|
||||
CHECK_TICK
|
||||
if(setup_edge_turfs)
|
||||
for(var/turf/T in edge_turfs)
|
||||
cleanup_edge_turf(T)
|
||||
CHECK_TICK
|
||||
for(var/turf/T in edge_turfs_new)
|
||||
setup_edge_turf(T)
|
||||
CHECK_TICK
|
||||
|
||||
/datum/proximity_monitor/advanced/proc/field_turf_canpass(atom/movable/AM, obj/effect/abstract/proximity_checker/advanced/field_turf/F, turf/entering)
|
||||
return TRUE
|
||||
|
||||
/datum/proximity_monitor/advanced/proc/field_turf_uncross(atom/movable/AM, obj/effect/abstract/proximity_checker/advanced/field_turf/F)
|
||||
return TRUE
|
||||
|
||||
/datum/proximity_monitor/advanced/proc/field_turf_crossed(atom/movable/AM, obj/effect/abstract/proximity_checker/advanced/field_turf/F)
|
||||
return TRUE
|
||||
|
||||
/datum/proximity_monitor/advanced/proc/field_turf_uncrossed(atom/movable/AM, obj/effect/abstract/proximity_checker/advanced/field_turf/F)
|
||||
return TRUE
|
||||
|
||||
/datum/proximity_monitor/advanced/proc/field_edge_canpass(atom/movable/AM, obj/effect/abstract/proximity_checker/advanced/field_edge/F, turf/entering)
|
||||
return TRUE
|
||||
|
||||
/datum/proximity_monitor/advanced/proc/field_edge_uncross(atom/movable/AM, obj/effect/abstract/proximity_checker/advanced/field_edge/F)
|
||||
return TRUE
|
||||
|
||||
/datum/proximity_monitor/advanced/proc/field_edge_crossed(atom/movable/AM, obj/effect/abstract/proximity_checker/advanced/field_edge/F)
|
||||
return TRUE
|
||||
|
||||
/datum/proximity_monitor/advanced/proc/field_edge_uncrossed(atom/movable/AM, obj/effect/abstract/proximity_checker/advanced/field_edge/F)
|
||||
return TRUE
|
||||
|
||||
/datum/proximity_monitor/advanced/HandleMove()
|
||||
var/atom/_host = host
|
||||
var/atom/new_host_loc = _host.loc
|
||||
if(last_host_loc != new_host_loc)
|
||||
recalculate_field()
|
||||
|
||||
/datum/proximity_monitor/advanced/proc/post_setup_field()
|
||||
|
||||
/datum/proximity_monitor/advanced/proc/setup_field()
|
||||
update_new_turfs()
|
||||
if(setup_field_turfs)
|
||||
for(var/turf/T in field_turfs_new)
|
||||
setup_field_turf(T)
|
||||
CHECK_TICK
|
||||
if(setup_edge_turfs)
|
||||
for(var/turf/T in edge_turfs_new)
|
||||
setup_edge_turf(T)
|
||||
CHECK_TICK
|
||||
|
||||
/datum/proximity_monitor/advanced/proc/cleanup_field_turf(turf/T)
|
||||
qdel(field_turfs[T])
|
||||
field_turfs -= T
|
||||
|
||||
/datum/proximity_monitor/advanced/proc/cleanup_edge_turf(turf/T)
|
||||
qdel(edge_turfs[T])
|
||||
edge_turfs -= T
|
||||
|
||||
/datum/proximity_monitor/advanced/proc/setup_field_turf(turf/T)
|
||||
field_turfs[T] = new /obj/effect/abstract/proximity_checker/advanced/field_turf(T, src)
|
||||
|
||||
/datum/proximity_monitor/advanced/proc/setup_edge_turf(turf/T)
|
||||
edge_turfs[T] = new /obj/effect/abstract/proximity_checker/advanced/field_edge(T, src)
|
||||
|
||||
/datum/proximity_monitor/advanced/proc/update_new_turfs()
|
||||
if(!istype(host))
|
||||
return FALSE
|
||||
last_host_loc = host.loc
|
||||
var/turf/center = get_turf(host)
|
||||
field_turfs_new = list()
|
||||
edge_turfs_new = list()
|
||||
switch(field_shape)
|
||||
if(FIELD_NO_SHAPE)
|
||||
return FALSE
|
||||
if(FIELD_SHAPE_RADIUS_SQUARE)
|
||||
for(var/turf/T in block(locate(center.x-current_range,center.y-current_range,center.z-square_depth_down),locate(center.x+current_range, center.y+current_range,center.z+square_depth_up)))
|
||||
field_turfs_new += T
|
||||
edge_turfs_new = field_turfs_new.Copy()
|
||||
if(current_range >= 1)
|
||||
var/list/turf/center_turfs = list()
|
||||
for(var/turf/T in block(locate(center.x-current_range+1,center.y-current_range+1,center.z-square_depth_down),locate(center.x+current_range-1, center.y+current_range-1,center.z+square_depth_up)))
|
||||
center_turfs += T
|
||||
for(var/turf/T in center_turfs)
|
||||
edge_turfs_new -= T
|
||||
if(FIELD_SHAPE_CUSTOM_SQUARE)
|
||||
for(var/turf/T in block(locate(center.x-square_width,center.y-square_height,center.z-square_depth_down),locate(center.x+square_width, center.y+square_height,center.z+square_depth_up)))
|
||||
field_turfs_new += T
|
||||
edge_turfs_new = field_turfs_new.Copy()
|
||||
if(square_height >= 1 && square_width >= 1)
|
||||
var/list/turf/center_turfs = list()
|
||||
for(var/turf/T in block(locate(center.x-square_width+1,center.y-square_height+1,center.z-square_depth_down),locate(center.x+square_width-1, center.y+square_height-1,center.z+square_depth_up)))
|
||||
center_turfs += T
|
||||
for(var/turf/T in center_turfs)
|
||||
edge_turfs_new -= T
|
||||
|
||||
//Gets edge direction/corner, only works with square radius/WDH fields!
|
||||
/datum/proximity_monitor/advanced/proc/get_edgeturf_direction(turf/T, turf/center_override = null)
|
||||
var/turf/checking_from = get_turf(host)
|
||||
if(istype(center_override))
|
||||
checking_from = center_override
|
||||
if(field_shape != FIELD_SHAPE_RADIUS_SQUARE && field_shape != FIELD_SHAPE_CUSTOM_SQUARE)
|
||||
return
|
||||
if(!(T in edge_turfs))
|
||||
return
|
||||
switch(field_shape)
|
||||
if(FIELD_SHAPE_RADIUS_SQUARE)
|
||||
if(((T.x == (checking_from.x + current_range)) || (T.x == (checking_from.x - current_range))) && ((T.y == (checking_from.y + current_range)) || (T.y == (checking_from.y - current_range))))
|
||||
return get_dir(checking_from, T)
|
||||
if(T.x == (checking_from.x + current_range))
|
||||
return EAST
|
||||
if(T.x == (checking_from.x - current_range))
|
||||
return WEST
|
||||
if(T.y == (checking_from.y - current_range))
|
||||
return SOUTH
|
||||
if(T.y == (checking_from.y + current_range))
|
||||
return NORTH
|
||||
if(FIELD_SHAPE_CUSTOM_SQUARE)
|
||||
if(((T.x == (checking_from.x + square_width)) || (T.x == (checking_from.x - square_width))) && ((T.y == (checking_from.y + square_height)) || (T.y == (checking_from.y - square_height))))
|
||||
return get_dir(checking_from, T)
|
||||
if(T.x == (checking_from.x + square_width))
|
||||
return EAST
|
||||
if(T.x == (checking_from.x - square_width))
|
||||
return WEST
|
||||
if(T.y == (checking_from.y - square_height))
|
||||
return SOUTH
|
||||
if(T.y == (checking_from.y + square_height))
|
||||
return NORTH
|
||||
|
||||
//DEBUG FIELDS
|
||||
/datum/proximity_monitor/advanced/debug
|
||||
name = "\improper Color Matrix Field"
|
||||
field_shape = FIELD_SHAPE_RADIUS_SQUARE
|
||||
current_range = 5
|
||||
var/set_fieldturf_color = "#aaffff"
|
||||
var/set_edgeturf_color = "#ffaaff"
|
||||
setup_field_turfs = TRUE
|
||||
setup_edge_turfs = TRUE
|
||||
|
||||
/datum/proximity_monitor/advanced/debug/recalculate_field()
|
||||
..()
|
||||
|
||||
/datum/proximity_monitor/advanced/debug/post_setup_field()
|
||||
..()
|
||||
|
||||
/datum/proximity_monitor/advanced/debug/setup_edge_turf(turf/T)
|
||||
T.color = set_edgeturf_color
|
||||
..()
|
||||
|
||||
/datum/proximity_monitor/advanced/debug/cleanup_edge_turf(turf/T)
|
||||
T.color = initial(T.color)
|
||||
..()
|
||||
if(T in field_turfs)
|
||||
T.color = set_fieldturf_color
|
||||
|
||||
/datum/proximity_monitor/advanced/debug/setup_field_turf(turf/T)
|
||||
T.color = set_fieldturf_color
|
||||
..()
|
||||
|
||||
/datum/proximity_monitor/advanced/debug/cleanup_field_turf(turf/T)
|
||||
T.color = initial(T.color)
|
||||
..()
|
||||
|
||||
//DEBUG FIELD ITEM
|
||||
/obj/item/device/multitool/field_debug
|
||||
name = "strange multitool"
|
||||
desc = "Seems to project a colored field!"
|
||||
var/list/field_params = list("field_shape" = FIELD_SHAPE_RADIUS_SQUARE, "current_range" = 5, "set_fieldturf_color" = "#aaffff", "set_edgeturf_color" = "#ffaaff")
|
||||
var/field_type = /datum/proximity_monitor/advanced/debug
|
||||
var/operating = FALSE
|
||||
var/datum/proximity_monitor/advanced/current = null
|
||||
|
||||
/obj/item/device/multitool/field_debug/New()
|
||||
START_PROCESSING(SSobj, src)
|
||||
..()
|
||||
|
||||
/obj/item/device/multitool/field_debug/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
QDEL_NULL(current)
|
||||
..()
|
||||
|
||||
/obj/item/device/multitool/field_debug/proc/setup_debug_field()
|
||||
var/list/new_params = field_params.Copy()
|
||||
new_params["host"] = src
|
||||
current = make_field(field_type, new_params)
|
||||
|
||||
/obj/item/device/multitool/field_debug/attack_self(mob/user)
|
||||
operating = !operating
|
||||
to_chat(user, "You turn the [src] [operating? "on":"off"].")
|
||||
if(!istype(current) && operating)
|
||||
setup_debug_field()
|
||||
else if(!operating)
|
||||
QDEL_NULL(current)
|
||||
|
||||
/obj/item/device/multitool/field_debug/on_mob_move()
|
||||
check_turf(get_turf(src))
|
||||
|
||||
/obj/item/device/multitool/field_debug/process()
|
||||
check_turf(get_turf(src))
|
||||
|
||||
/obj/item/device/multitool/field_debug/proc/check_turf(turf/T)
|
||||
current.HandleMove()
|
||||
106
code/modules/fields/peaceborg_dampener.dm
Normal file
106
code/modules/fields/peaceborg_dampener.dm
Normal file
@@ -0,0 +1,106 @@
|
||||
|
||||
//Projectile dampening field that slows projectiles and lowers their damage for an energy cost deducted every 1/5 second.
|
||||
//Only use square radius for this!
|
||||
/datum/proximity_monitor/advanced/peaceborg_dampener
|
||||
name = "\improper Hyperkinetic Dampener Field"
|
||||
requires_processing = TRUE
|
||||
setup_edge_turfs = TRUE
|
||||
setup_field_turfs = TRUE
|
||||
field_shape = FIELD_SHAPE_RADIUS_SQUARE
|
||||
var/static/image/edgeturf_south = image('icons/effects/fields.dmi', icon_state = "projectile_dampen_south")
|
||||
var/static/image/edgeturf_north = image('icons/effects/fields.dmi', icon_state = "projectile_dampen_north")
|
||||
var/static/image/edgeturf_west = image('icons/effects/fields.dmi', icon_state = "projectile_dampen_west")
|
||||
var/static/image/edgeturf_east = image('icons/effects/fields.dmi', icon_state = "projectile_dampen_east")
|
||||
var/static/image/northwest_corner = image('icons/effects/fields.dmi', icon_state = "projectile_dampen_northwest")
|
||||
var/static/image/southwest_corner = image('icons/effects/fields.dmi', icon_state = "projectile_dampen_southwest")
|
||||
var/static/image/northeast_corner = image('icons/effects/fields.dmi', icon_state = "projectile_dampen_northeast")
|
||||
var/static/image/southeast_corner = image('icons/effects/fields.dmi', icon_state = "projectile_dampen_southeast")
|
||||
var/obj/item/borg/projectile_dampen/projector = null
|
||||
var/list/obj/item/projectile/tracked
|
||||
var/list/obj/item/projectile/staging
|
||||
|
||||
/datum/proximity_monitor/advanced/peaceborg_dampener/New()
|
||||
tracked = list()
|
||||
staging = list()
|
||||
..()
|
||||
|
||||
/datum/proximity_monitor/advanced/peaceborg_dampener/process()
|
||||
if(!istype(projector))
|
||||
qdel(src)
|
||||
var/list/ranged = list()
|
||||
for(var/obj/item/projectile/P in range(current_range, get_turf(host)))
|
||||
ranged += P
|
||||
for(var/obj/item/projectile/P in tracked)
|
||||
if(!(P in ranged) || !P.loc)
|
||||
release_projectile(P)
|
||||
for(var/mob/living/silicon/robot/R in range(current_range, get_turf(host)))
|
||||
if(R.has_buckled_mobs())
|
||||
for(var/mob/living/L in R.buckled_mobs)
|
||||
L.visible_message("<span class='warning'>[L] is knocked off of [R] by the charge in [R]'s chassis induced by [name]!</span>") //I know it's bad.
|
||||
L.Weaken(3)
|
||||
R.unbuckle_mob(L)
|
||||
do_sparks(5, 0, L)
|
||||
..()
|
||||
|
||||
/datum/proximity_monitor/advanced/peaceborg_dampener/setup_edge_turf(turf/T)
|
||||
..()
|
||||
var/image/I = get_edgeturf_overlay(get_edgeturf_direction(T))
|
||||
var/obj/effect/abstract/proximity_checker/advanced/F = edge_turfs[T]
|
||||
F.appearance = I.appearance
|
||||
F.invisibility = 0
|
||||
F.layer = 5
|
||||
|
||||
/datum/proximity_monitor/advanced/peaceborg_dampener/cleanup_edge_turf(turf/T)
|
||||
..()
|
||||
|
||||
/datum/proximity_monitor/advanced/peaceborg_dampener/proc/get_edgeturf_overlay(direction)
|
||||
switch(direction)
|
||||
if(NORTH)
|
||||
return edgeturf_north
|
||||
if(SOUTH)
|
||||
return edgeturf_south
|
||||
if(EAST)
|
||||
return edgeturf_east
|
||||
if(WEST)
|
||||
return edgeturf_west
|
||||
if(NORTHEAST)
|
||||
return northeast_corner
|
||||
if(NORTHWEST)
|
||||
return northwest_corner
|
||||
if(SOUTHEAST)
|
||||
return southeast_corner
|
||||
if(SOUTHWEST)
|
||||
return southwest_corner
|
||||
|
||||
/datum/proximity_monitor/advanced/peaceborg_dampener/proc/capture_projectile(obj/item/projectile/P, track_projectile = TRUE)
|
||||
if(P in tracked)
|
||||
return
|
||||
projector.dampen_projectile(P, track_projectile)
|
||||
if(track_projectile)
|
||||
tracked += P
|
||||
|
||||
/datum/proximity_monitor/advanced/peaceborg_dampener/proc/release_projectile(obj/item/projectile/P)
|
||||
projector.restore_projectile(P)
|
||||
tracked -= P
|
||||
|
||||
/datum/proximity_monitor/advanced/peaceborg_dampener/field_edge_uncrossed(atom/movable/AM, obj/effect/abstract/proximity_checker/advanced/field_edge/F)
|
||||
if(!is_turf_in_field(get_turf(AM), src))
|
||||
if(istype(AM, /obj/item/projectile))
|
||||
if(AM in tracked)
|
||||
release_projectile(AM)
|
||||
else
|
||||
capture_projectile(AM, FALSE)
|
||||
return ..()
|
||||
|
||||
/datum/proximity_monitor/advanced/peaceborg_dampener/field_edge_crossed(atom/movable/AM, obj/effect/abstract/proximity_checker/advanced/field_edge/F)
|
||||
if(istype(AM, /obj/item/projectile) && !(AM in tracked) && staging[AM] && !is_turf_in_field(staging[AM], src))
|
||||
capture_projectile(AM)
|
||||
staging -= AM
|
||||
return ..()
|
||||
|
||||
/datum/proximity_monitor/advanced/peaceborg_dampener/field_edge_canpass(atom/movable/AM, obj/effect/abstract/proximity_checker/advanced/field_edge/F, turf/entering)
|
||||
if(istype(AM, /obj/item/projectile))
|
||||
staging[AM] = get_turf(AM)
|
||||
. = ..()
|
||||
if(!.)
|
||||
staging -= AM //This one ain't goin' through.
|
||||
76
code/modules/fields/turf_objects.dm
Normal file
76
code/modules/fields/turf_objects.dm
Normal file
@@ -0,0 +1,76 @@
|
||||
|
||||
/obj/effect/abstract/proximity_checker/advanced
|
||||
name = "field"
|
||||
desc = "Why can you see energy fields?!"
|
||||
icon = null
|
||||
icon_state = null
|
||||
alpha = 0
|
||||
invisibility = INVISIBILITY_ABSTRACT
|
||||
flags = ABSTRACT|ON_BORDER
|
||||
var/datum/proximity_monitor/advanced/parent = null
|
||||
|
||||
/obj/effect/abstract/proximity_checker/advanced/Initialize(mapload, _monitor)
|
||||
if(_monitor)
|
||||
parent = _monitor
|
||||
return ..()
|
||||
|
||||
/obj/effect/abstract/proximity_checker/advanced/center
|
||||
name = "field anchor"
|
||||
desc = "No."
|
||||
|
||||
/obj/effect/abstract/proximity_checker/advanced/field_turf
|
||||
name = "energy field"
|
||||
desc = "Get off my turf!"
|
||||
|
||||
/obj/effect/abstract/proximity_checker/advanced/field_turf/CanPass(atom/movable/AM, turf/target, height)
|
||||
if(parent)
|
||||
return parent.field_turf_canpass(AM, src, target)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/abstract/proximity_checker/advanced/field_turf/Crossed(atom/movable/AM)
|
||||
if(parent)
|
||||
return parent.field_turf_crossed(AM, src)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/abstract/proximity_checker/advanced/field_turf/Uncross(atom/movable/AM)
|
||||
if(parent)
|
||||
return parent.field_turf_uncross(AM, src)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/abstract/proximity_checker/advanced/field_turf/Uncrossed(atom/movable/AM)
|
||||
if(parent)
|
||||
return parent.field_turf_uncrossed(AM, src)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/abstract/proximity_checker/advanced/field_edge
|
||||
name = "energy field edge"
|
||||
desc = "Edgy description here."
|
||||
|
||||
/obj/effect/abstract/proximity_checker/advanced/field_edge/CanPass(atom/movable/AM, turf/target, height)
|
||||
if(parent)
|
||||
return parent.field_edge_canpass(AM, src, target)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/abstract/proximity_checker/advanced/field_edge/Crossed(atom/movable/AM)
|
||||
if(parent)
|
||||
return parent.field_edge_crossed(AM, src)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/abstract/proximity_checker/advanced/field_edge/Uncross(atom/movable/AM)
|
||||
if(parent)
|
||||
return parent.field_edge_uncross(AM, src)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/abstract/proximity_checker/advanced/field_edge/Uncrossed(atom/movable/AM)
|
||||
if(parent)
|
||||
return parent.field_edge_uncrossed(AM, src)
|
||||
return TRUE
|
||||
|
||||
/proc/is_turf_in_field(turf/T, datum/proximity_monitor/advanced/F) //Looking for ways to optimize this!
|
||||
for(var/obj/effect/abstract/proximity_checker/advanced/O in T)
|
||||
if(istype(O, /obj/effect/abstract/proximity_checker/advanced/field_edge))
|
||||
if(O.parent == F)
|
||||
return FIELD_EDGE
|
||||
if(O.parent == F)
|
||||
return FIELD_TURF
|
||||
return NO_FIELD
|
||||
@@ -407,7 +407,8 @@
|
||||
/obj/item/weapon/reagent_containers/borghypo/peace,
|
||||
/obj/item/weapon/holosign_creator/cyborg,
|
||||
/obj/item/borg/cyborghug/peacekeeper,
|
||||
/obj/item/weapon/extinguisher)
|
||||
/obj/item/weapon/extinguisher,
|
||||
/obj/item/borg/projectile_dampen)
|
||||
emag_modules = list(/obj/item/weapon/reagent_containers/borghypo/peace/hacked)
|
||||
ratvar_modules = list(
|
||||
/obj/item/clockwork/slab/cyborg/peacekeeper,
|
||||
|
||||
Reference in New Issue
Block a user