Merge branch 'master' of https://github.com/Citadel-Station-13/Citadel-Station-13 into player-panel-can-reenter

This commit is contained in:
Putnam
2020-01-18 03:39:35 -08:00
126 changed files with 1311 additions and 462 deletions
@@ -345,13 +345,13 @@
/obj/item/projectile/tentacle/on_hit(atom/target, blocked = FALSE)
var/mob/living/carbon/human/H = firer
if(blocked >= 100)
return 0
return BULLET_ACT_BLOCK
if(isitem(target))
var/obj/item/I = target
if(!I.anchored)
to_chat(firer, "<span class='notice'>You pull [I] right into your grasp.</span>")
H.put_in_hands(I) //Because throwing it is goofy as fuck and unreliable. If you land the tentacle despite the penalties to accuracy, you should have your reward.
. = 1
. = BULLET_ACT_HIT
else if(isliving(target))
var/mob/living/L = target
@@ -366,7 +366,7 @@
if(INTENT_HELP)
C.visible_message("<span class='danger'>[L] is pulled by [H]'s tentacle!</span>","<span class='userdanger'>A tentacle grabs you and pulls you towards [H]!</span>")
C.throw_at(get_step_towards(H,C), 8, 2)
return 1
return BULLET_ACT_HIT
if(INTENT_DISARM)
var/obj/item/I = C.get_active_held_item()
@@ -374,27 +374,27 @@
if(C.dropItemToGround(I))
C.visible_message("<span class='danger'>[I] is yanked off [C]'s hand by [src]!</span>","<span class='userdanger'>A tentacle pulls [I] away from you!</span>")
on_hit(I) //grab the item as if you had hit it directly with the tentacle
return 1
return BULLET_ACT_HIT
else
to_chat(firer, "<span class='danger'>You can't seem to pry [I] off [C]'s hands!</span>")
return 0
return BULLET_ACT_BLOCK
else
to_chat(firer, "<span class='danger'>[C] has nothing in hand to disarm!</span>")
return 0
return BULLET_ACT_HIT
if(INTENT_GRAB)
C.visible_message("<span class='danger'>[L] is grabbed by [H]'s tentacle!</span>","<span class='userdanger'>A tentacle grabs you and pulls you towards [H]!</span>")
C.throw_at(get_step_towards(H,C), 8, 2, H, TRUE, TRUE, callback=CALLBACK(src, .proc/tentacle_grab, H, C))
return 1
return BULLET_ACT_HIT
if(INTENT_HARM)
C.visible_message("<span class='danger'>[L] is thrown towards [H] by a tentacle!</span>","<span class='userdanger'>A tentacle grabs you and throws you towards [H]!</span>")
C.throw_at(get_step_towards(H,C), 8, 2, H, TRUE, TRUE, callback=CALLBACK(src, .proc/tentacle_stab, H, C))
return 1
return BULLET_ACT_HIT
else
L.visible_message("<span class='danger'>[L] is pulled by [H]'s tentacle!</span>","<span class='userdanger'>A tentacle grabs you and pulls you towards [H]!</span>")
L.throw_at(get_step_towards(H,L), 8, 2)
. = 1
. = BULLET_ACT_HIT
/obj/item/projectile/tentacle/Destroy()
qdel(chain)
@@ -182,7 +182,7 @@
if(isliving(target))
var/mob/living/L = target
if(is_servant_of_ratvar(L) || L.stat || L.has_status_effect(STATUS_EFFECT_KINDLE))
return
return BULLET_ACT_HIT
var/atom/O = L.anti_magic_check()
playsound(L, 'sound/magic/fireball.ogg', 50, TRUE, frequency = 1.25)
if(O)
@@ -97,7 +97,7 @@
/mob/living/simple_animal/hostile/clockwork/marauder/bullet_act(obj/item/projectile/P)
if(deflect_projectile(P))
return
return BULLET_ACT_BLOCK
return ..()
/mob/living/simple_animal/hostile/clockwork/marauder/proc/deflect_projectile(obj/item/projectile/P)
@@ -31,7 +31,7 @@
if(auto_reflect(P, P.dir, get_turf(P), P.Angle) != -1)
return ..()
return -1
return BULLET_ACT_FORCE_PIERCE
/obj/structure/destructible/clockwork/reflector/proc/auto_reflect(obj/item/projectile/P, pdir, turf/ploc, pangle)
@@ -35,7 +35,7 @@ The regular pipe you see everywhere, including bent ones.
/obj/machinery/atmospherics/pipe/simple/general/visible
level = PIPE_VISIBLE_LEVEL
layer = GAS_PIPE_VISIBLE_LAYER
/obj/machinery/atmospherics/pipe/simple/general/visible/layer1
piping_layer = PIPING_LAYER_MIN
pixel_x = -PIPING_LAYER_P_X
@@ -58,7 +58,7 @@ The regular pipe you see everywhere, including bent ones.
piping_layer = PIPING_LAYER_MAX
pixel_x = PIPING_LAYER_P_X
pixel_y = PIPING_LAYER_P_Y
/obj/machinery/atmospherics/pipe/simple/scrubbers
name="scrubbers pipe"
pipe_color=rgb(255,0,0)
@@ -77,7 +77,7 @@ The regular pipe you see everywhere, including bent ones.
piping_layer = PIPING_LAYER_MAX
pixel_x = PIPING_LAYER_P_X
pixel_y = PIPING_LAYER_P_Y
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden
level = PIPE_HIDDEN_LEVEL
@@ -90,7 +90,7 @@ The regular pipe you see everywhere, including bent ones.
piping_layer = PIPING_LAYER_MAX
pixel_x = PIPING_LAYER_P_X
pixel_y = PIPING_LAYER_P_Y
/obj/machinery/atmospherics/pipe/simple/supply
name="air supply pipe"
pipe_color=rgb(0,0,255)
@@ -99,7 +99,7 @@ The regular pipe you see everywhere, including bent ones.
/obj/machinery/atmospherics/pipe/simple/supply/visible
level = PIPE_VISIBLE_LEVEL
layer = GAS_PIPE_VISIBLE_LAYER
/obj/machinery/atmospherics/pipe/simple/supply/visible/layer1
piping_layer = PIPING_LAYER_MIN
pixel_x = -PIPING_LAYER_P_X
@@ -122,7 +122,7 @@ The regular pipe you see everywhere, including bent ones.
piping_layer = PIPING_LAYER_MAX
pixel_x = PIPING_LAYER_P_X
pixel_y = PIPING_LAYER_P_Y
/obj/machinery/atmospherics/pipe/simple/supplymain
name="main air supply pipe"
pipe_color=rgb(130,43,255)
@@ -141,7 +141,7 @@ The regular pipe you see everywhere, including bent ones.
piping_layer = PIPING_LAYER_MAX
pixel_x = PIPING_LAYER_P_X
pixel_y = PIPING_LAYER_P_Y
/obj/machinery/atmospherics/pipe/simple/supplymain/hidden
level = PIPE_HIDDEN_LEVEL
@@ -154,7 +154,7 @@ The regular pipe you see everywhere, including bent ones.
piping_layer = PIPING_LAYER_MAX
pixel_x = PIPING_LAYER_P_X
pixel_y = PIPING_LAYER_P_Y
/obj/machinery/atmospherics/pipe/simple/yellow
pipe_color=rgb(255,198,0)
color=rgb(255,198,0)
@@ -172,7 +172,7 @@ The regular pipe you see everywhere, including bent ones.
piping_layer = PIPING_LAYER_MAX
pixel_x = PIPING_LAYER_P_X
pixel_y = PIPING_LAYER_P_Y
/obj/machinery/atmospherics/pipe/simple/yellow/hidden
level = PIPE_HIDDEN_LEVEL
@@ -185,7 +185,7 @@ The regular pipe you see everywhere, including bent ones.
piping_layer = PIPING_LAYER_MAX
pixel_x = PIPING_LAYER_P_X
pixel_y = PIPING_LAYER_P_Y
/obj/machinery/atmospherics/pipe/simple/cyan
pipe_color=rgb(0,255,249)
color=rgb(0,255,249)
@@ -193,7 +193,7 @@ The regular pipe you see everywhere, including bent ones.
/obj/machinery/atmospherics/pipe/simple/cyan/visible
level = PIPE_VISIBLE_LEVEL
layer = GAS_PIPE_VISIBLE_LAYER
/obj/machinery/atmospherics/pipe/simple/cyan/visible/layer1
piping_layer = PIPING_LAYER_MIN
pixel_x = -PIPING_LAYER_P_X
@@ -206,7 +206,7 @@ The regular pipe you see everywhere, including bent ones.
/obj/machinery/atmospherics/pipe/simple/cyan/hidden
level = PIPE_HIDDEN_LEVEL
/obj/machinery/atmospherics/pipe/simple/cyan/hidden/layer1
piping_layer = PIPING_LAYER_MIN
pixel_x = -PIPING_LAYER_P_X
@@ -224,7 +224,7 @@ The regular pipe you see everywhere, including bent ones.
/obj/machinery/atmospherics/pipe/simple/green/visible
level = PIPE_VISIBLE_LEVEL
layer = GAS_PIPE_VISIBLE_LAYER
/obj/machinery/atmospherics/pipe/simple/green/visible/layer1
piping_layer = PIPING_LAYER_MIN
pixel_x = -PIPING_LAYER_P_X
@@ -237,7 +237,7 @@ The regular pipe you see everywhere, including bent ones.
/obj/machinery/atmospherics/pipe/simple/green/hidden
level = PIPE_HIDDEN_LEVEL
/obj/machinery/atmospherics/pipe/simple/green/hidden/layer1
piping_layer = PIPING_LAYER_MIN
pixel_x = -PIPING_LAYER_P_X
@@ -255,7 +255,7 @@ The regular pipe you see everywhere, including bent ones.
/obj/machinery/atmospherics/pipe/simple/orange/visible
level = PIPE_VISIBLE_LEVEL
layer = GAS_PIPE_VISIBLE_LAYER
/obj/machinery/atmospherics/pipe/simple/orange/visible/layer1
piping_layer = PIPING_LAYER_MIN
pixel_x = -PIPING_LAYER_P_X
@@ -268,7 +268,7 @@ The regular pipe you see everywhere, including bent ones.
/obj/machinery/atmospherics/pipe/simple/orange/hidden
level = PIPE_HIDDEN_LEVEL
/obj/machinery/atmospherics/pipe/simple/orange/hidden/layer1
piping_layer = PIPING_LAYER_MIN
pixel_x = -PIPING_LAYER_P_X
@@ -286,7 +286,7 @@ The regular pipe you see everywhere, including bent ones.
/obj/machinery/atmospherics/pipe/simple/purple/visible
level = PIPE_VISIBLE_LEVEL
layer = GAS_PIPE_VISIBLE_LAYER
/obj/machinery/atmospherics/pipe/simple/purple/visible/layer1
piping_layer = PIPING_LAYER_MIN
pixel_x = -PIPING_LAYER_P_X
@@ -309,7 +309,7 @@ The regular pipe you see everywhere, including bent ones.
piping_layer = PIPING_LAYER_MAX
pixel_x = PIPING_LAYER_P_X
pixel_y = PIPING_LAYER_P_Y
/obj/machinery/atmospherics/pipe/simple/dark
pipe_color=rgb(69,69,69)
color=rgb(69,69,69)
@@ -317,7 +317,7 @@ The regular pipe you see everywhere, including bent ones.
/obj/machinery/atmospherics/pipe/simple/dark/visible
level = PIPE_VISIBLE_LEVEL
layer = GAS_PIPE_VISIBLE_LAYER
/obj/machinery/atmospherics/pipe/simple/dark/visible/layer1
piping_layer = PIPING_LAYER_MIN
pixel_x = -PIPING_LAYER_P_X
@@ -340,7 +340,7 @@ The regular pipe you see everywhere, including bent ones.
piping_layer = PIPING_LAYER_MAX
pixel_x = PIPING_LAYER_P_X
pixel_y = PIPING_LAYER_P_Y
/obj/machinery/atmospherics/pipe/simple/violet
pipe_color=rgb(64,0,128)
color=rgb(64,0,128)
@@ -348,7 +348,7 @@ The regular pipe you see everywhere, including bent ones.
/obj/machinery/atmospherics/pipe/simple/violet/visible
level = PIPE_VISIBLE_LEVEL
layer = GAS_PIPE_VISIBLE_LAYER
/obj/machinery/atmospherics/pipe/simple/violet/visible/layer1
piping_layer = PIPING_LAYER_MIN
pixel_x = -PIPING_LAYER_P_X
@@ -371,7 +371,7 @@ The regular pipe you see everywhere, including bent ones.
piping_layer = PIPING_LAYER_MAX
pixel_x = PIPING_LAYER_P_X
pixel_y = PIPING_LAYER_P_Y
/obj/machinery/atmospherics/pipe/simple/brown
pipe_color=rgb(178,100,56)
color=rgb(178,100,56)
@@ -379,7 +379,7 @@ The regular pipe you see everywhere, including bent ones.
/obj/machinery/atmospherics/pipe/simple/brown/visible
level = PIPE_VISIBLE_LEVEL
layer = GAS_PIPE_VISIBLE_LAYER
/obj/machinery/atmospherics/pipe/simple/brown/visible/layer1
piping_layer = PIPING_LAYER_MIN
pixel_x = -PIPING_LAYER_P_X
+11
View File
@@ -73,6 +73,17 @@
crate_name = "atmospherics hardsuit"
crate_type = /obj/structure/closet/crate/secure/engineering
/datum/supply_pack/engineering/radhardsuit
name = "Radiation Hardsuit"
desc = "The Singulo is loose? Do you need to do a few changes to its containment and don't want to spent the rest of the shift under the shower? Get this Radiation Hardsuit! It protect from radiations and space only."
cost = 3500
access = ACCESS_ENGINE
contains = list(/obj/item/tank/internals/air,
/obj/item/clothing/mask/gas,
/obj/item/clothing/suit/space/hardsuit/engine/rad)
crate_name = "radiation hardsuit"
crate_type = /obj/structure/closet/crate/secure/engineering
/datum/supply_pack/engineering/industrialrcd
name = "Industrial RCD"
desc = "An industrial RCD in case the station has gone through more then one meteor storm and the CE needs to bring out the somthing a bit more reliable. Does not contain spare ammo for the industrial RCD or any other RCD models."
@@ -203,6 +203,31 @@
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/engine/atmos
//Radiation
/obj/item/clothing/head/helmet/space/hardsuit/engine/rad
name = "radiation hardsuit helmet"
desc = "A special helmet that protects against radiation and space. Not much else unfortunately."
icon_state = "cespace_helmet"
item_state = "nothing"
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = 0, "acid" = 0)
item_color = "engineering"
resistance_flags = FIRE_PROOF
rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE
actions_types = list()
/obj/item/clothing/suit/space/hardsuit/engine/rad
name = "radiation hardsuit"
desc = "A special suit that protects against radiation and space. Not much else unfortunately."
icon_state = "hardsuit-rad"
item_state = "nothing"
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = 0, "acid" = 0)
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/engine/rad
resistance_flags = FIRE_PROOF
rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE
mutantrace_variation = NONE
/obj/item/clothing/head/helmet/space/hardsuit/engine/rad/attack_self()
return //Sprites required for flashlight
//Chief Engineer's hardsuit
/obj/item/clothing/head/helmet/space/hardsuit/engine/elite
+1
View File
@@ -90,6 +90,7 @@
return ..()
if(istype(Proj , /obj/item/projectile/energy/floramut))
mutate()
return BULLET_ACT_HIT
else if(istype(Proj , /obj/item/projectile/energy/florayield))
return myseed.bullet_act(Proj)
else
+1
View File
@@ -145,6 +145,7 @@ obj/item/seeds/proc/is_gene_forbidden(typepath)
adjust_yield(1 * rating)
else if(prob(1/(yield * yield) * 100))//This formula gives you diminishing returns based on yield. 100% with 1 yield, decreasing to 25%, 11%, 6, 4, 2...
adjust_yield(1 * rating)
return BULLET_ACT_HIT
else
return ..()
@@ -1,90 +1,4 @@
//Landmarks and other helpers which speed up the mapping process and reduce the number of unique instances/subtypes of items/turf/ect
/obj/effect/baseturf_helper //Set the baseturfs of every turf in the /area/ it is placed.
name = "baseturf editor"
icon = 'icons/effects/mapping_helpers.dmi'
icon_state = ""
var/list/baseturf_to_replace
var/baseturf
layer = POINT_LAYER
/obj/effect/baseturf_helper/Initialize()
. = ..()
return INITIALIZE_HINT_LATELOAD
/obj/effect/baseturf_helper/LateInitialize()
if(!baseturf_to_replace)
baseturf_to_replace = typecacheof(list(/turf/open/space,/turf/baseturf_bottom))
else if(!length(baseturf_to_replace))
baseturf_to_replace = list(baseturf_to_replace = TRUE)
else if(baseturf_to_replace[baseturf_to_replace[1]] != TRUE) // It's not associative
var/list/formatted = list()
for(var/i in baseturf_to_replace)
formatted[i] = TRUE
baseturf_to_replace = formatted
var/area/our_area = get_area(src)
for(var/i in get_area_turfs(our_area, z))
replace_baseturf(i)
qdel(src)
/obj/effect/baseturf_helper/proc/replace_baseturf(turf/thing)
var/list/baseturf_cache = thing.baseturfs
if(length(baseturf_cache))
for(var/i in baseturf_cache)
if(baseturf_to_replace[i])
baseturf_cache -= i
if(!baseturf_cache.len)
thing.assemble_baseturfs(baseturf)
else
thing.PlaceOnBottom(null, baseturf)
else if(baseturf_to_replace[thing.baseturfs])
thing.assemble_baseturfs(baseturf)
else
thing.PlaceOnBottom(null, baseturf)
/obj/effect/baseturf_helper/space
name = "space baseturf editor"
baseturf = /turf/open/space
/obj/effect/baseturf_helper/asteroid
name = "asteroid baseturf editor"
baseturf = /turf/open/floor/plating/asteroid
/obj/effect/baseturf_helper/asteroid/airless
name = "asteroid airless baseturf editor"
baseturf = /turf/open/floor/plating/asteroid/airless
/obj/effect/baseturf_helper/asteroid/basalt
name = "asteroid basalt baseturf editor"
baseturf = /turf/open/floor/plating/asteroid/basalt
/obj/effect/baseturf_helper/asteroid/snow
name = "asteroid snow baseturf editor"
baseturf = /turf/open/floor/plating/asteroid/snow
/obj/effect/baseturf_helper/beach/sand
name = "beach sand baseturf editor"
baseturf = /turf/open/floor/plating/beach/sand
/obj/effect/baseturf_helper/beach/water
name = "water baseturf editor"
baseturf = /turf/open/floor/plating/beach/water
/obj/effect/baseturf_helper/lava
name = "lava baseturf editor"
baseturf = /turf/open/lava/smooth
/obj/effect/baseturf_helper/lava_land/surface
name = "lavaland baseturf editor"
baseturf = /turf/open/lava/smooth/lava_land_surface
/obj/effect/mapping_helpers
icon = 'icons/effects/mapping_helpers.dmi'
icon_state = ""
@@ -94,7 +8,6 @@
..()
return late ? INITIALIZE_HINT_LATELOAD : INITIALIZE_HINT_QDEL
//airlock helpers
/obj/effect/mapping_helpers/airlock
layer = DOOR_HELPER_LAYER
@@ -0,0 +1,82 @@
/obj/effect/baseturf_helper //Set the baseturfs of every turf in the /area/ it is placed.
name = "baseturf editor"
icon = 'icons/effects/mapping_helpers.dmi'
icon_state = ""
var/list/baseturf_to_replace
var/baseturf
layer = POINT_LAYER
/obj/effect/baseturf_helper/Initialize()
. = ..()
return INITIALIZE_HINT_LATELOAD
/obj/effect/baseturf_helper/LateInitialize()
if(!baseturf_to_replace)
baseturf_to_replace = typecacheof(list(/turf/open/space,/turf/baseturf_bottom))
else if(!length(baseturf_to_replace))
baseturf_to_replace = list(baseturf_to_replace = TRUE)
else if(baseturf_to_replace[baseturf_to_replace[1]] != TRUE) // It's not associative
var/list/formatted = list()
for(var/i in baseturf_to_replace)
formatted[i] = TRUE
baseturf_to_replace = formatted
var/area/our_area = get_area(src)
for(var/i in get_area_turfs(our_area, z))
replace_baseturf(i)
qdel(src)
/obj/effect/baseturf_helper/proc/replace_baseturf(turf/thing)
var/list/baseturf_cache = thing.baseturfs
if(length(baseturf_cache))
for(var/i in baseturf_cache)
if(baseturf_to_replace[i])
baseturf_cache -= i
if(!baseturf_cache.len)
thing.assemble_baseturfs(baseturf)
else
thing.PlaceOnBottom(null, baseturf)
else if(baseturf_to_replace[thing.baseturfs])
thing.assemble_baseturfs(baseturf)
else
thing.PlaceOnBottom(null, baseturf)
/obj/effect/baseturf_helper/space
name = "space baseturf editor"
baseturf = /turf/open/space
/obj/effect/baseturf_helper/asteroid
name = "asteroid baseturf editor"
baseturf = /turf/open/floor/plating/asteroid
/obj/effect/baseturf_helper/asteroid/airless
name = "asteroid airless baseturf editor"
baseturf = /turf/open/floor/plating/asteroid/airless
/obj/effect/baseturf_helper/asteroid/basalt
name = "asteroid basalt baseturf editor"
baseturf = /turf/open/floor/plating/asteroid/basalt
/obj/effect/baseturf_helper/asteroid/snow
name = "asteroid snow baseturf editor"
baseturf = /turf/open/floor/plating/asteroid/snow
/obj/effect/baseturf_helper/beach/sand
name = "beach sand baseturf editor"
baseturf = /turf/open/floor/plating/beach/sand
/obj/effect/baseturf_helper/beach/water
name = "water baseturf editor"
baseturf = /turf/open/floor/plating/beach/water
/obj/effect/baseturf_helper/lava
name = "lava baseturf editor"
baseturf = /turf/open/lava/smooth
/obj/effect/baseturf_helper/lava_land/surface
name = "lavaland baseturf editor"
baseturf = /turf/open/lava/smooth/lava_land_surface
@@ -0,0 +1,43 @@
//Builds networks like power cables/atmos lines/etc
//Just a holder parent type for now..
/obj/effect/mapping_helpers/network_builder
/// set var to true to not del on lateload
var/custom_spawned = FALSE
icon = 'icons/effects/mapping_helpers.dmi'
late = TRUE
/// what directions we know connections are in
var/list/network_directions = list()
/obj/effect/mapping_helpers/network_builder/Initialize(mapload)
. = ..()
to_chat(world, "DEBUG: Initializing [COORD(src)]")
var/conflict = check_duplicates()
if(conflict)
stack_trace("WARNING: [type] network building helper found check_duplicates() conflict [conflict] in its location.!")
return INITIALIZE_HINT_QDEL
if(!mapload)
if(GLOB.Debug2)
custom_spawned = TRUE
return INITIALIZE_HINT_NORMAL
else
return INITIALIZE_HINT_QDEL
return INITIALIZE_HINT_LATELOAD
/// How this works: On LateInitialize, detect all directions that this should be applicable to, and do what it needs to do, and then inform all network builders in said directions that it's been around since it won't be around afterwards.
/obj/effect/mapping_helpers/network_builder/LateInitialize()
to_chat(world, "DEBUG: LateInitializing [COORD(src)]")
scan_directions()
build_network()
if(!custom_spawned)
qdel(src)
/obj/effect/mapping_helpers/network_builder/proc/check_duplicates()
CRASH("Base abstract network builder tried to check duplicates.")
/obj/effect/mapping_helpers/network_builder/proc/scan_directions()
CRASH("Base abstract network builder tried to scan directions.")
/obj/effect/mapping_helpers/network_builder/proc/build_network()
CRASH("Base abstract network builder tried to build network.")
@@ -0,0 +1,96 @@
/* Automatically places pipes on init based on any pipes connecting to it and adjacent helpers. Only supports cardinals.
* Conflicts with ANY PIPE ON ITS LAYER, as well as atmos network build helpers on the same layer, as well as any pipe on all layers. Do those manually.
*/
/obj/effect/mapping_helpers/network_builder/atmos_pipe
name = "atmos pipe autobuilder"
icon_state = "atmospipebuilder"
/// Layer to put our pipes on
var/pipe_layer = PIPING_LAYER_DEFAULT
/// Color to set our pipes to
var/pipe_color
/// Whether or not pipes we make are visible
var/visible_pipes = FALSE
color = null
/obj/effect/mapping_helpers/network_builder/atmos_pipe/check_duplicates()
for(var/obj/effect/mapping_helpers/network_builder/atmos_pipe/other in loc)
if(other == src)
continue
if(other.pipe_layer == pipe_layer)
return other
for(var/obj/machinery/atmospherics/A in loc)
if(A.pipe_flags & PIPING_ALL_LAYER)
return A
if(A.piping_layer == pipe_layer)
return A
return FALSE
/// Scans directions, sets network_directions to have every direction that we can link to. If there's another power cable builder detected, make sure they know we're here by adding us to their cable directions list before we're deleted.
/obj/effect/mapping_helpers/network_builder/atmos_pipe/scan_directions()
var/turf/T
for(var/i in GLOB.cardinals)
if(i in network_directions)
continue //we're already set, that means another builder set us.
T = get_step(loc, i)
if(!T)
continue
var/found = FALSE
for(var/obj/effect/mapping_helpers/network_builder/atmos_pipe/other in T)
if(other.pipe_layer == pipe_layer)
network_directions += i
other.network_directions += turn(i, 180)
found = TRUE
break
if(found)
continue
for(var/obj/machinery/atmospherics/A in T)
if((A.piping_layer == pipe_layer) && (A.initialize_directions & turn(i, 180)))
network_directions += i
break
return network_directions
/// Directions should only ever have cardinals.
/obj/effect/mapping_helpers/network_builder/atmos_pipe/build_network()
if(length(network_directions) <= 1)
return
var/obj/machinery/atmospherics/pipe/built
switch(length(network_directions))
if(2) //straight pipe
built = new /obj/machinery/atmospherics/pipe/simple(loc)
var/d1 = network_directions[1]
var/d2 = network_directions[2]
var/combined = d1 | d2
if(combined in GLOB.diagonals)
built.setDir(combined)
else
built.setDir(d1)
if(3) //manifold
var/list/missing = network_directions ^ GLOB.cardinals
missing = missing[1]
built = new /obj/machinery/atmospherics/pipe/manifold(loc)
built.setDir(missing)
if(4) //4 way manifold
built = new /obj/machinery/atmospherics/pipe/manifold4w(loc)
built.SetInitDirections()
built.on_construction(pipe_color, pipe_layer)
built.hide(!visible_pipes)
/obj/effect/mapping_helpers/network_builder/atmos_pipe/distro
name = "distro line autobuilder"
pipe_layer = PIPING_LAYER_MIN
pixel_x = -PIPING_LAYER_P_X
pixel_y = -PIPING_LAYER_P_Y
pipe_color = rgb(130,43,255)
color = rgb(130,43,255)
/obj/effect/mapping_helpers/network_builder/atmos_pipe/scrubbers
name = "scrubbers line autobuilder"
pipe_layer = PIPING_LAYER_MAX
pixel_x = PIPING_LAYER_P_X
pixel_y = PIPING_LAYER_P_Y
pipe_color = rgb(255,0,0)
color = rgb(255,0,0)
@@ -0,0 +1,189 @@
#define NO_KNOT 0
#define KNOT_AUTO 1
#define KNOT_FORCED 2
/// Automatically links on init to power cables and other cable builder helpers. Only supports cardinals.
/obj/effect/mapping_helpers/network_builder/power_cable
name = "power line autobuilder"
icon_state = "powerlinebuilder"
color = "#ff0000"
/// Whether or not we forcefully make a knot
var/knot = NO_KNOT
/// cable color as from GLOB.cable_colors
var/cable_color = "red"
/obj/effect/mapping_helpers/network_builder/power_cable/check_duplicates()
var/obj/structure/cable/C = locate() in loc
if(C)
return C
for(var/obj/effect/mapping_helpers/network_builder/power_cable/other in loc)
if(other == src)
continue
return other
/// Scans directions, sets network_directions to have every direction that we can link to. If there's another power cable builder detected, make sure they know we're here by adding us to their cable directions list before we're deleted.
/obj/effect/mapping_helpers/network_builder/power_cable/scan_directions()
var/turf/T
for(var/i in GLOB.cardinals)
if(i in network_directions)
continue //we're already set, that means another builder set us.
T = get_step(loc, i)
if(!T)
continue
var/obj/effect/mapping_helpers/network_builder/power_cable/other = locate() in T
if(other)
network_directions += i
other.network_directions += turn(i, 180)
continue
for(var/obj/structure/cable/C in T)
if(C.d1 == turn(i, 180) || C.d2 == turn(i, 180))
network_directions += i
continue
return network_directions
/// Directions should only ever have cardinals.
/obj/effect/mapping_helpers/network_builder/power_cable/build_network()
if(!length(network_directions))
return
else if(length(network_directions) == 1)
new /obj/structure/cable(loc, cable_color, NONE, network_directions[1])
else
if(knot == KNOT_FORCED)
for(var/d in network_directions)
new /obj/structure/cable(loc, cable_color, NONE, d)
else
var/do_knot = (knot == KNOT_FORCED) || ((knot == KNOT_AUTO) && should_auto_knot())
var/dirs = length(network_directions)
for(var/i in 1 to dirs - 1)
var/li = (i == 1)? dirs : (i - 1)
var/d1 = network_directions[i]
var/d2 = network_directions[li]
if(d1 > d2) //this is ugly please help me
d1 = network_directions[li]
d2 = network_directions[i]
new /obj/structure/cable(loc, cable_color, d1, d2)
if(do_knot)
new /obj/structure/cable(loc, cable_color, NONE, network_directions[i])
do_knot = FALSE
/obj/effect/mapping_helpers/network_builder/power_cable/proc/should_auto_knot()
return (locate(/obj/machinery/power/terminal) in loc)
/obj/effect/mapping_helpers/network_builder/power_cable/knot
icon_state = "powerlinebuilderknot"
knot = KNOT_FORCED
/obj/effect/mapping_helpers/network_builder/power_cable/auto
icon_state = "powerlinebuilderauto"
knot = KNOT_AUTO
// Red
/obj/effect/mapping_helpers/network_builder/power_cable/red
color = "#ff0000"
cable_color = "red"
/obj/effect/mapping_helpers/network_builder/power_cable/red/knot
icon_state = "powerlinebuilderknot"
knot = KNOT_FORCED
/obj/effect/mapping_helpers/network_builder/power_cable/red/auto
icon_state = "powerlinebuilderauto"
knot = KNOT_AUTO
// White
/obj/effect/mapping_helpers/network_builder/power_cable/white
color = "#ffffff"
cable_color = "white"
/obj/effect/mapping_helpers/network_builder/power_cable/white/knot
icon_state = "powerlinebuilderknot"
knot = KNOT_FORCED
/obj/effect/mapping_helpers/network_builder/power_cable/white/auto
icon_state = "powerlinebuilderauto"
knot = KNOT_AUTO
// Cyan
/obj/effect/mapping_helpers/network_builder/power_cable/cyan
color = "#00ffff"
cable_color = "cyan"
/obj/effect/mapping_helpers/network_builder/power_cable/cyan/knot
icon_state = "powerlinebuilderknot"
knot = KNOT_FORCED
/obj/effect/mapping_helpers/network_builder/power_cable/cyan/auto
icon_state = "powerlinebuilderauto"
knot = KNOT_AUTO
// Orange
/obj/effect/mapping_helpers/network_builder/power_cable/orange
color = "#ff8000"
cable_color = "orange"
/obj/effect/mapping_helpers/network_builder/power_cable/orange/knot
icon_state = "powerlinebuilderknot"
knot = KNOT_FORCED
/obj/effect/mapping_helpers/network_builder/power_cable/orange/auto
icon_state = "powerlinebuilderauto"
knot = KNOT_AUTO
// Pink
/obj/effect/mapping_helpers/network_builder/power_cable/pink
color = "#ff3cc8"
cable_color = "pink"
/obj/effect/mapping_helpers/network_builder/power_cable/pink/knot
icon_state = "powerlinebuilderknot"
knot = KNOT_FORCED
/obj/effect/mapping_helpers/network_builder/power_cable/pink/auto
icon_state = "powerlinebuilderauto"
knot = KNOT_AUTO
// Blue
/obj/effect/mapping_helpers/network_builder/power_cable/blue
color = "#1919c8"
cable_color = "blue"
/obj/effect/mapping_helpers/network_builder/power_cable/blue/knot
icon_state = "powerlinebuilderknot"
knot = KNOT_FORCED
/obj/effect/mapping_helpers/network_builder/power_cable/blue/auto
icon_state = "powerlinebuilderauto"
knot = KNOT_AUTO
// Green
/obj/effect/mapping_helpers/network_builder/power_cable/green
color = "#00aa00"
cable_color = "green"
/obj/effect/mapping_helpers/network_builder/power_cable/green/knot
icon_state = "powerlinebuilderknot"
knot = KNOT_FORCED
/obj/effect/mapping_helpers/network_builder/power_cable/green/auto
icon_state = "powerlinebuilderauto"
knot = KNOT_AUTO
// Yellow
/obj/effect/mapping_helpers/network_builder/power_cable/yellow
color = "#ffff00"
cable_color = "yellow"
/obj/effect/mapping_helpers/network_builder/power_cable/yellow/knot
icon_state = "powerlinebuilderknot"
knot = KNOT_FORCED
/obj/effect/mapping_helpers/network_builder/power_cable/yellow/auto
icon_state = "powerlinebuilderauto"
knot = KNOT_AUTO
#undef NO_KNOT
#undef KNOT_AUTO
#undef KNOT_FORCED
+1 -1
View File
@@ -250,7 +250,7 @@ GLOBAL_LIST_INIT(sand_recipes, list(\
/obj/item/twohanded/required/gibtonite/bullet_act(obj/item/projectile/P)
GibtoniteReaction(P.firer)
..()
return ..()
/obj/item/twohanded/required/gibtonite/ex_act()
GibtoniteReaction(null, 1)
+1 -1
View File
@@ -14,7 +14,7 @@
/obj/effect/dummy/phased_mob/slaughter/ex_act()
return
/obj/effect/dummy/phased_mob/slaughter/bullet_act()
return
return BULLET_ACT_FORCE_PIERCE
/obj/effect/dummy/phased_mob/slaughter/singularity_act()
return
@@ -51,7 +51,7 @@
if(prob(mind.martial_art.dodge_chance))
var/dodgemessage = pick("dodges under the projectile!","dodges to the right of the projectile!","jumps over the projectile!")
visible_message("<span class='danger'>[src] [dodgemessage]</span>", "<span class='userdanger'>You dodge the projectile!</span>")
return -1
return BULLET_ACT_BLOCK
if(mind.martial_art && !incapacitated(FALSE, TRUE) && mind.martial_art.can_use(src) && mind.martial_art.deflection_chance) //Some martial arts users can deflect projectiles!
if(prob(mind.martial_art.deflection_chance))
if(!lying && dna && !dna.check_mutation(HULK)) //But only if they're not lying down, and hulks can't do it
@@ -60,12 +60,10 @@
else
visible_message("<span class='danger'>[src] deflects the projectile!</span>", "<span class='userdanger'>You deflect the projectile!</span>")
playsound(src, pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), 75, 1)
if(!mind.martial_art.reroute_deflection)
return FALSE
else
if(mind.martial_art.reroute_deflection)
P.firer = src
P.setAngle(rand(0, 360))//SHING
return FALSE
return BULLET_ACT_FORCE_PIERCE
return ..()
@@ -1998,7 +1998,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
/datum/species/proc/bullet_act(obj/item/projectile/P, mob/living/carbon/human/H)
// called before a projectile hit
return 0
return
/////////////
//BREATHING//
@@ -360,8 +360,8 @@
playsound(H, 'sound/effects/shovel_dig.ogg', 70, 1)
H.visible_message("<span class='danger'>The [P.name] sinks harmlessly in [H]'s sandy body!</span>", \
"<span class='userdanger'>The [P.name] sinks harmlessly in [H]'s sandy body!</span>")
return 2
return 0
return BULLET_ACT_BLOCK
return ..()
//Reflects lasers and resistant to burn damage, but very vulnerable to brute damage. Shatters on death.
/datum/species/golem/glass
@@ -397,8 +397,8 @@
var/turf/target = get_turf(P.starting)
// redirect the projectile
P.preparePixelProjectile(locate(CLAMP(target.x + new_x, 1, world.maxx), CLAMP(target.y + new_y, 1, world.maxy), H.z), H)
return -1
return 0
return BULLET_ACT_FORCE_PIERCE
return ..()
//Teleports when hit or when it wants to
/datum/species/golem/bluespace
@@ -60,8 +60,8 @@
if(light_amount < SHADOW_SPECIES_LIGHT_THRESHOLD)
H.visible_message("<span class='danger'>[H] dances in the shadows, evading [P]!</span>")
playsound(T, "bullet_miss", 75, 1)
return -1
return 0
return BULLET_ACT_FORCE_PIERCE
return ..()
/datum/species/shadow/nightmare/check_roundstart_eligible()
return FALSE
@@ -403,7 +403,7 @@
if((Proj.damage_type == BURN) || (Proj.damage_type == BRUTE))
if(!Proj.nodamage && Proj.damage < src.health && isliving(Proj.firer))
retaliate(Proj.firer)
..()
return ..()
/mob/living/carbon/monkey/hitby(atom/movable/AM, skipcatch = FALSE, hitpush = TRUE, blocked = FALSE)
if(istype(AM, /obj/item))
+2 -2
View File
@@ -110,7 +110,7 @@
/mob/living/proc/apply_effects(stun = 0, knockdown = 0, unconscious = 0, irradiate = 0, slur = 0, stutter = 0, eyeblur = 0, drowsy = 0, blocked = FALSE, stamina = 0, jitter = 0, kd_stamoverride, kd_stammax)
if(blocked >= 100)
return 0
return BULLET_ACT_BLOCK
if(stun)
apply_effect(stun, EFFECT_STUN, blocked)
if(knockdown)
@@ -131,7 +131,7 @@
apply_damage(stamina, STAMINA, null, blocked)
if(jitter)
apply_effect(jitter, EFFECT_JITTER, blocked)
return 1
return BULLET_ACT_HIT
/mob/living/proc/getBruteLoss()
+4 -4
View File
@@ -34,7 +34,7 @@
return FALSE
/mob/living/proc/on_hit(obj/item/projectile/P)
return
return BULLET_ACT_HIT
/mob/living/proc/check_shields(atom/AM, damage, attack_text = "the attack", attack_type = MELEE_ATTACK, armour_penetration = 0)
var/block_chance_modifier = round(damage / -3)
@@ -76,16 +76,16 @@
/mob/living/bullet_act(obj/item/projectile/P, def_zone)
if(P.original != src || P.firer != src) //try to block or reflect the bullet, can't do so when shooting oneself
if(reflect_bullet_check(P, def_zone))
return -1 // complete projectile permutation
return BULLET_ACT_FORCE_PIERCE // complete projectile permutation
if(check_shields(P, P.damage, "the [P.name]", PROJECTILE_ATTACK, P.armour_penetration))
P.on_hit(src, 100, def_zone)
return 2
return BULLET_ACT_BLOCK
var/armor = run_armor_check(def_zone, P.flag, null, null, P.armour_penetration, null)
if(!P.nodamage)
apply_damage(P.damage, P.damage_type, def_zone, armor)
if(P.dismemberment)
check_projectile_dismemberment(P, def_zone)
return P.on_hit(src, armor)
return P.on_hit(src, armor) ? BULLET_ACT_HIT : BULLET_ACT_BLOCK
/mob/living/proc/check_projectile_dismemberment(obj/item/projectile/P, def_zone)
return 0
@@ -2,6 +2,21 @@
. = ..()
update_turf_movespeed(loc)
/mob/living/CanPass(atom/movable/mover, turf/target)
if((mover.pass_flags & PASSMOB))
return TRUE
if(istype(mover, /obj/item/projectile))
var/obj/item/projectile/P = mover
return !P.can_hit_target(src, P.permutated, src == P.original, TRUE)
if(mover.throwing)
return (!density || lying)
if(buckled == mover)
return TRUE
if(ismob(mover))
if (mover in buckled_mobs)
return TRUE
return (!mover.density || !density || lying || (mover.throwing && mover.throwing.thrower == src && !ismob(mover)))
/mob/living/toggle_move_intent()
. = ..()
update_move_intent_slowdown()
@@ -42,9 +42,8 @@
/mob/living/silicon/ai/bullet_act(obj/item/projectile/Proj)
..(Proj)
. = ..()
updatehealth()
return 2
/mob/living/silicon/ai/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0)
return // no eyes, no flashing
@@ -55,7 +55,7 @@
if(P.stun)
fold_in(force = TRUE)
visible_message("<span class='warning'>The electrically-charged projectile disrupts [src]'s holomatrix, forcing [src] to fold in!</span>")
. = ..()
return ..()
/mob/living/silicon/pai/stripPanelUnequip(obj/item/what, mob/who, where) //prevents stripping
to_chat(src, "<span class='warning'>Your holochassis stutters and warps intensely as you attempt to interact with the object, forcing you to cease lest the field fail.</span>")
@@ -184,8 +184,7 @@
adjustBruteLoss(30)
/mob/living/silicon/robot/bullet_act(obj/item/projectile/P, def_zone)
..()
. = ..()
updatehealth()
if(prob(75) && P.damage > 0)
spark_system.start()
return 2
@@ -129,7 +129,7 @@
unbuckle_mob(M)
M.visible_message("<span class='boldwarning'>[M] is knocked off of [src] by the [P]!</span>")
P.on_hit(src)
return 2
return BULLET_ACT_HIT
/mob/living/silicon/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /obj/screen/fullscreen/flash/static)
if(affect_silicon)
@@ -114,7 +114,7 @@
return
apply_damage(Proj.damage, Proj.damage_type)
Proj.on_hit(src)
return 0
return BULLET_ACT_HIT
/mob/living/simple_animal/ex_act(severity, target, origin)
if(origin && istype(origin, /datum/spacevine_mutation) && isvineimmune(src))
@@ -21,7 +21,7 @@
/mob/living/simple_animal/bot/secbot/grievous/bullet_act(obj/item/projectile/P)
visible_message("[src] deflects [P] with its energy swords!")
playsound(src, 'sound/weapons/blade1.ogg', 50, TRUE)
return FALSE
return BULLET_ACT_BLOCK
/mob/living/simple_animal/bot/secbot/grievous/Crossed(atom/movable/AM)
..()
@@ -210,7 +210,7 @@ Auto Patrol[]"},
if((Proj.damage_type == BURN) || (Proj.damage_type == BRUTE))
if(!Proj.nodamage && Proj.damage < src.health && ishuman(Proj.firer))
retaliate(Proj.firer)
..()
return ..()
/mob/living/simple_animal/bot/ed209/handle_automated_action()
if(!..())
@@ -510,11 +510,9 @@ Auto Patrol[]"},
spawn(100)
disabled = 0
icon_state = "[lasercolor]ed2091"
return 1
else
..(Proj)
else
..(Proj)
return BULLET_ACT_HIT
return ..()
return ..()
/mob/living/simple_animal/bot/ed209/bluetag
lasercolor = "b"
@@ -139,7 +139,7 @@ Maintenance panel panel is [open ? "opened" : "closed"]"},
/mob/living/simple_animal/bot/honkbot/bullet_act(obj/item/projectile/Proj)
if((istype(Proj,/obj/item/projectile/beam)) || (istype(Proj,/obj/item/projectile/bullet) && (Proj.damage_type == BURN))||(Proj.damage_type == BRUTE) && (!Proj.nodamage && Proj.damage < health && ishuman(Proj.firer)))
retaliate(Proj.firer)
..()
return ..()
/mob/living/simple_animal/bot/honkbot/UnarmedAttack(atom/A)
if(!on)
@@ -152,7 +152,7 @@
/mob/living/simple_animal/bot/mulebot/bullet_act(obj/item/projectile/Proj)
. = ..()
if(. && !QDELETED(src)) //Got hit and not blown up yet.
if(. == BULLET_ACT_HIT && !QDELETED(src)) //Got hit and not blown up yet.)
if(prob(50) && !isnull(load))
unload(0)
if(prob(25))
@@ -205,7 +205,7 @@ Auto Patrol: []"},
if((Proj.damage_type == BURN) || (Proj.damage_type == BRUTE))
if(!Proj.nodamage && Proj.damage < src.health && ishuman(Proj.firer))
retaliate(Proj.firer)
..()
return ..()
/mob/living/simple_animal/bot/secbot/UnarmedAttack(atom/A)
@@ -167,9 +167,9 @@
new_angle_s -= 360
P.setAngle(new_angle_s)
return -1 // complete projectile permutation
return BULLET_ACT_FORCE_PIERCE // complete projectile permutation
return (..(P))
return ..()
@@ -117,7 +117,7 @@ Difficulty: Very Hard
var/random_y = rand(0, 72)
AT.pixel_y += random_y
..()
return ..()
/mob/living/simple_animal/hostile/megafauna/colossus/proc/enrage(mob/living/L)
if(ishuman(L))
@@ -395,7 +395,7 @@ Difficulty: Very Hard
..()
/obj/machinery/anomalous_crystal/bullet_act(obj/item/projectile/P, def_zone)
..()
. = ..()
if(istype(P, /obj/item/projectile/magic))
ActivationReaction(P.firer, ACTIVATE_MAGIC, P.damage_type)
return
@@ -98,7 +98,7 @@ IGNORE_PROC_IF_NOT_TARGET(attack_slime)
/mob/living/simple_animal/hostile/asteroid/curseblob/bullet_act(obj/item/projectile/Proj)
if(Proj.firer != set_target)
return
return BULLET_ACT_FORCE_PIERCE
return ..()
/mob/living/simple_animal/hostile/asteroid/curseblob/attacked_by(obj/item/I, mob/living/L)
@@ -75,7 +75,7 @@
/mob/living/simple_animal/hostile/asteroid/goldgrub/bullet_act(obj/item/projectile/P)
visible_message("<span class='danger'>The [P.name] was repelled by [name]'s girth!</span>")
return
return BULLET_ACT_BLOCK
/mob/living/simple_animal/hostile/asteroid/goldgrub/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
vision_range = 9
@@ -43,7 +43,7 @@
if(P.damage < 30 && P.damage_type != BRUTE)
P.damage = (P.damage / 3)
visible_message("<span class='danger'>[P] has a reduced effect on [src]!</span>")
..()
return ..()
/mob/living/simple_animal/hostile/asteroid/hitby(atom/movable/AM)//No floor tiling them to death, wiseguy
if(istype(AM, /obj/item))
@@ -179,9 +179,10 @@
if(T.throwforce)
Bruise()
/mob/living/simple_animal/hostile/mushroom/bullet_act()
..()
Bruise()
/mob/living/simple_animal/hostile/mushroom/bullet_act(obj/item/projectile/P)
. = ..()
if(!P.nodamage)
Bruise()
/mob/living/simple_animal/hostile/mushroom/harvest()
var/counter
@@ -128,13 +128,10 @@
return ..()
/mob/living/simple_animal/hostile/syndicate/melee/bullet_act(obj/item/projectile/Proj)
if(!Proj)
return
if(prob(25))
return ..()
else
visible_message("<span class='danger'>[src] blocks [Proj] with its shield!</span>")
return 0
visible_message("<span class='danger'>[src] blocks [Proj] with its shield!</span>")
return BULLET_ACT_BLOCK
/mob/living/simple_animal/hostile/syndicate/melee/sword/space
icon_state = "syndicate_space_sword"
@@ -337,7 +337,7 @@
//Bullets
/mob/living/simple_animal/parrot/bullet_act(obj/item/projectile/Proj)
..()
. = ..()
if(!stat && !client)
if(parrot_state == PARROT_PERCH)
parrot_sleep_dur = parrot_sleep_max //Reset it's sleep timer if it was perched
@@ -347,7 +347,6 @@
//parrot_been_shot += 5
icon_state = icon_living
drop_held_item(0)
return
/*
@@ -220,15 +220,12 @@
return ..() //Heals them
/mob/living/simple_animal/slime/bullet_act(obj/item/projectile/Proj)
if(!Proj)
return
attacked += 10
if((Proj.damage_type == BURN))
adjustBruteLoss(-abs(Proj.damage)) //fire projectiles heals slimes.
Proj.on_hit(src)
else
..(Proj)
return 0
return BULLET_ACT_BLOCK
return ..()
/mob/living/simple_animal/slime/emp_act(severity)
. = ..()
+4
View File
@@ -508,6 +508,10 @@ GLOBAL_VAR_INIT(exploit_warn_spam_prevention, 0)
usr << browse(text("<HTML><HEAD><TITLE>[]</TITLE></HEAD><BODY><TT>[]</TT></BODY></HTML>", name, replacetext(flavor_text, "\n", "<BR>")), text("window=[];size=500x200", name))
onclose(usr, "[name]")
if(href_list["flavor2_more"])
usr << browse(text("<HTML><HEAD><TITLE>[]</TITLE></HEAD><BODY><TT>[]</TT></BODY></HTML>", name, replacetext(flavor_text_2, "\n", "<BR>")), text("window=[];size=500x200", name))
onclose(usr, "[name]")
if(href_list["flavor_change"])
update_flavor_text()
-12
View File
@@ -1,15 +1,3 @@
/mob/CanPass(atom/movable/mover, turf/target)
if((mover.pass_flags & PASSMOB))
return TRUE
if(istype(mover, /obj/item/projectile) || mover.throwing)
return (!density || lying)
if(buckled == mover)
return TRUE
if(ismob(mover))
if (mover in buckled_mobs)
return TRUE
return (!mover.density || !density || lying || (mover.throwing && mover.throwing.thrower == src && !ismob(mover)))
//DO NOT USE THIS UNLESS YOU ABSOLUTELY HAVE TO. THIS IS BEING PHASED OUT FOR THE MOVESPEED MODIFICATION SYSTEM.
//See mob_movespeed.dm
/mob/proc/movement_delay() //update /living/movement_delay() if you change this
+1 -1
View File
@@ -51,7 +51,7 @@
if(length(msg) <= 40)
return "<span class='notice'>[html_encode(msg)]</span>"
else
return "<span class='notice'>[html_encode(copytext(msg, 1, 37))]... <a href='?src=[REF(src)];flavor_more=1'>More...</span></a>"
return "<span class='notice'>[html_encode(copytext(msg, 1, 37))]... <a href='?src=[REF(src)];flavor2_more=1'>More...</span></a>"
/mob/proc/get_top_level_mob()
@@ -158,4 +158,5 @@
// "Brute" damage mostly damages the casing.
/obj/machinery/modular_computer/bullet_act(obj/item/projectile/Proj)
if(cpu)
cpu.bullet_act(Proj)
return cpu.bullet_act(Proj)
return ..()
+9 -5
View File
@@ -79,13 +79,17 @@ By design, d1 is the smallest direction and d2 is the highest
color = "#ffffff"
// the power cable object
/obj/structure/cable/Initialize(mapload, param_color)
/obj/structure/cable/Initialize(mapload, param_color, _d1, _d2)
. = ..()
// ensure d1 & d2 reflect the icon_state for entering and exiting cable
var/dash = findtext(icon_state, "-")
d1 = text2num( copytext( icon_state, 1, dash ) )
d2 = text2num( copytext( icon_state, dash+1 ) )
if(isnull(_d1) || isnull(_d2))
// ensure d1 & d2 reflect the icon_state for entering and exiting cable
var/dash = findtext(icon_state, "-")
d1 = text2num( copytext( icon_state, 1, dash ) )
d2 = text2num( copytext( icon_state, dash+1 ) )
else
d1 = _d1
d2 = _d2
var/turf/T = get_turf(src) // hide if turf is not intact
if(level==1)
+1 -1
View File
@@ -74,7 +74,7 @@
addtimer(CALLBACK(GLOBAL_PROC, .proc/explosion, get_turf(src), 2, 3, 4, 8), 100) // Not a normal explosion.
/obj/machinery/power/rtg/abductor/bullet_act(obj/item/projectile/Proj)
..()
. = ..()
if(!going_kaboom && istype(Proj) && !Proj.nodamage && ((Proj.damage_type == BURN) || (Proj.damage_type == BRUTE)))
message_admins("[ADMIN_LOOKUPFLW(Proj.firer)] triggered an Abductor Core explosion at [AREACOORD(src)] via projectile.")
log_game("[key_name(Proj.firer)] triggered an Abductor Core explosion at [AREACOORD(src)] via projectile.")
@@ -113,7 +113,8 @@
/obj/singularity/bullet_act(obj/item/projectile/P)
return 0 //Will there be an impact? Who knows. Will we see it? No.
qdel(P)
return BULLET_ACT_HIT //Will there be an impact? Who knows. Will we see it? No.
/obj/singularity/Bump(atom/A)
@@ -521,7 +521,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
has_been_powered = TRUE
else if(takes_damage)
damage += Proj.damage * config_bullet_energy
return FALSE
return BULLET_ACT_HIT
/obj/machinery/power/supermatter_crystal/singularity_act()
var/gain = 100
@@ -569,4 +569,4 @@
/obj/item/projectile/beam/beam_rifle/hitscan/aiming_beam/on_hit()
qdel(src)
return FALSE
return BULLET_ACT_HIT
@@ -114,7 +114,7 @@
icon_state = "blastwave"
damage = 0
nodamage = FALSE
forcedodge = TRUE
movement_type = FLYING | UNSTOPPABLE
var/heavyr = 0
var/mediumr = 0
var/lightr = 0
+99 -58
View File
@@ -11,15 +11,16 @@
item_flags = ABSTRACT
pass_flags = PASSTABLE
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
movement_type = FLYING
hitsound = 'sound/weapons/pierce.ogg'
var/hitsound_wall = ""
resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
var/def_zone = "" //Aiming at
var/atom/movable/firer = null//Who shot it
var/atom/fired_from = null // the atom that the projectile was fired from (gun, turret)
var/atom/fired_from = null // the atom that the projectile was fired from (gun, turret) var/suppressed = FALSE //Attack message
var/suppressed = FALSE //Attack message
var/candink = FALSE //Can this projectile play the dink sound when hitting the head?
var/candink = FALSE //Can this projectile play the dink sound when hitting the head? var/yo = null
var/yo = null
var/xo = null
var/atom/original = null // the original target clicked
@@ -84,7 +85,8 @@
var/flag = "bullet" //Defines what armor to use when it hits things. Must be set to bullet, laser, energy,or bomb
var/projectile_type = /obj/item/projectile
var/range = 50 //This will de-increment every step. When 0, it will deletze the projectile.
var/decayedRange
var/decayedRange //stores original range
var/reflect_range_decrease = 5 //amount of original range that falls off when reflecting, so it doesn't go forever
var/is_reflectable = FALSE // Can it be reflected or not?
//Effects
var/stun = 0
@@ -99,11 +101,12 @@
var/drowsy = 0
var/stamina = 0
var/jitter = 0
var/forcedodge = 0 //to pass through everything
var/dismemberment = 0 //The higher the number, the greater the bonus to dismembering. 0 will not dismember at all.
var/impact_effect_type //what type of impact effect to show when hitting something
var/log_override = FALSE //is this type spammed enough to not log? (KAs)
var/temporary_unstoppable_movement = FALSE
/obj/item/projectile/Initialize()
. = ..()
permutated = list()
@@ -152,12 +155,12 @@
W.add_dent(WALL_DENT_SHOT, hitx, hity)
return 0
return BULLET_ACT_HIT
if(!isliving(target))
if(impact_effect_type && !hitscan)
new impact_effect_type(target_loca, hitx, hity)
return 0
return BULLET_ACT_HIT
var/mob/living/L = target
@@ -185,7 +188,6 @@
C.bleed(damage)
else
L.add_splatter_floor(target_loca)
else if(impact_effect_type && !hitscan)
new impact_effect_type(target_loca, hitx, hity)
@@ -235,24 +237,20 @@
beam_segments[beam_index] = null
/obj/item/projectile/Bump(atom/A)
var/turf/T = get_turf(A)
if(trajectory && check_ricochet(A) && check_ricochet_flag(A) && ricochets < ricochets_max)
var/datum/point/pcache = trajectory.copy_to()
ricochets++
if(A.handle_ricochet(src))
on_ricochet(A)
ignore_source_check = TRUE
range = initial(range)
decayedRange = max(0, decayedRange - reflect_range_decrease)
range = decayedRange
if(hitscan)
store_hitscan_collision(pcache)
return TRUE
if(firer && !ignore_source_check)
if(A == firer || (A == firer.loc && ismecha(A))) //cannot shoot yourself or your mech
trajectory_ignore_forcemove = TRUE
forceMove(get_turf(A))
trajectory_ignore_forcemove = FALSE
return FALSE
var/distance = get_dist(get_turf(A), starting) // Get the distance between the turf shot from and the mob we hit and use that for the calculations.
var/distance = get_dist(T, starting) // Get the distance between the turf shot from and the mob we hit and use that for the calculations.
def_zone = ran_zone(def_zone, max(100-(7*distance), 5)) //Lower accurancy/longer range tradeoff. 7 is a balanced number to use.
if(isturf(A) && hitsound_wall)
@@ -261,51 +259,66 @@
volume = 5
playsound(loc, hitsound_wall, volume, 1, -1)
var/turf/target_turf = get_turf(A)
return process_hit(T, select_target(T, A))
if(!prehit(A))
if(forcedodge)
trajectory_ignore_forcemove = TRUE
forceMove(target_turf)
trajectory_ignore_forcemove = FALSE
return FALSE
#define QDEL_SELF 1 //Delete if we're not UNSTOPPABLE flagged non-temporarily
#define DO_NOT_QDEL 2 //Pass through.
#define FORCE_QDEL 3 //Force deletion.
var/permutation = A.bullet_act(src, def_zone) // searches for return value, could be deleted after run so check A isn't null
if(permutation == -1 || forcedodge)// the bullet passes through a dense object!
trajectory_ignore_forcemove = TRUE
forceMove(target_turf)
trajectory_ignore_forcemove = FALSE
if(A)
permutated.Add(A)
return FALSE
else
var/atom/alt = select_target(A)
if(alt)
if(!prehit(alt))
return FALSE
alt.bullet_act(src, def_zone)
qdel(src)
return TRUE
/obj/item/projectile/proc/process_hit(turf/T, atom/target, qdel_self, hit_something = FALSE) //probably needs to be reworked entirely when pixel movement is done.
if(QDELETED(src) || !T || !target) //We're done, nothing's left.
if((qdel_self == FORCE_QDEL) || ((qdel_self == QDEL_SELF) && !temporary_unstoppable_movement && !CHECK_BITFIELD(movement_type, UNSTOPPABLE)))
qdel(src)
return hit_something
permutated |= target //Make sure we're never hitting it again. If we ever run into weirdness with piercing projectiles needing to hit something multiple times.. well.. that's a to-do.
if(!prehit(target))
return process_hit(T, select_target(T), qdel_self, hit_something) //Hit whatever else we can since that didn't work.
var/result = target.bullet_act(src, def_zone)
if(result == BULLET_ACT_FORCE_PIERCE)
if(!CHECK_BITFIELD(movement_type, UNSTOPPABLE))
temporary_unstoppable_movement = TRUE
ENABLE_BITFIELD(movement_type, UNSTOPPABLE)
return process_hit(T, select_target(T), qdel_self, TRUE) //Hit whatever else we can since we're piercing through but we're still on the same tile.
else if(result == BULLET_ACT_TURF) //We hit the turf but instead we're going to also hit something else on it.
return process_hit(T, select_target(T), QDEL_SELF, TRUE)
else //Whether it hit or blocked, we're done!
qdel_self = QDEL_SELF
hit_something = TRUE
if((qdel_self == FORCE_QDEL) || ((qdel_self == QDEL_SELF) && !temporary_unstoppable_movement && !CHECK_BITFIELD(movement_type, UNSTOPPABLE)))
qdel(src)
return hit_something
/obj/item/projectile/proc/select_target(atom/A) //Selects another target from a wall if we hit a wall.
if(!A || !A.density || (A.flags_1 & ON_BORDER_1) || ismob(A) || A == original) //if we hit a dense non-border obj or dense turf then we also hit one of the mobs or machines/structures on that tile.
return
var/turf/T = get_turf(A)
if(original in T)
#undef QDEL_SELF
#undef DO_NOT_QDEL
#undef FORCE_QDEL
/obj/item/projectile/proc/select_target(turf/T, atom/target) //Select a target from a turf.
if((original in T) && can_hit_target(original, permutated, TRUE, TRUE))
return original
var/list/mob/possible_mobs = typecache_filter_list(T, GLOB.typecache_mob) - A
if(target && can_hit_target(target, permutated, target == original, TRUE))
return target
var/list/mob/living/possible_mobs = typecache_filter_list(T, GLOB.typecache_mob)
var/list/mob/mobs = list()
for(var/i in possible_mobs)
var/mob/M = i
if(M.lying)
for(var/mob/living/M in possible_mobs)
if(!can_hit_target(M, permutated, M == original, TRUE))
continue
mobs += M
var/mob/M = safepick(mobs)
if(M)
return M.lowest_buckled_mob()
var/obj/O = safepick(typecache_filter_list(T, GLOB.typecache_machine_or_structure) - A)
var/list/obj/possible_objs = typecache_filter_list(T, GLOB.typecache_machine_or_structure)
var/list/obj/objs = list()
for(var/obj/O in possible_objs)
if(!can_hit_target(O, permutated, O == original, TRUE))
continue
objs += O
var/obj/O = safepick(objs)
if(O)
return O
//Nothing else is here that we can hit, hit the turf if we haven't.
if(!(T in permutated) && can_hit_target(T, permutated, T == original, TRUE))
return T
//Returns null if nothing at all was found.
/obj/item/projectile/proc/check_ricochet()
if(prob(ricochet_chance))
@@ -332,7 +345,7 @@
var/turf/ending = return_predicted_turf_after_moves(moves, forced_angle)
return getline(current, ending)
/obj/item/projectile/Process_Spacemove(var/movement_dir = 0)
/obj/item/projectile/Process_Spacemove(movement_dir = 0)
return TRUE //Bullets don't drift in space
/obj/item/projectile/process()
@@ -360,8 +373,7 @@
/obj/item/projectile/proc/fire(angle, atom/direct_target)
if(fired_from)
SEND_SIGNAL(fired_from, COMSIG_PROJECTILE_BEFORE_FIRE, src, original)
//If no angle needs to resolve it from xo/yo!
SEND_SIGNAL(fired_from, COMSIG_PROJECTILE_BEFORE_FIRE, src, original) //If no angle needs to resolve it from xo/yo!
if(!log_override && firer && original)
log_combat(firer, original, "fired at", src, "from [get_area_name(src, TRUE)]")
if(direct_target)
@@ -498,8 +510,6 @@
else if(T != loc)
step_towards(src, T)
hitscan_last = loc
if(can_hit_target(original, permutated))
Bump(original)
if(!hitscanning && !forcemoved)
pixel_x = trajectory.return_px() - trajectory.mpx * trajectory_multiplier * SSprojectiles.global_iterations_per_move
pixel_y = trajectory.return_py() - trajectory.mpy * trajectory_multiplier * SSprojectiles.global_iterations_per_move
@@ -528,8 +538,28 @@
homing_offset_y = -homing_offset_y
//Returns true if the target atom is on our current turf and above the right layer
/obj/item/projectile/proc/can_hit_target(atom/target, var/list/passthrough)
return (target && ((target.layer >= PROJECTILE_HIT_THRESHHOLD_LAYER) || ismob(target)) && (loc == get_turf(target)) && (!(target in passthrough)))
//If direct target is true it's the originally clicked target.
/obj/item/projectile/proc/can_hit_target(atom/target, list/passthrough, direct_target = FALSE, ignore_loc = FALSE)
if(QDELETED(target))
return FALSE
if(!ignore_source_check && firer)
var/mob/M = firer
if((target == firer) || ((target == firer.loc) && ismecha(firer.loc)) || (target in firer.buckled_mobs) || (istype(M) && (M.buckled == target)))
return FALSE
if(!ignore_loc && (loc != target.loc))
return FALSE
if(target in passthrough)
return FALSE
if(target.density) //This thing blocks projectiles, hit it regardless of layer/mob stuns/etc.
return TRUE
if(!isliving(target))
if(target.layer < PROJECTILE_HIT_THRESHHOLD_LAYER)
return FALSE
else
var/mob/living/L = target
if(!direct_target && !L.density)
return FALSE
return TRUE
//Spread is FORCED!
/obj/item/projectile/proc/preparePixelProjectile(atom/target, atom/source, params, spread = 0)
@@ -591,9 +621,20 @@
return list(angle, p_x, p_y)
/obj/item/projectile/Crossed(atom/movable/AM) //A mob moving on a tile with a projectile is hit by it.
..()
if(isliving(AM) && (AM.density || AM == original) && !(src.pass_flags & PASSMOB))
Bump(AM)
. = ..()
if(isliving(AM) && !(pass_flags & PASSMOB))
var/mob/living/L = AM
if(can_hit_target(L, permutated, (AM == original)))
Bump(AM)
/obj/item/projectile/Move(atom/newloc, dir = NONE)
. = ..()
if(.)
if(temporary_unstoppable_movement)
temporary_unstoppable_movement = FALSE
DISABLE_BITFIELD(movement_type, UNSTOPPABLE)
if(fired && can_hit_target(original, permutated, TRUE))
Bump(original)
/obj/item/projectile/Destroy()
if(hitscan)
+3 -3
View File
@@ -107,8 +107,8 @@
/obj/item/projectile/beam/pulse/heavy/on_hit(atom/target, blocked = FALSE)
life -= 10
if(life > 0)
. = -1
..()
. = BULLET_ACT_FORCE_PIERCE
return ..()
/obj/item/projectile/beam/emitter
name = "emitter beam"
@@ -207,4 +207,4 @@
. = ..()
if(isopenturf(target) || istype(target, /turf/closed/indestructible))//shrunk floors wouldnt do anything except look weird, i-walls shouldnt be bypassable
return
target.AddComponent(/datum/component/shrink, shrink_time)
target.AddComponent(/datum/component/shrink, shrink_time)
@@ -15,7 +15,7 @@
if(M.can_inject(null, FALSE, def_zone, piercing)) // Pass the hit zone to see if it can inject by whether it hit the head or the body.
..()
if(skip == TRUE)
return
return BULLET_ACT_HIT
reagents.reaction(M, INJECT)
reagents.trans_to(M, reagents.total_volume)
return TRUE
@@ -27,7 +27,7 @@
..(target, blocked)
DISABLE_BITFIELD(reagents.reagents_holder_flags, NO_REACT)
reagents.handle_reactions()
return TRUE
return BULLET_ACT_HIT
/obj/item/projectile/bullet/dart/metalfoam/Initialize()
. = ..()
@@ -70,11 +70,11 @@
target.visible_message("<span class='notice'>\The [src] beeps!</span>")
to_chat("<span class='notice'><i>You feel a tiny prick as a smartdart embeds itself in you with a beep.</i></span>")
return TRUE
return BULLET_ACT_HIT
else
blocked = 100
target.visible_message("<span class='danger'>\The [src] was deflected!</span>", \
"<span class='userdanger'>You see a [src] bounce off you, booping sadly!</span>")
target.visible_message("<span class='danger'>\The [src] fails to land on target!</span>")
return TRUE
return BULLET_ACT_BLOCK
@@ -12,7 +12,7 @@
if(M.can_inject(null, FALSE, def_zone, FALSE))
if(injector.inject(M, firer))
QDEL_NULL(injector)
return TRUE
return BULLET_ACT_HIT
else
blocked = 100
target.visible_message("<span class='danger'>\The [src] was deflected!</span>", \
@@ -9,4 +9,4 @@
/obj/item/projectile/bullet/a40mm/on_hit(atom/target, blocked = FALSE)
..()
explosion(target, -1, 0, 2, 1, 0, flame_range = 3)
return TRUE
return BULLET_ACT_HIT
@@ -53,7 +53,7 @@
/obj/item/projectile/bullet/shotgun_frag12/on_hit(atom/target, blocked = FALSE)
..()
explosion(target, -1, 0, 1)
return TRUE
return BULLET_ACT_HIT
/obj/item/projectile/bullet/pellet
var/tile_dropoff = 0.75
@@ -34,7 +34,7 @@
icon_state = "gauss"
name = "penetrator round"
damage = 60
forcedodge = TRUE
movement_type = FLYING | UNSTOPPABLE
dismemberment = 0 //It goes through you cleanly.
knockdown = 0
breakthings = FALSE
@@ -3,7 +3,7 @@
/obj/item/projectile/bullet/honker
damage = 0
knockdown = 60
forcedodge = TRUE
movement_type = FLYING | UNSTOPPABLE
nodamage = TRUE
candink = FALSE
hitsound = 'sound/items/bikehorn.ogg'
@@ -15,7 +15,7 @@
var/turf/Tloc = get_turf(target)
if(!locate(/obj/effect/nettingportal) in Tloc)
new /obj/effect/nettingportal(Tloc)
..()
return ..()
/obj/item/projectile/energy/net/on_range()
do_sparks(1, TRUE, src)
@@ -69,7 +69,7 @@
else if(iscarbon(target))
var/obj/item/restraints/legcuffs/beartrap/B = new /obj/item/restraints/legcuffs/beartrap/energy(get_turf(target))
B.Crossed(target)
..()
return ..()
/obj/item/projectile/energy/trap/on_range()
new /obj/item/restraints/legcuffs/beartrap/energy(loc)
@@ -91,7 +91,7 @@
var/obj/item/restraints/legcuffs/beartrap/B = new /obj/item/restraints/legcuffs/beartrap/energy/cyborg(get_turf(target))
B.Crossed(target)
QDEL_IN(src, 10)
..()
return ..()
/obj/item/projectile/energy/trap/cyborg/on_range()
do_sparks(1, TRUE, src)
+15 -14
View File
@@ -17,7 +17,7 @@
var/mob/M = target
if(M.anti_magic_check())
M.visible_message("<span class='warning'>[src] vanishes on contact with [target]!</span>")
return
return BULLET_ACT_BLOCK
M.death(0)
/obj/item/projectile/magic/resurrection
@@ -31,10 +31,10 @@
. = ..()
if(isliving(target))
if(target.hellbound)
return
return BULLET_ACT_BLOCK
if(target.anti_magic_check())
target.visible_message("<span class='warning'>[src] vanishes on contact with [target]!</span>")
return
return BULLET_ACT_BLOCK
if(iscarbon(target))
var/mob/living/carbon/C = target
C.regenerate_limbs()
@@ -60,7 +60,7 @@
var/mob/M = target
if(M.anti_magic_check())
M.visible_message("<span class='warning'>[src] fizzles on contact with [target]!</span>")
return
return BULLET_ACT_BLOCK
var/teleammount = 0
var/teleloc = target
if(!isturf(target))
@@ -116,7 +116,7 @@
if(M.anti_magic_check())
M.visible_message("<span class='warning'>[src] fizzles on contact with [M]!</span>")
qdel(src)
return
return BULLET_ACT_BLOCK
wabbajack(change)
qdel(src)
@@ -264,7 +264,7 @@
/obj/item/projectile/magic/animate/on_hit(atom/target, blocked = FALSE)
target.animate_atom_living(firer)
..()
. = ..()
/atom/proc/animate_atom_living(var/mob/living/owner = null)
if((isitem(src) || isstructure(src)) && !is_type_in_list(src, GLOB.protected_objects))
@@ -315,7 +315,7 @@
if(M.anti_magic_check())
M.visible_message("<span class='warning'>[src] vanishes on contact with [target]!</span>")
qdel(src)
return
return BULLET_ACT_BLOCK
. = ..()
/obj/item/projectile/magic/arcane_barrage
@@ -334,7 +334,7 @@
if(M.anti_magic_check())
M.visible_message("<span class='warning'>[src] vanishes on contact with [target]!</span>")
qdel(src)
return
return BULLET_ACT_BLOCK
. = ..()
@@ -460,7 +460,7 @@
if(M.anti_magic_check())
visible_message("<span class='warning'>[src] fizzles on contact with [target]!</span>")
qdel(src)
return
return BULLET_ACT_BLOCK
tesla_zap(src, tesla_range, tesla_power, tesla_flags)
qdel(src)
@@ -487,7 +487,7 @@
var/mob/living/M = target
if(M.anti_magic_check())
visible_message("<span class='warning'>[src] vanishes into smoke on contact with [target]!</span>")
return
return BULLET_ACT_BLOCK
M.take_overall_damage(0,10) //between this 10 burn, the 10 brute, the explosion brute, and the onfire burn, your at about 65 damage if you stop drop and roll immediately
var/turf/T = get_turf(target)
explosion(T, -1, exp_heavy, exp_light, exp_flash, 0, flame_range = exp_fire)
@@ -504,7 +504,7 @@
if(ismob(target))
var/mob/living/M = target
if(M.anti_magic_check())
return
return BULLET_ACT_BLOCK
var/turf/T = get_turf(target)
for(var/i=0, i<50, i+=10)
addtimer(CALLBACK(GLOBAL_PROC, .proc/explosion, T, -1, exp_heavy, exp_light, exp_flash, FALSE, FALSE, exp_fire), i)
@@ -518,11 +518,11 @@
/obj/item/projectile/magic/nuclear/on_hit(target)
if(used)
return
return BULLET_ACT_HIT
new/obj/effect/temp_visual/slugboom(get_turf(src))
if(ismob(target))
if(target == victim)
return
return BULLET_ACT_FORCE_PIERCE
used = 1
visible_message("<span class='danger'>[victim] slams into [target] with explosive force!</span>")
explosion(src, 2, 3, 4, -1, TRUE, FALSE, 5)
@@ -531,8 +531,9 @@
victim.take_overall_damage(30,30)
victim.Knockdown(60)
explosion(src, -1, -1, -1, -1, FALSE, FALSE, 5)
return BULLET_ACT_HIT
/obj/item/projectile/magic/nuclear/Destroy()
for(var/atom/movable/AM in contents)
AM.forceMove(get_turf(src))
. = ..()
. = ..()
@@ -12,7 +12,7 @@
knockdown = 20
speed = 2
range = 16
forcedodge = TRUE
movement_type = FLYING | UNSTOPPABLE
var/datum/beam/arm
var/handedness = 0
@@ -28,7 +28,7 @@
/obj/item/projectile/curse_hand/prehit(atom/target)
if(target == original)
forcedodge = FALSE
DISABLE_BITFIELD(movement_type, UNSTOPPABLE)
else if(!isturf(target))
return FALSE
return ..()
@@ -37,7 +37,7 @@
if(arm)
arm.End()
arm = null
if(forcedodge)
if(CHECK_BITFIELD(movement_type, UNSTOPPABLE))
playsound(src, 'sound/effects/curse3.ogg', 25, 1, -1)
var/turf/T = get_step(src, dir)
new/obj/effect/temp_visual/dir_setting/curse/hand(T, dir, handedness)
@@ -6,15 +6,12 @@
nodamage = 1
flag = "energy"
impact_effect_type = /obj/effect/temp_visual/impact_effect/ion
var/emp_radius = 1
/obj/item/projectile/ion/on_hit(atom/target, blocked = FALSE)
..()
empulse(target, 1, 1)
return TRUE
empulse(target, emp_radius, emp_radius)
return BULLET_ACT_HIT
/obj/item/projectile/ion/weak
/obj/item/projectile/ion/weak/on_hit(atom/target, blocked = FALSE)
..()
empulse(target, 0, 0)
return TRUE
emp_radius = 0
@@ -29,7 +29,7 @@
mine_range--
range++
if(range > 0)
return -1
return BULLET_ACT_FORCE_PIERCE
/obj/item/projectile/plasma/adv
damage = 28
@@ -6,7 +6,7 @@
/obj/item/projectile/bullet/gyro/on_hit(atom/target, blocked = FALSE)
..()
explosion(target, -1, 0, 2)
return TRUE
return BULLET_ACT_HIT
/obj/item/projectile/bullet/a84mm
name ="\improper HEDP rocket"
@@ -28,7 +28,7 @@
if(issilicon(target))
var/mob/living/silicon/S = target
S.take_overall_damage(anti_armour_damage*0.75, anti_armour_damage*0.25)
return TRUE
return BULLET_ACT_HIT
/obj/item/projectile/bullet/a84mm_he
name ="\improper HE missile"
@@ -43,4 +43,4 @@
explosion(target, 0, 1, 2, 4)
else
explosion(target, 0, 0, 2, 4)
return TRUE
return BULLET_ACT_HIT
@@ -25,5 +25,5 @@
/obj/item/projectile/beam/wormhole/on_hit(atom/target)
if(!gun)
qdel(src)
return
return BULLET_ACT_BLOCK
gun.create_portal(src, get_turf(src))
@@ -222,7 +222,6 @@
/datum/chemical_reaction/mix_virus
name = "Mix Virus"
id = "mixvirus"
results = list(/datum/reagent/blood = 1)
required_reagents = list(/datum/reagent/consumable/virus_food = 1)
required_catalysts = list(/datum/reagent/blood = 1)
var/level_min = 1
@@ -234,8 +233,8 @@
if(B && B.data)
var/datum/disease/advance/D = locate(/datum/disease/advance) in B.data["viruses"]
if(D)
D.Evolve(level_min, level_max)
for(var/i in 1 to min(created_volume, 5))
D.Evolve(level_min, level_max)
/datum/chemical_reaction/mix_virus/mix_virus_2
@@ -326,19 +325,18 @@
level_max = 8
/datum/chemical_reaction/mix_virus/rem_virus
name = "Devolve Virus"
id = "remvirus"
required_reagents = list(/datum/reagent/medicine/synaptizine = 1)
required_catalysts = list(/datum/reagent/blood = 1)
/datum/chemical_reaction/mix_virus/rem_virus/on_reaction(datum/reagents/holder, created_volume)
var/datum/reagent/blood/B = locate(/datum/reagent/blood) in holder.reagent_list
if(B && B.data)
var/datum/disease/advance/D = locate(/datum/disease/advance) in B.data["viruses"]
if(D)
D.Devolve()
for(var/i in 1 to min(created_volume, 5))
D.Devolve()
/datum/chemical_reaction/mix_virus/neuter_virus
name = "Neuter Virus"
@@ -347,14 +345,12 @@
required_catalysts = list(/datum/reagent/blood = 1)
/datum/chemical_reaction/mix_virus/neuter_virus/on_reaction(datum/reagents/holder, created_volume)
var/datum/reagent/blood/B = locate(/datum/reagent/blood) in holder.reagent_list
if(B && B.data)
var/datum/disease/advance/D = locate(/datum/disease/advance) in B.data["viruses"]
if(D)
D.Neuter()
for(var/i in 1 to min(created_volume, 5))
D.Neuter()
////////////////////////////////// foam and foam precursor ///////////////////////////////////////////////////
+1 -1
View File
@@ -125,7 +125,7 @@
boom()
/obj/structure/reagent_dispensers/fueltank/bullet_act(obj/item/projectile/P)
..()
. = ..()
if(!QDELETED(src)) //wasn't deleted by the projectile's effects.
if(!P.nodamage && ((P.damage_type == BURN) || (P.damage_type == BRUTE)))
var/boom_message = "[ADMIN_LOOKUPFLW(P.firer)] triggered a fueltank explosion via projectile."
@@ -46,6 +46,16 @@
category = list("Electronics")
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
/datum/design/nanite_comm_remote
name = "Nanite Communication Remote"
desc = "Allows for the construction of a nanite communication remote."
id = "nanite_comm_remote"
build_type = PROTOLATHE
materials = list(MAT_GLASS = 500, MAT_METAL = 500)
build_path = /obj/item/nanite_remote/comm
category = list("Electronics")
departmental_flags = DEPARTMENTAL_FLAG_SCIENCE
/datum/design/nanite_scanner
name = "Nanite Scanner"
desc = "Allows for the construction of a nanite scanner."
@@ -380,7 +380,7 @@
name = "Mind Control"
desc = "The nanites imprint an absolute directive onto the host's brain while they're active."
id = "mindcontrol_nanites"
program_type = /datum/nanite_program/mind_control
program_type = /datum/nanite_program/triggered/comm/mind_control
category = list("Weaponized Nanites")
////////////////////SUPPRESSION NANITES//////////////////////////////////////
@@ -445,21 +445,35 @@
name = "Skull Echo"
desc = "The nanites echo a synthesized message inside the host's skull."
id = "voice_nanites"
program_type = /datum/nanite_program/triggered/voice
program_type = /datum/nanite_program/triggered/comm/voice
category = list("Suppression Nanites")
/datum/design/nanites/speech
name = "Forced Speech"
desc = "The nanites force the host to say a pre-programmed sentence when triggered."
id = "speech_nanites"
program_type = /datum/nanite_program/triggered/speech
program_type = /datum/nanite_program/triggered/comm/speech
category = list("Suppression Nanites")
/datum/design/nanites/hallucination
name = "Hallucination"
desc = "The nanites make the host see and hear things that aren't real."
id = "hallucination_nanites"
program_type = /datum/nanite_program/triggered/hallucination
program_type = /datum/nanite_program/triggered/comm/hallucination
category = list("Suppression Nanites")
/datum/design/nanites/good_mood
name = "Happiness Enhancer"
desc = "The nanites synthesize serotonin inside the host's brain, creating an artificial sense of happiness."
id = "good_mood_nanites"
program_type = /datum/nanite_program/good_mood
category = list("Suppression Nanites")
/datum/design/nanites/bad_mood
name = "Happiness Suppressor"
desc = "The nanites suppress the production of serotonin inside the host's brain, creating an artificial state of depression."
id = "bad_mood_nanites"
program_type = /datum/nanite_program/bad_mood
category = list("Suppression Nanites")
////////////////////SENSOR NANITES//////////////////////////////////////
@@ -3,7 +3,7 @@
/datum/nanite_program/regenerative
name = "Accelerated Regeneration"
desc = "The nanites boost the host's natural regeneration, increasing their healing speed. Does not consume nanites if the host is unharmed."
use_rate = 2.5
use_rate = 0.5
rogue_types = list(/datum/nanite_program/necrotic)
/datum/nanite_program/regenerative/check_conditions()
@@ -23,11 +23,11 @@
if(!parts.len)
return
for(var/obj/item/bodypart/L in parts)
if(L.heal_damage(1/parts.len, 1/parts.len))
if(L.heal_damage(0.5/parts.len, 0.5/parts.len, null, BODYPART_ORGANIC))
host_mob.update_damage_overlays()
else
host_mob.adjustBruteLoss(-1, TRUE)
host_mob.adjustFireLoss(-1, TRUE)
host_mob.adjustBruteLoss(-0.5, TRUE)
host_mob.adjustFireLoss(-0.5, TRUE)
/datum/nanite_program/temperature
name = "Temperature Adjustment"
@@ -112,7 +112,7 @@
/datum/nanite_program/repairing
name = "Mechanical Repair"
desc = "The nanites fix damage in the host's mechanical limbs."
use_rate = 0.5 //much more efficient than organic healing
use_rate = 0.5
rogue_types = list(/datum/nanite_program/necrotic)
/datum/nanite_program/repairing/check_conditions()
@@ -137,13 +137,13 @@
return
var/update = FALSE
for(var/obj/item/bodypart/L in parts)
if(L.heal_damage(1/parts.len, 1/parts.len, only_robotic = TRUE, only_organic = FALSE))
if(L.heal_damage(1.5/parts.len, 1.5/parts.len, null, BODYPART_ROBOTIC)) //much faster than organic healing
update = TRUE
if(update)
host_mob.update_damage_overlays()
else
host_mob.adjustBruteLoss(-1, TRUE)
host_mob.adjustFireLoss(-1, TRUE)
host_mob.adjustBruteLoss(-1.5, TRUE)
host_mob.adjustFireLoss(-1.5, TRUE)
/datum/nanite_program/purging_advanced
name = "Selective Blood Purification"
@@ -114,7 +114,19 @@
. = ..()
host_mob.cure_fakedeath("nanites")
/datum/nanite_program/triggered/speech
//Can receive transmissions from a nanite communication remote for customized messages
/datum/nanite_program/triggered/comm
var/comm_code = 0
var/comm_message = ""
/datum/nanite_program/triggered/comm/proc/receive_comm_signal(signal_comm_code, comm_message, comm_source)
if(!activated || !comm_code)
return
if(signal_comm_code == comm_code)
host_mob.investigate_log("'s [name] nanite program was messaged by [comm_source] with comm code [signal_comm_code] and message '[comm_message]'.", INVESTIGATE_NANITES)
trigger(comm_message)
/datum/nanite_program/triggered/comm/speech
name = "Forced Speech"
desc = "The nanites force the host to say a pre-programmed sentence when triggered."
unique = FALSE
@@ -122,10 +134,10 @@
trigger_cooldown = 20
rogue_types = list(/datum/nanite_program/brain_misfire, /datum/nanite_program/brain_decay)
extra_settings = list("Sentence")
extra_settings = list("Sentence","Comm Code")
var/sentence = ""
/datum/nanite_program/triggered/speech/set_extra_setting(user, setting)
/datum/nanite_program/triggered/comm/speech/set_extra_setting(user, setting)
if(setting == "Sentence")
var/new_sentence = stripped_input(user, "Choose the sentence that the host will be forced to say.", "Sentence", sentence, MAX_MESSAGE_LEN)
if(!new_sentence)
@@ -133,23 +145,34 @@
if(copytext(new_sentence, 1, 2) == "*") //emotes are abusable, like surrender
return
sentence = new_sentence
if(setting == "Comm Code")
var/new_code = input(user, "Set the communication code (1-9999) or set to 0 to disable external signals.", name, null) as null|num
if(isnull(new_code))
return
comm_code = CLAMP(round(new_code, 1), 0, 9999)
/datum/nanite_program/triggered/speech/get_extra_setting(setting)
/datum/nanite_program/triggered/comm/speech/get_extra_setting(setting)
if(setting == "Sentence")
return sentence
if(setting == "Comm Code")
return comm_code
/datum/nanite_program/triggered/speech/copy_extra_settings_to(datum/nanite_program/triggered/speech/target)
/datum/nanite_program/triggered/comm/speech/copy_extra_settings_to(datum/nanite_program/triggered/comm/speech/target)
target.sentence = sentence
target.comm_code = comm_code
/datum/nanite_program/triggered/speech/trigger()
/datum/nanite_program/triggered/comm/speech/trigger(comm_message)
if(!..())
return
var/sent_message = comm_message
if(!comm_message)
sent_message = sentence
if(host_mob.stat == DEAD)
return
to_chat(host_mob, "<span class='warning'>You feel compelled to speak...</span>")
host_mob.say(sentence, forced = "nanite speech")
host_mob.say(sent_message, forced = "nanite speech")
/datum/nanite_program/triggered/voice
/datum/nanite_program/triggered/comm/voice
name = "Skull Echo"
desc = "The nanites echo a synthesized message inside the host's skull."
unique = FALSE
@@ -157,44 +180,62 @@
trigger_cooldown = 20
rogue_types = list(/datum/nanite_program/brain_misfire, /datum/nanite_program/brain_decay)
extra_settings = list("Message")
extra_settings = list("Message","Comm Code")
var/message = ""
/datum/nanite_program/triggered/voice/set_extra_setting(user, setting)
/datum/nanite_program/triggered/comm/voice/set_extra_setting(user, setting)
if(setting == "Message")
var/new_message = stripped_input(user, "Choose the message sent to the host.", "Message", message, MAX_MESSAGE_LEN)
if(!new_message)
return
message = new_message
if(setting == "Comm Code")
var/new_code = input(user, "Set the communication code (1-9999) or set to 0 to disable external signals.", name, null) as null|num
if(isnull(new_code))
return
comm_code = CLAMP(round(new_code, 1), 0, 9999)
/datum/nanite_program/triggered/voice/get_extra_setting(setting)
/datum/nanite_program/triggered/comm/voice/get_extra_setting(setting)
if(setting == "Message")
return message
if(setting == "Comm Code")
return comm_code
/datum/nanite_program/triggered/voice/copy_extra_settings_to(datum/nanite_program/triggered/voice/target)
/datum/nanite_program/triggered/comm/voice/copy_extra_settings_to(datum/nanite_program/triggered/comm/voice/target)
target.message = message
target.comm_code = comm_code
/datum/nanite_program/triggered/voice/trigger()
/datum/nanite_program/triggered/comm/voice/trigger(comm_message)
if(!..())
return
var/sent_message = comm_message
if(!comm_message)
sent_message = message
if(host_mob.stat == DEAD)
return
to_chat(host_mob, "<i>You hear a strange, robotic voice in your head...</i> \"<span class='robot'>[message]</span>\"")
to_chat(host_mob, "<i>You hear a strange, robotic voice in your head...</i> \"<span class='robot'>[sent_message]</span>\"")
/datum/nanite_program/triggered/hallucination
/datum/nanite_program/triggered/comm/hallucination
name = "Hallucination"
desc = "The nanites make the host hallucinate something when triggered."
trigger_cost = 4
trigger_cooldown = 80
unique = FALSE
rogue_types = list(/datum/nanite_program/brain_misfire)
extra_settings = list("Hallucination Type")
extra_settings = list("Hallucination Type", "Comm Code")
var/hal_type
var/hal_details
/datum/nanite_program/triggered/hallucination/trigger()
/datum/nanite_program/triggered/comm/hallucination/trigger(comm_message)
if(!..())
return
if(comm_message && (hal_type != "Message")) //Triggered via comm remote, but not set to a message hallucination
return
var/sent_message = comm_message //Comm remotes can send custom hallucination messages for the chat hallucination
if(!sent_message)
sent_message = hal_details
if(!iscarbon(host_mob))
return
var/mob/living/carbon/C = host_mob
@@ -203,7 +244,7 @@
else
switch(hal_type)
if("Message")
new /datum/hallucination/chat(C, TRUE, null, hal_details)
new /datum/hallucination/chat(C, TRUE, null, sent_message)
if("Battle")
new /datum/hallucination/battle(C, TRUE, hal_details)
if("Sound")
@@ -223,7 +264,13 @@
if("Plasma Flood")
new /datum/hallucination/fake_flood(C, TRUE)
/datum/nanite_program/triggered/hallucination/set_extra_setting(user, setting)
/datum/nanite_program/triggered/comm/hallucination/set_extra_setting(user, setting)
if(setting == "Comm Code")
var/new_code = input(user, "(Only for Message) Set the communication code (1-9999) or set to 0 to disable external signals.", name, null) as null|num
if(isnull(new_code))
return
comm_code = CLAMP(round(new_code, 1), 0, 9999)
if(setting == "Hallucination Type")
var/list/possible_hallucinations = list("Random","Message","Battle","Sound","Weird Sound","Station Message","Health","Alert","Fire","Shock","Plasma Flood")
var/hal_type_choice = input("Choose the hallucination type", name) as null|anything in possible_hallucinations
@@ -299,13 +346,76 @@
if("Plasma Flood")
hal_type = "Plasma Flood"
/datum/nanite_program/triggered/hallucination/get_extra_setting(setting)
/datum/nanite_program/triggered/comm/hallucination/get_extra_setting(setting)
if(setting == "Hallucination Type")
if(!hal_type)
return "Random"
else
return hal_type
if(setting == "Comm Code")
return comm_code
/datum/nanite_program/triggered/hallucination/copy_extra_settings_to(datum/nanite_program/triggered/hallucination/target)
/datum/nanite_program/triggered/comm/hallucination/copy_extra_settings_to(datum/nanite_program/triggered/comm/hallucination/target)
target.hal_type = hal_type
target.hal_details = hal_details
target.hal_details = hal_details
target.comm_code = comm_code
/datum/nanite_program/good_mood
name = "Happiness Enhancer"
desc = "The nanites synthesize serotonin inside the host's brain, creating an artificial sense of happiness."
use_rate = 0.1
rogue_types = list(/datum/nanite_program/brain_decay)
extra_settings = list("Mood Message")
var/message = "HAPPINESS ENHANCEMENT"
/datum/nanite_program/good_mood/set_extra_setting(user, setting)
if(setting == "Mood Message")
var/new_message = stripped_input(user, "Choose the message visible on the mood effect.", "Message", message, MAX_NAME_LEN)
if(!new_message)
return
message = new_message
/datum/nanite_program/good_mood/get_extra_setting(setting)
if(setting == "Mood Message")
return message
/datum/nanite_program/good_mood/copy_extra_settings_to(datum/nanite_program/good_mood/target)
target.message = message
/datum/nanite_program/good_mood/enable_passive_effect()
. = ..()
SEND_SIGNAL(host_mob, COMSIG_ADD_MOOD_EVENT, "nanite_happy", /datum/mood_event/nanite_happiness, message)
/datum/nanite_program/good_mood/disable_passive_effect()
. = ..()
SEND_SIGNAL(host_mob, COMSIG_CLEAR_MOOD_EVENT, "nanite_happy")
/datum/nanite_program/bad_mood
name = "Happiness Suppressor"
desc = "The nanites suppress the production of serotonin inside the host's brain, creating an artificial state of depression."
use_rate = 0.1
rogue_types = list(/datum/nanite_program/brain_decay)
extra_settings = list("Mood Message")
var/message = "HAPPINESS SUPPRESSION"
/datum/nanite_program/bad_mood/set_extra_setting(user, setting)
if(setting == "Mood Message")
var/new_message = stripped_input(user, "Choose the message visible on the mood effect.", "Message", message, MAX_NAME_LEN)
if(!new_message)
return
message = new_message
/datum/nanite_program/bad_mood/get_extra_setting(setting)
if(setting == "Mood Message")
return message
/datum/nanite_program/bad_mood/copy_extra_settings_to(datum/nanite_program/bad_mood/target)
target.message = message
/datum/nanite_program/bad_mood/enable_passive_effect()
. = ..()
SEND_SIGNAL(host_mob, COMSIG_ADD_MOOD_EVENT, "nanite_sadness", /datum/mood_event/nanite_sadness, message)
/datum/nanite_program/bad_mood/disable_passive_effect()
. = ..()
SEND_SIGNAL(host_mob, COMSIG_CLEAR_MOOD_EVENT, "nanite_sadness")
@@ -6,6 +6,7 @@
rogue_types = list(/datum/nanite_program/toxic)
extra_settings = list("Program Overwrite","Cloud Overwrite")
var/pulse_cooldown = 0
var/sync_programs = TRUE
var/sync_overwrite = FALSE
var/overwrite_cloud = FALSE
@@ -67,12 +68,16 @@
target.sync_overwrite = sync_overwrite
/datum/nanite_program/viral/active_effect()
if(world.time < pulse_cooldown)
return
for(var/mob/M in orange(host_mob, 5))
if(prob(5))
if(sync_programs)
SEND_SIGNAL(M, COMSIG_NANITE_SYNC, nanites, sync_overwrite)
if(overwrite_cloud)
SEND_SIGNAL(M, COMSIG_NANITE_SET_CLOUD, set_cloud)
if(SEND_SIGNAL(M, COMSIG_NANITE_IS_STEALTHY))
continue
if(sync_programs)
SEND_SIGNAL(M, COMSIG_NANITE_SYNC, nanites, sync_overwrite)
if(overwrite_cloud)
SEND_SIGNAL(M, COMSIG_NANITE_SET_CLOUD, set_cloud)
pulse_cooldown = world.time + 75
/datum/nanite_program/monitoring
name = "Monitoring"
@@ -197,6 +202,15 @@
return
SEND_SIGNAL(host_mob, COMSIG_NANITE_SIGNAL, code, source)
/datum/nanite_program/relay/proc/relay_comm_signal(comm_code, relay_code, comm_message)
if(!activated)
return
if(!host_mob)
return
if(relay_code != relay_channel)
return
SEND_SIGNAL(host_mob, COMSIG_NANITE_COMM_SIGNAL, comm_code, comm_message)
/datum/nanite_program/metabolic_synthesis
name = "Metabolic Synthesis"
desc = "The nanites use the metabolic cycle of the host to speed up their replication rate, using their extra nutrition as fuel."
@@ -248,26 +262,27 @@
resulting in an extremely infective strain of nanites."
use_rate = 1.50
rogue_types = list(/datum/nanite_program/aggressive_replication, /datum/nanite_program/necrotic)
var/spread_cooldown = 0
/datum/nanite_program/spreading/active_effect()
if(prob(10))
var/list/mob/living/target_hosts = list()
var/turf/T = get_turf(host_mob)
for(var/mob/living/L in range(5, host_mob))
if(!(MOB_ORGANIC in L.mob_biotypes) && !(MOB_UNDEAD in L.mob_biotypes))
continue
if(!disease_air_spread_walk(T, get_turf(L)))
continue
target_hosts += L
target_hosts -= host_mob
if(!target_hosts.len)
return
var/mob/living/infectee = pick(target_hosts)
if(prob(100 - (infectee.get_permeability_protection() * 100)))
//this will potentially take over existing nanites!
infectee.AddComponent(/datum/component/nanites, 10)
SEND_SIGNAL(infectee, COMSIG_NANITE_SYNC, nanites)
infectee.investigate_log("[key_name(infectee)] was infected by spreading nanites by [key_name(host_mob)]", INVESTIGATE_NANITES)
if(spread_cooldown < world.time)
return
spread_cooldown = world.time + 50
var/list/mob/living/target_hosts = list()
for(var/mob/living/L in oview(5, host_mob))
if(!prob(25))
continue
if(!(L.mob_biotypes & (MOB_ORGANIC|MOB_UNDEAD)))
continue
target_hosts += L
if(!target_hosts.len)
return
var/mob/living/infectee = pick(target_hosts)
if(prob(100 - (infectee.get_permeability_protection() * 100)))
//this will potentially take over existing nanites!
infectee.AddComponent(/datum/component/nanites, 10)
SEND_SIGNAL(infectee, COMSIG_NANITE_SYNC, nanites)
infectee.investigate_log("was infected by spreading nanites by [key_name(host_mob)] at [AREACOORD(infectee)].", INVESTIGATE_NANITES)
/datum/nanite_program/mitosis
name = "Mitosis"
@@ -160,40 +160,55 @@
/datum/nanite_program/cryo/active_effect()
host_mob.adjust_bodytemperature(-rand(15,25), 50)
/datum/nanite_program/mind_control
/datum/nanite_program/triggered/comm/mind_control
name = "Mind Control"
desc = "The nanites imprint an absolute directive onto the host's brain while they're active."
use_rate = 3
desc = "The nanites imprint an absolute directive onto the host's brain for one minute when triggered."
trigger_cost = 30
trigger_cooldown = 1800
rogue_types = list(/datum/nanite_program/brain_decay, /datum/nanite_program/brain_misfire)
extra_settings = list("Directive")
var/cooldown = 0 //avoids spam when nanites are running low
extra_settings = list("Directive","Comm Code")
var/directive = "..."
/datum/nanite_program/mind_control/set_extra_setting(user, setting)
/datum/nanite_program/triggered/comm/mind_control/set_extra_setting(user, setting)
if(setting == "Directive")
var/new_directive = stripped_input(user, "Choose the directive to imprint with mind control.", "Directive", directive, MAX_MESSAGE_LEN)
if(!new_directive)
return
directive = new_directive
if(setting == "Comm Code")
var/new_code = input(user, "Set the communication code (1-9999) or set to 0 to disable external signals.", name, null) as null|num
if(isnull(new_code))
return
comm_code = CLAMP(round(new_code, 1), 0, 9999)
/datum/nanite_program/mind_control/get_extra_setting(setting)
/datum/nanite_program/triggered/comm/mind_control/get_extra_setting(setting)
if(setting == "Directive")
return directive
if(setting == "Comm Code")
return comm_code
/datum/nanite_program/mind_control/copy_extra_settings_to(datum/nanite_program/mind_control/target)
/datum/nanite_program/triggered/comm/mind_control/copy_extra_settings_to(datum/nanite_program/triggered/comm/mind_control/target)
target.directive = directive
target.comm_code = comm_code
/datum/nanite_program/mind_control/enable_passive_effect()
if(world.time < cooldown)
/datum/nanite_program/triggered/comm/mind_control/trigger(comm_message)
if(!..())
return
. = ..()
brainwash(host_mob, directive)
if(host_mob.stat == DEAD)
return
var/sent_directive = comm_message
if(!comm_message)
sent_directive = directive
brainwash(host_mob, sent_directive)
log_game("A mind control nanite program brainwashed [key_name(host_mob)] with the objective '[directive]'.")
addtimer(CALLBACK(src, .proc/end_brainwashing), 600)
/datum/nanite_program/mind_control/disable_passive_effect()
. = ..()
/datum/nanite_program/triggered/comm/mind_control/proc/end_brainwashing()
if(host_mob.mind && host_mob.mind.has_antag_datum(/datum/antagonist/brainwashed))
host_mob.mind.remove_antag_datum(/datum/antagonist/brainwashed)
log_game("[key_name(host_mob)] is no longer brainwashed by nanites.")
cooldown = world.time + 450
/datum/nanite_program/triggered/comm/mind_control/disable_passive_effect()
. = ..()
end_brainwashing()
@@ -168,6 +168,109 @@
. = TRUE
/obj/item/nanite_remote/comm
name = "nanite communication remote"
desc = "A device that can send text messages to specific programs."
icon_state = "nanite_comm_remote"
var/comm_code = 0
var/comm_message = ""
/obj/item/nanite_remote/comm/afterattack(atom/target, mob/user, etc)
switch(mode)
if(REMOTE_MODE_OFF)
return
if(REMOTE_MODE_SELF)
to_chat(user, "<span class='notice'>You activate [src], signaling the nanites in your bloodstream.<span>")
signal_mob(user, comm_code, comm_message)
if(REMOTE_MODE_TARGET)
if(isliving(target) && (get_dist(target, get_turf(src)) <= 7))
to_chat(user, "<span class='notice'>You activate [src], signaling the nanites inside [target].<span>")
signal_mob(target, code, comm_message, key_name(user))
if(REMOTE_MODE_AOE)
to_chat(user, "<span class='notice'>You activate [src], signaling the nanites inside every host around you.<span>")
for(var/mob/living/L in view(user, 7))
signal_mob(L, code, comm_message, key_name(user))
if(REMOTE_MODE_RELAY)
to_chat(user, "<span class='notice'>You activate [src], signaling all connected relay nanites.<span>")
signal_relay(code, relay_code, comm_message, key_name(user))
/obj/item/nanite_remote/comm/signal_mob(mob/living/M, code, source)
SEND_SIGNAL(M, COMSIG_NANITE_COMM_SIGNAL, comm_code, comm_message)
/obj/item/nanite_remote/comm/signal_relay(code, relay_code, source)
for(var/X in SSnanites.nanite_relays)
var/datum/nanite_program/relay/N = X
N.relay_comm_signal(comm_code, relay_code, comm_message)
/obj/item/nanite_remote/comm/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.hands_state)
SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
ui = new(user, src, ui_key, "nanite_comm_remote", name, 420, 800, master_ui, state)
ui.open()
/obj/item/nanite_remote/comm/ui_data()
var/list/data = list()
data["comm_code"] = comm_code
data["relay_code"] = relay_code
data["comm_message"] = comm_message
data["mode"] = mode
data["locked"] = locked
data["saved_settings"] = saved_settings
return data
/obj/item/nanite_remote/comm/ui_act(action, params)
if(..())
return
switch(action)
if("set_comm_code")
if(locked)
return
var/new_code = input("Set comm code (0000-9999):", name, code) as null|num
if(!isnull(new_code))
new_code = CLAMP(round(new_code, 1),0,9999)
comm_code = new_code
. = TRUE
if("set_message")
if(locked)
return
var/new_message = stripped_input(usr, "Set the message (Max 300 characters):", "Set Message", null , 300)
if(!new_message)
return
comm_message = new_message
. = TRUE
if("comm_save")
if(locked)
return
var/code_name = stripped_input(usr, "Set the setting name", "Set Name", null , 15)
if(!code_name)
return
var/new_save = list()
new_save["id"] = last_id + 1
last_id++
new_save["name"] = code_name
new_save["code"] = comm_code
new_save["mode"] = mode
new_save["relay_code"] = relay_code
new_save["message"] = comm_message
saved_settings += list(new_save)
. = TRUE
if("comm_load")
var/code_id = params["save_id"]
var/list/setting
for(var/list/X in saved_settings)
if(X["id"] == text2num(code_id))
setting = X
break
if(setting)
comm_code = setting["code"]
mode = setting["mode"]
relay_code = setting["relay_code"]
comm_message = setting["message"]
. = TRUE
#undef REMOTE_MODE_OFF
#undef REMOTE_MODE_SELF
#undef REMOTE_MODE_TARGET
@@ -142,4 +142,10 @@
program_type = /datum/nanite_program/researchplus
/obj/item/disk/nanite_program/reduced_diagnostics
program_type = /datum/nanite_program/reduced_diagnostics
program_type = /datum/nanite_program/reduced_diagnostics
/obj/item/disk/nanite_program/good_mood
program_type = /datum/nanite_program/good_mood
/obj/item/disk/nanite_program/bad_mood
program_type = /datum/nanite_program/bad_mood
+2 -2
View File
@@ -976,7 +976,7 @@
display_name = "Basic Nanite Programming"
description = "The basics of nanite construction and programming."
prereq_ids = list("datatheory","robotics")
design_ids = list("nanite_disk","nanite_remote","nanite_scanner",\
design_ids = list("nanite_disk","nanite_remote","nanite_comm_remote","nanite_scanner",\
"nanite_chamber","public_nanite_chamber","nanite_chamber_control","nanite_programmer","nanite_program_hub","nanite_cloud_control",\
"relay_nanites", "monitoring_nanites", "access_nanites", "repairing_nanites","sensor_nanite_volume", "repeater_nanites", "relay_repeater_nanites","red_diag_nanites")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
@@ -1015,7 +1015,7 @@
display_name = "Neural Nanite Programming"
description = "Nanite programs affecting nerves and brain matter."
prereq_ids = list("nanite_bio")
design_ids = list("nervous_nanites", "brainheal_nanites", "paralyzing_nanites", "stun_nanites", "selfscan_nanites")
design_ids = list("nervous_nanites", "brainheal_nanites", "paralyzing_nanites", "stun_nanites", "selfscan_nanites","good_mood_nanites","bad_mood_nanites")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500)
export_price = 5000
@@ -99,5 +99,6 @@
/obj/effect/dummy/phased_mob/spell_jaunt/ex_act(blah)
return
/obj/effect/dummy/phased_mob/spell_jaunt/bullet_act(blah)
return
return BULLET_ACT_FORCE_PIERCE
@@ -91,7 +91,7 @@
return
/obj/effect/dummy/phased_mob/shadow/bullet_act()
return
return BULLET_ACT_FORCE_PIERCE
/obj/effect/dummy/phased_mob/shadow/singularity_act()
return
+2 -1
View File
@@ -21,6 +21,7 @@
range = 2
/obj/item/projectile/sickshot/on_hit(var/atom/movable/target, var/blocked = 0)
. = ..()
if(iscarbon(target))
var/mob/living/carbon/H = target
if(prob(5))
@@ -28,7 +29,7 @@
H.release_vore_contents()
H.visible_message("<span class='danger'>[H] contracts strangely, spewing out contents on the floor!</span>", \
"<span class='userdanger'>You spew out everything inside you on the floor!</span>")
return
return BULLET_ACT_HIT
////////////////////////// Anti-Noms Drugs //////////////////////////
+12 -8
View File
@@ -42,7 +42,8 @@
impact_type = /obj/effect/projectile/xray/impact
/obj/item/projectile/beam/shrinklaser/on_hit(var/atom/target, var/blocked = 0)
if(istype(target, /mob/living))
. = ..()
if(isliving(target))
var/mob/living/M = target
switch(M.size_multiplier)
if(SIZESCALE_HUGE to INFINITY)
@@ -54,7 +55,7 @@
if((0 - INFINITY) to SIZESCALE_NORMAL)
M.sizescale(SIZESCALE_TINY)
M.update_transform()
return 1
return BULLET_ACT_HIT
/obj/item/projectile/beam/growlaser
name = "growth beam"
@@ -68,7 +69,8 @@
impact_type = /obj/effect/projectile/laser_blue/impact
/obj/item/projectile/beam/growlaser/on_hit(var/atom/target, var/blocked = 0)
if(istype(target, /mob/living))
. = ..()
if(isliving(target))
var/mob/living/M = target
switch(M.size_multiplier)
if(SIZESCALE_BIG to SIZESCALE_HUGE)
@@ -80,7 +82,7 @@
if((0 - INFINITY) to SIZESCALE_TINY)
M.sizescale(SIZESCALE_SMALL)
M.update_transform()
return 1
return BULLET_ACT_HIT
*/
datum/design/sizeray
@@ -108,7 +110,8 @@ datum/design/sizeray
icon_state="laser"
/obj/item/projectile/sizeray/shrinkray/on_hit(var/atom/target, var/blocked = 0)
if(istype(target, /mob/living))
. = ..()
if(isliving(target))
var/mob/living/M = target
switch(M.size_multiplier)
if(SIZESCALE_HUGE to INFINITY)
@@ -120,10 +123,11 @@ datum/design/sizeray
if((0 - INFINITY) to SIZESCALE_NORMAL)
M.sizescale(SIZESCALE_TINY)
M.update_transform()
return 1
return BULLET_ACT_
/obj/item/projectile/sizeray/growthray/on_hit(var/atom/target, var/blocked = 0)
if(istype(target, /mob/living))
. = ..()
if(isliving(target))
var/mob/living/M = target
switch(M.size_multiplier)
if(SIZESCALE_BIG to SIZESCALE_HUGE)
@@ -135,7 +139,7 @@ datum/design/sizeray
if((0 - INFINITY) to SIZESCALE_TINY)
M.sizescale(SIZESCALE_SMALL)
M.update_transform()
return 1
return BULLET_ACT_HIT
/obj/item/ammo_casing/energy/laser/growthray
projectile_type = /obj/item/projectile/sizeray/growthray