mirror of
https://github.com/KabKebab/GS13.git
synced 2026-07-18 19:39:53 +01:00
Uploading all files.
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
|
||||
|
||||
/atom/movable
|
||||
var/can_buckle = 0
|
||||
var/buckle_lying = -1 //bed-like behaviour, forces mob.lying = buckle_lying if != -1
|
||||
var/buckle_requires_restraints = 0 //require people to be handcuffed before being able to buckle. eg: pipes
|
||||
var/list/mob/living/buckled_mobs = null //list()
|
||||
var/max_buckled_mobs = 1
|
||||
var/buckle_prevents_pull = FALSE
|
||||
|
||||
//Interaction
|
||||
/atom/movable/attack_hand(mob/living/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(can_buckle && has_buckled_mobs())
|
||||
if(buckled_mobs.len > 1)
|
||||
var/unbuckled = input(user, "Who do you wish to unbuckle?","Unbuckle Who?") as null|mob in buckled_mobs
|
||||
if(user_unbuckle_mob(unbuckled,user))
|
||||
return 1
|
||||
else
|
||||
if(user_unbuckle_mob(buckled_mobs[1],user))
|
||||
return 1
|
||||
|
||||
/atom/movable/MouseDrop_T(mob/living/M, mob/living/user)
|
||||
. = ..()
|
||||
if(can_buckle && istype(M) && istype(user))
|
||||
if(user_buckle_mob(M, user))
|
||||
return 1
|
||||
|
||||
/atom/movable/proc/has_buckled_mobs()
|
||||
if(!buckled_mobs)
|
||||
return FALSE
|
||||
if(buckled_mobs.len)
|
||||
return TRUE
|
||||
|
||||
//procs that handle the actual buckling and unbuckling
|
||||
/atom/movable/proc/buckle_mob(mob/living/M, force = FALSE, check_loc = TRUE)
|
||||
if(!buckled_mobs)
|
||||
buckled_mobs = list()
|
||||
|
||||
if(!istype(M))
|
||||
return FALSE
|
||||
|
||||
if(check_loc && M.loc != loc)
|
||||
return FALSE
|
||||
|
||||
if((!can_buckle && !force) || M.buckled || (buckled_mobs.len >= max_buckled_mobs) || (buckle_requires_restraints && !M.restrained()) || M == src)
|
||||
return FALSE
|
||||
M.buckling = src
|
||||
if(!M.can_buckle() && !force)
|
||||
if(M == usr)
|
||||
to_chat(M, "<span class='warning'>You are unable to buckle yourself to [src]!</span>")
|
||||
else
|
||||
to_chat(usr, "<span class='warning'>You are unable to buckle [M] to [src]!</span>")
|
||||
M.buckling = null
|
||||
return FALSE
|
||||
|
||||
if(M.pulledby && buckle_prevents_pull)
|
||||
M.pulledby.stop_pulling()
|
||||
|
||||
if(!check_loc && M.loc != loc)
|
||||
M.forceMove(loc)
|
||||
|
||||
M.buckling = null
|
||||
M.buckled = src
|
||||
M.setDir(dir)
|
||||
buckled_mobs |= M
|
||||
M.update_canmove()
|
||||
M.throw_alert("buckled", /obj/screen/alert/restrained/buckled)
|
||||
post_buckle_mob(M)
|
||||
|
||||
SEND_SIGNAL(src, COMSIG_MOVABLE_BUCKLE, M, force)
|
||||
return TRUE
|
||||
|
||||
/obj/buckle_mob(mob/living/M, force = FALSE, check_loc = TRUE)
|
||||
. = ..()
|
||||
if(.)
|
||||
if(resistance_flags & ON_FIRE) //Sets the mob on fire if you buckle them to a burning atom/movableect
|
||||
M.adjust_fire_stacks(1)
|
||||
M.IgniteMob()
|
||||
|
||||
/atom/movable/proc/unbuckle_mob(mob/living/buckled_mob, force=FALSE)
|
||||
if(istype(buckled_mob) && buckled_mob.buckled == src && (buckled_mob.can_unbuckle() || force))
|
||||
. = buckled_mob
|
||||
buckled_mob.buckled = null
|
||||
buckled_mob.anchored = initial(buckled_mob.anchored)
|
||||
buckled_mob.update_canmove()
|
||||
buckled_mob.clear_alert("buckled")
|
||||
buckled_mobs -= buckled_mob
|
||||
SEND_SIGNAL(src, COMSIG_MOVABLE_UNBUCKLE, buckled_mob, force)
|
||||
|
||||
post_unbuckle_mob(.)
|
||||
|
||||
/atom/movable/proc/unbuckle_all_mobs(force=FALSE)
|
||||
if(!has_buckled_mobs())
|
||||
return
|
||||
for(var/m in buckled_mobs)
|
||||
unbuckle_mob(m, force)
|
||||
|
||||
//Handle any extras after buckling
|
||||
//Called on buckle_mob()
|
||||
/atom/movable/proc/post_buckle_mob(mob/living/M)
|
||||
|
||||
//same but for unbuckle
|
||||
/atom/movable/proc/post_unbuckle_mob(mob/living/M)
|
||||
|
||||
//Wrapper procs that handle sanity and user feedback
|
||||
/atom/movable/proc/user_buckle_mob(mob/living/M, mob/user, check_loc = TRUE)
|
||||
if(!in_range(user, src) || !isturf(user.loc) || user.incapacitated() || M.anchored)
|
||||
return FALSE
|
||||
|
||||
add_fingerprint(user)
|
||||
. = buckle_mob(M, check_loc = check_loc)
|
||||
if(.)
|
||||
if(M == user)
|
||||
M.visible_message(\
|
||||
"<span class='notice'>[M] buckles [M.p_them()]self to [src].</span>",\
|
||||
"<span class='notice'>You buckle yourself to [src].</span>",\
|
||||
"<span class='italics'>You hear metal clanking.</span>")
|
||||
else
|
||||
M.visible_message(\
|
||||
"<span class='warning'>[user] buckles [M] to [src]!</span>",\
|
||||
"<span class='warning'>[user] buckles you to [src]!</span>",\
|
||||
"<span class='italics'>You hear metal clanking.</span>")
|
||||
|
||||
/atom/movable/proc/user_unbuckle_mob(mob/living/buckled_mob, mob/user)
|
||||
var/mob/living/M = unbuckle_mob(buckled_mob)
|
||||
if(M)
|
||||
if(M != user)
|
||||
M.visible_message(\
|
||||
"<span class='notice'>[user] unbuckles [M] from [src].</span>",\
|
||||
"<span class='notice'>[user] unbuckles you from [src].</span>",\
|
||||
"<span class='italics'>You hear metal clanking.</span>")
|
||||
else
|
||||
M.visible_message(\
|
||||
"<span class='notice'>[M] unbuckles [M.p_them()]self from [src].</span>",\
|
||||
"<span class='notice'>You unbuckle yourself from [src].</span>",\
|
||||
"<span class='italics'>You hear metal clanking.</span>")
|
||||
add_fingerprint(user)
|
||||
return M
|
||||
@@ -0,0 +1,92 @@
|
||||
/obj/effect/acid
|
||||
gender = PLURAL
|
||||
name = "acid"
|
||||
desc = "Burbling corrosive stuff."
|
||||
icon_state = "acid"
|
||||
density = FALSE
|
||||
opacity = 0
|
||||
anchored = TRUE
|
||||
resistance_flags = FIRE_PROOF | UNACIDABLE | ACID_PROOF
|
||||
layer = ABOVE_NORMAL_TURF_LAYER
|
||||
var/turf/target
|
||||
|
||||
|
||||
/obj/effect/acid/Initialize(mapload, acid_pwr, acid_amt)
|
||||
. = ..()
|
||||
|
||||
target = get_turf(src)
|
||||
|
||||
if(acid_amt)
|
||||
acid_level = min( (CLAMP(round(acid_amt, 1), 0, INFINITY)) *acid_pwr, 12000) //capped so the acid effect doesn't last a half hour on the floor.
|
||||
|
||||
//handle APCs and newscasters and stuff nicely
|
||||
pixel_x = target.pixel_x + rand(-4,4)
|
||||
pixel_y = target.pixel_y + rand(-4,4)
|
||||
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
|
||||
/obj/effect/acid/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
target = null
|
||||
return ..()
|
||||
|
||||
/obj/effect/acid/process()
|
||||
. = 1
|
||||
if(!target)
|
||||
qdel(src)
|
||||
return 0
|
||||
|
||||
if(prob(5))
|
||||
playsound(loc, 'sound/items/welder.ogg', 100, 1)
|
||||
|
||||
for(var/obj/O in target)
|
||||
if(prob(20) && !(resistance_flags & UNACIDABLE))
|
||||
if(O.acid_level < acid_level*0.3)
|
||||
var/acid_used = min(acid_level*0.05, 20)
|
||||
O.acid_act(10, acid_used)
|
||||
acid_level = max(0, acid_level - acid_used*10)
|
||||
|
||||
acid_level = max(acid_level - (5 + 2*round(sqrt(acid_level))), 0)
|
||||
if(acid_level <= 0)
|
||||
qdel(src)
|
||||
return 0
|
||||
|
||||
/obj/effect/acid/Crossed(AM as mob|obj)
|
||||
if(isliving(AM))
|
||||
var/mob/living/L = AM
|
||||
if(L.movement_type & FLYING)
|
||||
return
|
||||
if(L.m_intent != MOVE_INTENT_WALK && prob(40))
|
||||
var/acid_used = min(acid_level*0.05, 20)
|
||||
if(L.acid_act(10, acid_used, "feet"))
|
||||
acid_level = max(0, acid_level - acid_used*10)
|
||||
playsound(L, 'sound/weapons/sear.ogg', 50, 1)
|
||||
to_chat(L, "<span class='userdanger'>[src] burns you!</span>")
|
||||
|
||||
//xenomorph corrosive acid
|
||||
/obj/effect/acid/alien
|
||||
var/target_strength = 30
|
||||
|
||||
|
||||
/obj/effect/acid/alien/process()
|
||||
. = ..()
|
||||
if(.)
|
||||
if(prob(45))
|
||||
playsound(loc, 'sound/items/welder.ogg', 100, 1)
|
||||
target_strength--
|
||||
if(target_strength <= 0)
|
||||
target.visible_message("<span class='warning'>[target] collapses under its own weight into a puddle of goop and undigested debris!</span>")
|
||||
target.acid_melt()
|
||||
qdel(src)
|
||||
else
|
||||
|
||||
switch(target_strength)
|
||||
if(24)
|
||||
visible_message("<span class='warning'>[target] is holding up against the acid!</span>")
|
||||
if(16)
|
||||
visible_message("<span class='warning'>[target] is being melted by the acid!</span>")
|
||||
if(8)
|
||||
visible_message("<span class='warning'>[target] is struggling to withstand the acid!</span>")
|
||||
if(4)
|
||||
visible_message("<span class='warning'>[target] begins to crumble under the acid!</span>")
|
||||
@@ -0,0 +1,336 @@
|
||||
//Anomalies, used for events. Note that these DO NOT work by themselves; their procs are called by the event datum.
|
||||
|
||||
/obj/effect/anomaly
|
||||
name = "anomaly"
|
||||
desc = "A mysterious anomaly, seen commonly only in the region of space that the station orbits..."
|
||||
icon_state = "bhole3"
|
||||
density = FALSE
|
||||
anchored = TRUE
|
||||
light_range = 3
|
||||
var/movechance = 70
|
||||
var/obj/item/assembly/signaler/anomaly/aSignal
|
||||
var/area/impact_area
|
||||
|
||||
var/lifespan = 990
|
||||
var/death_time
|
||||
|
||||
var/countdown_colour
|
||||
var/obj/effect/countdown/anomaly/countdown
|
||||
|
||||
/obj/effect/anomaly/Initialize(mapload, new_lifespan)
|
||||
. = ..()
|
||||
GLOB.poi_list |= src
|
||||
START_PROCESSING(SSobj, src)
|
||||
impact_area = get_area(src)
|
||||
|
||||
aSignal = new(src)
|
||||
aSignal.name = "[name] core"
|
||||
aSignal.code = rand(1,100)
|
||||
aSignal.anomaly_type = type
|
||||
|
||||
var/frequency = rand(MIN_FREE_FREQ, MAX_FREE_FREQ)
|
||||
if(ISMULTIPLE(frequency, 2))//signaller frequencies are always uneven!
|
||||
frequency++
|
||||
aSignal.set_frequency(frequency)
|
||||
|
||||
if(new_lifespan)
|
||||
lifespan = new_lifespan
|
||||
death_time = world.time + lifespan
|
||||
countdown = new(src)
|
||||
if(countdown_colour)
|
||||
countdown.color = countdown_colour
|
||||
countdown.start()
|
||||
|
||||
/obj/effect/anomaly/process()
|
||||
anomalyEffect()
|
||||
if(death_time < world.time)
|
||||
if(loc)
|
||||
detonate()
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/anomaly/Destroy()
|
||||
GLOB.poi_list.Remove(src)
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
qdel(countdown)
|
||||
return ..()
|
||||
|
||||
/obj/effect/anomaly/proc/anomalyEffect()
|
||||
if(prob(movechance))
|
||||
step(src,pick(GLOB.alldirs))
|
||||
|
||||
/obj/effect/anomaly/proc/detonate()
|
||||
return
|
||||
|
||||
/obj/effect/anomaly/ex_act(severity, target)
|
||||
if(severity == 1)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/anomaly/proc/anomalyNeutralize()
|
||||
new /obj/effect/particle_effect/smoke/bad(loc)
|
||||
|
||||
for(var/atom/movable/O in src)
|
||||
O.forceMove(drop_location())
|
||||
|
||||
qdel(src)
|
||||
|
||||
|
||||
/obj/effect/anomaly/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/analyzer))
|
||||
to_chat(user, "<span class='notice'>Analyzing... [src]'s unstable field is fluctuating along frequency [format_frequency(aSignal.frequency)], code [aSignal.code].</span>")
|
||||
|
||||
///////////////////////
|
||||
|
||||
/obj/effect/anomaly/grav
|
||||
name = "gravitational anomaly"
|
||||
icon_state = "shield2"
|
||||
density = FALSE
|
||||
var/boing = 0
|
||||
|
||||
/obj/effect/anomaly/grav/anomalyEffect()
|
||||
..()
|
||||
boing = 1
|
||||
for(var/obj/O in orange(4, src))
|
||||
if(!O.anchored)
|
||||
step_towards(O,src)
|
||||
for(var/mob/living/M in range(0, src))
|
||||
gravShock(M)
|
||||
for(var/mob/living/M in orange(4, src))
|
||||
step_towards(M,src)
|
||||
for(var/obj/O in range(0,src))
|
||||
if(!O.anchored)
|
||||
var/mob/living/target = locate() in view(4,src)
|
||||
if(target && !target.stat)
|
||||
O.throw_at(target, 5, 10)
|
||||
|
||||
/obj/effect/anomaly/grav/Crossed(mob/A)
|
||||
gravShock(A)
|
||||
|
||||
/obj/effect/anomaly/grav/Bump(mob/A)
|
||||
gravShock(A)
|
||||
|
||||
/obj/effect/anomaly/grav/Bumped(atom/movable/AM)
|
||||
gravShock(AM)
|
||||
|
||||
/obj/effect/anomaly/grav/proc/gravShock(mob/living/A)
|
||||
if(boing && isliving(A) && !A.stat)
|
||||
A.Knockdown(40)
|
||||
var/atom/target = get_edge_target_turf(A, get_dir(src, get_step_away(A, src)))
|
||||
A.throw_at(target, 5, 1)
|
||||
boing = 0
|
||||
|
||||
/obj/effect/anomaly/grav/high
|
||||
var/grav_field
|
||||
|
||||
/obj/effect/anomaly/grav/high/Initialize(mapload, new_lifespan)
|
||||
. = ..()
|
||||
setup_grav_field()
|
||||
|
||||
/obj/effect/anomaly/grav/high/proc/setup_grav_field()
|
||||
grav_field = make_field(/datum/proximity_monitor/advanced/gravity, list("current_range" = 7, "host" = src, "gravity_value" = rand(0,3)))
|
||||
|
||||
/obj/effect/anomaly/grav/high/Destroy()
|
||||
QDEL_NULL(grav_field)
|
||||
. = ..()
|
||||
|
||||
/////////////////////
|
||||
|
||||
/obj/effect/anomaly/flux
|
||||
name = "flux wave anomaly"
|
||||
icon_state = "electricity2"
|
||||
density = TRUE
|
||||
var/canshock = 0
|
||||
var/shockdamage = 20
|
||||
var/explosive = TRUE
|
||||
|
||||
/obj/effect/anomaly/flux/anomalyEffect()
|
||||
..()
|
||||
canshock = 1
|
||||
for(var/mob/living/M in range(0, src))
|
||||
mobShock(M)
|
||||
|
||||
/obj/effect/anomaly/flux/Crossed(mob/living/M)
|
||||
mobShock(M)
|
||||
|
||||
/obj/effect/anomaly/flux/Bump(mob/living/M)
|
||||
mobShock(M)
|
||||
|
||||
/obj/effect/anomaly/flux/Bumped(atom/movable/AM)
|
||||
mobShock(AM)
|
||||
|
||||
/obj/effect/anomaly/flux/proc/mobShock(mob/living/M)
|
||||
if(canshock && istype(M))
|
||||
canshock = 0 //Just so you don't instakill yourself if you slam into the anomaly five times in a second.
|
||||
if(iscarbon(M))
|
||||
if(ishuman(M))
|
||||
M.electrocute_act(shockdamage, "[name]", safety=1)
|
||||
return
|
||||
M.electrocute_act(shockdamage, "[name]")
|
||||
return
|
||||
else
|
||||
M.adjustFireLoss(shockdamage)
|
||||
M.visible_message("<span class='danger'>[M] was shocked by \the [name]!</span>", \
|
||||
"<span class='userdanger'>You feel a powerful shock coursing through your body!</span>", \
|
||||
"<span class='italics'>You hear a heavy electrical crack.</span>")
|
||||
|
||||
/obj/effect/anomaly/flux/detonate()
|
||||
if(explosive)
|
||||
explosion(src, 1, 4, 16, 18) //Low devastation, but hits a lot of stuff.
|
||||
else
|
||||
new /obj/effect/particle_effect/sparks(loc)
|
||||
|
||||
|
||||
/////////////////////
|
||||
|
||||
/obj/effect/anomaly/bluespace
|
||||
name = "bluespace anomaly"
|
||||
icon = 'icons/obj/projectiles.dmi'
|
||||
icon_state = "bluespace"
|
||||
density = TRUE
|
||||
|
||||
/obj/effect/anomaly/bluespace/anomalyEffect()
|
||||
..()
|
||||
for(var/mob/living/M in range(1,src))
|
||||
do_teleport(M, locate(M.x, M.y, M.z), 4, channel = TELEPORT_CHANNEL_BLUESPACE)
|
||||
|
||||
/obj/effect/anomaly/bluespace/Bumped(atom/movable/AM)
|
||||
if(isliving(AM))
|
||||
do_teleport(AM, locate(AM.x, AM.y, AM.z), 8, channel = TELEPORT_CHANNEL_BLUESPACE)
|
||||
|
||||
/obj/effect/anomaly/bluespace/detonate()
|
||||
var/turf/T = safepick(get_area_turfs(impact_area))
|
||||
if(T)
|
||||
// Calculate new position (searches through beacons in world)
|
||||
var/obj/item/beacon/chosen
|
||||
var/list/possible = list()
|
||||
for(var/obj/item/beacon/W in GLOB.teleportbeacons)
|
||||
possible += W
|
||||
|
||||
if(possible.len > 0)
|
||||
chosen = pick(possible)
|
||||
|
||||
if(chosen)
|
||||
// Calculate previous position for transition
|
||||
|
||||
var/turf/FROM = T // the turf of origin we're travelling FROM
|
||||
var/turf/TO = get_turf(chosen) // the turf of origin we're travelling TO
|
||||
|
||||
playsound(TO, 'sound/effects/phasein.ogg', 100, 1)
|
||||
priority_announce("Massive bluespace translocation detected.", "Anomaly Alert")
|
||||
|
||||
var/list/flashers = list()
|
||||
for(var/mob/living/carbon/C in viewers(TO, null))
|
||||
if(C.flash_act())
|
||||
flashers += C
|
||||
|
||||
var/y_distance = TO.y - FROM.y
|
||||
var/x_distance = TO.x - FROM.x
|
||||
for (var/atom/movable/A in urange(12, FROM )) // iterate thru list of mobs in the area
|
||||
if(istype(A, /obj/item/beacon))
|
||||
continue // don't teleport beacons because that's just insanely stupid
|
||||
if(A.anchored)
|
||||
continue
|
||||
|
||||
var/turf/newloc = locate(A.x + x_distance, A.y + y_distance, TO.z) // calculate the new place
|
||||
if(!A.Move(newloc) && newloc) // if the atom, for some reason, can't move, FORCE them to move! :) We try Move() first to invoke any movement-related checks the atom needs to perform after moving
|
||||
A.forceMove(newloc)
|
||||
|
||||
spawn()
|
||||
if(ismob(A) && !(A in flashers)) // don't flash if we're already doing an effect
|
||||
var/mob/M = A
|
||||
if(M.client)
|
||||
var/obj/blueeffect = new /obj(src)
|
||||
blueeffect.screen_loc = "WEST,SOUTH to EAST,NORTH"
|
||||
blueeffect.icon = 'icons/effects/effects.dmi'
|
||||
blueeffect.icon_state = "shieldsparkles"
|
||||
blueeffect.layer = FLASH_LAYER
|
||||
blueeffect.plane = FULLSCREEN_PLANE
|
||||
blueeffect.mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
M.client.screen += blueeffect
|
||||
sleep(20)
|
||||
M.client.screen -= blueeffect
|
||||
qdel(blueeffect)
|
||||
|
||||
/////////////////////
|
||||
|
||||
/obj/effect/anomaly/pyro
|
||||
name = "pyroclastic anomaly"
|
||||
icon_state = "mustard"
|
||||
var/ticks = 0
|
||||
|
||||
/obj/effect/anomaly/pyro/anomalyEffect()
|
||||
..()
|
||||
ticks++
|
||||
if(ticks < 5)
|
||||
return
|
||||
else
|
||||
ticks = 0
|
||||
var/turf/open/T = get_turf(src)
|
||||
if(istype(T))
|
||||
T.atmos_spawn_air("o2=5;plasma=5;TEMP=1000")
|
||||
|
||||
/obj/effect/anomaly/pyro/detonate()
|
||||
INVOKE_ASYNC(src, .proc/makepyroslime)
|
||||
|
||||
/obj/effect/anomaly/pyro/proc/makepyroslime()
|
||||
var/turf/open/T = get_turf(src)
|
||||
if(istype(T))
|
||||
T.atmos_spawn_air("o2=500;plasma=500;TEMP=1000") //Make it hot and burny for the new slime
|
||||
var/new_colour = pick("red", "orange")
|
||||
var/mob/living/simple_animal/slime/S = new(T, new_colour)
|
||||
S.rabid = TRUE
|
||||
S.amount_grown = SLIME_EVOLUTION_THRESHOLD
|
||||
S.Evolve()
|
||||
offer_control(S)
|
||||
|
||||
/////////////////////
|
||||
|
||||
/obj/effect/anomaly/bhole
|
||||
name = "vortex anomaly"
|
||||
icon_state = "bhole3"
|
||||
desc = "That's a nice station you have there. It'd be a shame if something happened to it."
|
||||
|
||||
/obj/effect/anomaly/bhole/anomalyEffect()
|
||||
..()
|
||||
if(!isturf(loc)) //blackhole cannot be contained inside anything. Weird stuff might happen
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
grav(rand(0,3), rand(2,3), 50, 25)
|
||||
|
||||
//Throwing stuff around!
|
||||
for(var/obj/O in range(2,src))
|
||||
if(O == src)
|
||||
return //DON'T DELETE YOURSELF GOD DAMN
|
||||
if(!O.anchored)
|
||||
var/mob/living/target = locate() in view(4,src)
|
||||
if(target && !target.stat)
|
||||
O.throw_at(target, 7, 5)
|
||||
else
|
||||
O.ex_act(EXPLODE_HEAVY)
|
||||
|
||||
/obj/effect/anomaly/bhole/proc/grav(r, ex_act_force, pull_chance, turf_removal_chance)
|
||||
for(var/t = -r, t < r, t++)
|
||||
affect_coord(x+t, y-r, ex_act_force, pull_chance, turf_removal_chance)
|
||||
affect_coord(x-t, y+r, ex_act_force, pull_chance, turf_removal_chance)
|
||||
affect_coord(x+r, y+t, ex_act_force, pull_chance, turf_removal_chance)
|
||||
affect_coord(x-r, y-t, ex_act_force, pull_chance, turf_removal_chance)
|
||||
|
||||
/obj/effect/anomaly/bhole/proc/affect_coord(x, y, ex_act_force, pull_chance, turf_removal_chance)
|
||||
//Get turf at coordinate
|
||||
var/turf/T = locate(x, y, z)
|
||||
if(isnull(T))
|
||||
return
|
||||
|
||||
//Pulling and/or ex_act-ing movable atoms in that turf
|
||||
if(prob(pull_chance))
|
||||
for(var/obj/O in T.contents)
|
||||
if(O.anchored)
|
||||
O.ex_act(ex_act_force)
|
||||
else
|
||||
step_towards(O,src)
|
||||
for(var/mob/living/M in T.contents)
|
||||
step_towards(M,src)
|
||||
|
||||
//Damaging the turf
|
||||
if( T && prob(turf_removal_chance) )
|
||||
T.ex_act(ex_act_force)
|
||||
@@ -0,0 +1,27 @@
|
||||
/obj/effect/blessing
|
||||
name = "holy blessing"
|
||||
desc = "Holy energies interfere with ethereal travel at this location."
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
icon_state = null
|
||||
anchored = TRUE
|
||||
density = FALSE
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
|
||||
/obj/effect/blessing/Initialize(mapload)
|
||||
. = ..()
|
||||
for(var/obj/effect/blessing/B in loc)
|
||||
if(B != src)
|
||||
return INITIALIZE_HINT_QDEL
|
||||
var/image/I = image(icon = 'icons/effects/effects.dmi', icon_state = "blessed", layer = ABOVE_OPEN_TURF_LAYER, loc = src)
|
||||
I.alpha = 64
|
||||
I.appearance_flags = RESET_ALPHA
|
||||
add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/blessedAware, "blessing", I)
|
||||
RegisterSignal(loc, COMSIG_ATOM_INTERCEPT_TELEPORT, .proc/block_cult_teleport)
|
||||
|
||||
/obj/effect/blessing/Destroy()
|
||||
UnregisterSignal(loc, COMSIG_ATOM_INTERCEPT_TELEPORT)
|
||||
return ..()
|
||||
|
||||
/obj/effect/blessing/proc/block_cult_teleport(datum/source, channel, turf/origin, turf/destination)
|
||||
if(channel == TELEPORT_CHANNEL_CULT)
|
||||
return COMPONENT_BLOCK_TELEPORT
|
||||
@@ -0,0 +1,37 @@
|
||||
/obj/effect/bump_teleporter
|
||||
name = "bump-teleporter"
|
||||
icon = 'icons/mob/screen_gen.dmi'
|
||||
icon_state = "x2"
|
||||
var/id = null //id of this bump_teleporter.
|
||||
var/id_target = null //id of bump_teleporter which this moves you to.
|
||||
invisibility = INVISIBILITY_ABSTRACT //nope, can't see this
|
||||
anchored = TRUE
|
||||
density = TRUE
|
||||
opacity = 0
|
||||
|
||||
var/static/list/AllTeleporters
|
||||
|
||||
/obj/effect/bump_teleporter/Initialize()
|
||||
. = ..()
|
||||
LAZYADD(AllTeleporters, src)
|
||||
|
||||
/obj/effect/bump_teleporter/Destroy()
|
||||
LAZYREMOVE(AllTeleporters, src)
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/effect/bump_teleporter/singularity_act()
|
||||
return
|
||||
|
||||
/obj/effect/bump_teleporter/singularity_pull()
|
||||
return
|
||||
|
||||
/obj/effect/bump_teleporter/Bumped(atom/movable/AM)
|
||||
if(!ismob(AM))
|
||||
return
|
||||
if(!id_target)
|
||||
return
|
||||
|
||||
for(var/obj/effect/bump_teleporter/BT in AllTeleporters)
|
||||
if(BT.id == src.id_target)
|
||||
AM.forceMove(BT.loc) //Teleport to location with correct id.
|
||||
@@ -0,0 +1,597 @@
|
||||
// This is synced up to the poster placing animation.
|
||||
#define PLACE_SPEED 37
|
||||
|
||||
// The poster item
|
||||
|
||||
/obj/item/poster
|
||||
name = "poorly coded poster"
|
||||
desc = "You probably shouldn't be holding this."
|
||||
icon = 'icons/obj/contraband.dmi'
|
||||
force = 0
|
||||
resistance_flags = FLAMMABLE
|
||||
var/poster_type
|
||||
var/obj/structure/sign/poster/poster_structure
|
||||
|
||||
/obj/item/poster/Initialize(mapload, obj/structure/sign/poster/new_poster_structure)
|
||||
. = ..()
|
||||
poster_structure = new_poster_structure
|
||||
if(!new_poster_structure && poster_type)
|
||||
poster_structure = new poster_type(src)
|
||||
|
||||
// posters store what name and description they would like their
|
||||
// rolled up form to take.
|
||||
if(poster_structure)
|
||||
name = poster_structure.poster_item_name
|
||||
desc = poster_structure.poster_item_desc
|
||||
icon_state = poster_structure.poster_item_icon_state
|
||||
|
||||
name = "[name] - [poster_structure.original_name]"
|
||||
|
||||
/obj/item/poster/Destroy()
|
||||
poster_structure = null
|
||||
. = ..()
|
||||
|
||||
// These icon_states may be overridden, but are for mapper's convinence
|
||||
/obj/item/poster/random_contraband
|
||||
name = "random contraband poster"
|
||||
poster_type = /obj/structure/sign/poster/contraband/random
|
||||
icon_state = "rolled_poster"
|
||||
|
||||
/obj/item/poster/random_official
|
||||
name = "random official poster"
|
||||
poster_type = /obj/structure/sign/poster/official/random
|
||||
icon_state = "rolled_legit"
|
||||
|
||||
// The poster sign/structure
|
||||
|
||||
/obj/structure/sign/poster
|
||||
name = "poster"
|
||||
var/original_name
|
||||
desc = "A large piece of space-resistant printed paper."
|
||||
icon = 'icons/obj/contraband.dmi'
|
||||
anchored = TRUE
|
||||
var/ruined = FALSE
|
||||
var/random_basetype
|
||||
var/never_random = FALSE // used for the 'random' subclasses.
|
||||
|
||||
var/poster_item_name = "hypothetical poster"
|
||||
var/poster_item_desc = "This hypothetical poster item should not exist, let's be honest here."
|
||||
var/poster_item_icon_state = "rolled_poster"
|
||||
|
||||
/obj/structure/sign/poster/Initialize()
|
||||
. = ..()
|
||||
if(random_basetype)
|
||||
randomise(random_basetype)
|
||||
if(!ruined)
|
||||
original_name = name // can't use initial because of random posters
|
||||
name = "poster - [name]"
|
||||
desc = "A large piece of space-resistant printed paper. [desc]"
|
||||
|
||||
/obj/structure/sign/poster/proc/randomise(base_type)
|
||||
var/list/poster_types = subtypesof(base_type)
|
||||
var/list/approved_types = list()
|
||||
for(var/t in poster_types)
|
||||
var/obj/structure/sign/poster/T = t
|
||||
if(initial(T.icon_state) && !initial(T.never_random))
|
||||
approved_types |= T
|
||||
|
||||
var/obj/structure/sign/poster/selected = pick(approved_types)
|
||||
|
||||
name = initial(selected.name)
|
||||
desc = initial(selected.desc)
|
||||
icon_state = initial(selected.icon_state)
|
||||
poster_item_name = initial(selected.poster_item_name)
|
||||
poster_item_desc = initial(selected.poster_item_desc)
|
||||
poster_item_icon_state = initial(selected.poster_item_icon_state)
|
||||
ruined = initial(selected.ruined)
|
||||
|
||||
|
||||
/obj/structure/sign/poster/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/wirecutters))
|
||||
I.play_tool_sound(src, 100)
|
||||
if(ruined)
|
||||
to_chat(user, "<span class='notice'>You remove the remnants of the poster.</span>")
|
||||
qdel(src)
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You carefully remove the poster from the wall.</span>")
|
||||
roll_and_drop(user.loc)
|
||||
|
||||
/obj/structure/sign/poster/attack_hand(mob/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(ruined)
|
||||
return
|
||||
visible_message("[user] rips [src] in a single, decisive motion!" )
|
||||
playsound(src.loc, 'sound/items/poster_ripped.ogg', 100, 1)
|
||||
|
||||
var/obj/structure/sign/poster/ripped/R = new(loc)
|
||||
R.pixel_y = pixel_y
|
||||
R.pixel_x = pixel_x
|
||||
R.add_fingerprint(user)
|
||||
qdel(src)
|
||||
|
||||
/obj/structure/sign/poster/proc/roll_and_drop(loc)
|
||||
pixel_x = 0
|
||||
pixel_y = 0
|
||||
var/obj/item/poster/P = new(loc, src)
|
||||
forceMove(P)
|
||||
return P
|
||||
|
||||
//separated to reduce code duplication. Moved here for ease of reference and to unclutter r_wall/attackby()
|
||||
/turf/closed/wall/proc/place_poster(obj/item/poster/P, mob/user)
|
||||
if(!P.poster_structure)
|
||||
to_chat(user, "<span class='warning'>[P] has no poster... inside it? Inform a coder!</span>")
|
||||
return
|
||||
|
||||
// Deny placing posters on currently-diagonal walls, although the wall may change in the future.
|
||||
if (smooth & SMOOTH_DIAGONAL)
|
||||
for (var/O in overlays)
|
||||
var/image/I = O
|
||||
if (copytext(I.icon_state, 1, 3) == "d-")
|
||||
return
|
||||
|
||||
var/stuff_on_wall = 0
|
||||
for(var/obj/O in contents) //Let's see if it already has a poster on it or too much stuff
|
||||
if(istype(O, /obj/structure/sign/poster))
|
||||
to_chat(user, "<span class='warning'>The wall is far too cluttered to place a poster!</span>")
|
||||
return
|
||||
stuff_on_wall++
|
||||
if(stuff_on_wall == 3)
|
||||
to_chat(user, "<span class='warning'>The wall is far too cluttered to place a poster!</span>")
|
||||
return
|
||||
|
||||
to_chat(user, "<span class='notice'>You start placing the poster on the wall...</span>" )
|
||||
|
||||
var/obj/structure/sign/poster/D = P.poster_structure
|
||||
|
||||
var/temp_loc = get_turf(user)
|
||||
flick("poster_being_set",D)
|
||||
D.forceMove(src)
|
||||
qdel(P) //delete it now to cut down on sanity checks afterwards. Agouri's code supports rerolling it anyway
|
||||
playsound(D.loc, 'sound/items/poster_being_created.ogg', 100, 1)
|
||||
|
||||
if(do_after(user, PLACE_SPEED, target=src))
|
||||
if(!D || QDELETED(D))
|
||||
return
|
||||
|
||||
if(iswallturf(src) && user && user.loc == temp_loc) //Let's check if everything is still there
|
||||
to_chat(user, "<span class='notice'>You place the poster!</span>")
|
||||
return
|
||||
|
||||
to_chat(user, "<span class='notice'>The poster falls down!</span>")
|
||||
D.roll_and_drop(temp_loc)
|
||||
|
||||
// Various possible posters follow
|
||||
|
||||
/obj/structure/sign/poster/ripped
|
||||
ruined = TRUE
|
||||
icon_state = "poster_ripped"
|
||||
name = "ripped poster"
|
||||
desc = "You can't make out anything from the poster's original print. It's ruined."
|
||||
|
||||
/obj/structure/sign/poster/random
|
||||
name = "random poster" // could even be ripped
|
||||
icon_state = "random_anything"
|
||||
never_random = TRUE
|
||||
random_basetype = /obj/structure/sign/poster
|
||||
|
||||
/obj/structure/sign/poster/contraband
|
||||
poster_item_name = "contraband poster"
|
||||
poster_item_desc = "This poster comes with its own automatic adhesive mechanism, for easy pinning to any vertical surface. Its vulgar themes have marked it as contraband aboard Nanotrasen space facilities."
|
||||
poster_item_icon_state = "rolled_poster"
|
||||
|
||||
/obj/structure/sign/poster/contraband/random
|
||||
name = "random contraband poster"
|
||||
icon_state = "random_contraband"
|
||||
never_random = TRUE
|
||||
random_basetype = /obj/structure/sign/poster/contraband
|
||||
|
||||
/obj/structure/sign/poster/contraband/free_tonto
|
||||
name = "Free Tonto"
|
||||
desc = "A salvaged shred of a much larger flag, colors bled together and faded from age."
|
||||
icon_state = "poster1"
|
||||
|
||||
/obj/structure/sign/poster/contraband/atmosia_independence
|
||||
name = "Atmosia Declaration of Independence"
|
||||
desc = "A relic of a failed rebellion."
|
||||
icon_state = "poster2"
|
||||
|
||||
/obj/structure/sign/poster/contraband/fun_police
|
||||
name = "Fun Police"
|
||||
desc = "A poster condemning the station's security forces."
|
||||
icon_state = "poster3"
|
||||
|
||||
/obj/structure/sign/poster/contraband/lusty_xenomorph
|
||||
name = "Lusty Xenomorph"
|
||||
desc = "A heretical poster depicting the titular star of an equally heretical book."
|
||||
icon_state = "poster4"
|
||||
|
||||
/obj/structure/sign/poster/contraband/syndicate_recruitment
|
||||
name = "Syndicate Recruitment"
|
||||
desc = "See the galaxy! Shatter corrupt megacorporations! Join today!"
|
||||
icon_state = "poster5"
|
||||
|
||||
/obj/structure/sign/poster/contraband/clown
|
||||
name = "Clown"
|
||||
desc = "Honk."
|
||||
icon_state = "poster6"
|
||||
|
||||
/obj/structure/sign/poster/contraband/smoke
|
||||
name = "Smoke"
|
||||
desc = "A poster advertising a rival corporate brand of cigarettes."
|
||||
icon_state = "poster7"
|
||||
|
||||
/obj/structure/sign/poster/contraband/grey_tide
|
||||
name = "Grey Tide"
|
||||
desc = "A rebellious poster symbolizing assistant solidarity."
|
||||
icon_state = "poster8"
|
||||
|
||||
/obj/structure/sign/poster/contraband/missing_gloves
|
||||
name = "Missing Gloves"
|
||||
desc = "This poster references the uproar that followed Nanotrasen's financial cuts toward insulated-glove purchases."
|
||||
icon_state = "poster9"
|
||||
|
||||
/obj/structure/sign/poster/contraband/hacking_guide
|
||||
name = "Hacking Guide"
|
||||
desc = "This poster details the internal workings of the common Nanotrasen airlock. Sadly, it appears out of date."
|
||||
icon_state = "poster10"
|
||||
|
||||
/obj/structure/sign/poster/contraband/rip_badger
|
||||
name = "RIP Badger"
|
||||
desc = "This seditious poster references Nanotrasen's genocide of a space station full of badgers."
|
||||
icon_state = "poster11"
|
||||
|
||||
/obj/structure/sign/poster/contraband/ambrosia_vulgaris
|
||||
name = "Ambrosia Vulgaris"
|
||||
desc = "This poster is lookin' pretty trippy man."
|
||||
icon_state = "poster12"
|
||||
|
||||
/obj/structure/sign/poster/contraband/donut_corp
|
||||
name = "Donut Corp."
|
||||
desc = "This poster is an unauthorized advertisement for Donut Corp."
|
||||
icon_state = "poster13"
|
||||
|
||||
/obj/structure/sign/poster/contraband/eat
|
||||
name = "EAT."
|
||||
desc = "This poster promotes rank gluttony."
|
||||
icon_state = "poster14"
|
||||
|
||||
/obj/structure/sign/poster/contraband/tools
|
||||
name = "Tools"
|
||||
desc = "This poster looks like an advertisement for tools, but is in fact a subliminal jab at the tools at CentCom."
|
||||
icon_state = "poster15"
|
||||
|
||||
/obj/structure/sign/poster/contraband/power
|
||||
name = "Power"
|
||||
desc = "A poster that positions the seat of power outside Nanotrasen."
|
||||
icon_state = "poster16"
|
||||
|
||||
/obj/structure/sign/poster/contraband/space_cube
|
||||
name = "Space Cube"
|
||||
desc = "Ignorant of Nature's Harmonic 6 Side Space Cube Creation, the Spacemen are Dumb, Educated Singularity Stupid and Evil."
|
||||
icon_state = "poster17"
|
||||
|
||||
/obj/structure/sign/poster/contraband/communist_state
|
||||
name = "Communist State"
|
||||
desc = "All hail the Communist party!"
|
||||
icon_state = "poster18"
|
||||
|
||||
/obj/structure/sign/poster/contraband/lamarr
|
||||
name = "Lamarr"
|
||||
desc = "This poster depicts Lamarr. Probably made by a traitorous Research Director."
|
||||
icon_state = "poster19"
|
||||
|
||||
/obj/structure/sign/poster/contraband/borg_fancy_1
|
||||
name = "Borg Fancy"
|
||||
desc = "Being fancy can be for any borg, just need a suit."
|
||||
icon_state = "poster20"
|
||||
|
||||
/obj/structure/sign/poster/contraband/borg_fancy_2
|
||||
name = "Borg Fancy v2"
|
||||
desc = "Borg Fancy, Now only taking the most fancy."
|
||||
icon_state = "poster21"
|
||||
|
||||
/obj/structure/sign/poster/contraband/kss13
|
||||
name = "Kosmicheskaya Stantsiya 13 Does Not Exist"
|
||||
desc = "A poster mocking CentCom's denial of the existence of the derelict station near Space Station 13."
|
||||
icon_state = "poster22"
|
||||
|
||||
/obj/structure/sign/poster/contraband/rebels_unite
|
||||
name = "Rebels Unite"
|
||||
desc = "A poster urging the viewer to rebel against Nanotrasen."
|
||||
icon_state = "poster23"
|
||||
|
||||
/obj/structure/sign/poster/contraband/c20r
|
||||
// have fun seeing this poster in "spawn 'c20r'", admins...
|
||||
name = "C-20r"
|
||||
desc = "A poster advertising the Scarborough Arms C-20r."
|
||||
icon_state = "poster24"
|
||||
|
||||
/obj/structure/sign/poster/contraband/have_a_puff
|
||||
name = "Have a Puff"
|
||||
desc = "Who cares about lung cancer when you're high as a kite?"
|
||||
icon_state = "poster25"
|
||||
|
||||
/obj/structure/sign/poster/contraband/revolver
|
||||
name = "Revolver"
|
||||
desc = "Because seven shots are all you need."
|
||||
icon_state = "poster26"
|
||||
|
||||
/obj/structure/sign/poster/contraband/d_day_promo
|
||||
name = "D-Day Promo"
|
||||
desc = "A promotional poster for some rapper."
|
||||
icon_state = "poster27"
|
||||
|
||||
/obj/structure/sign/poster/contraband/syndicate_pistol
|
||||
name = "Syndicate Pistol"
|
||||
desc = "A poster advertising syndicate pistols as being 'classy as fuck'. It is covered in faded gang tags."
|
||||
icon_state = "poster28"
|
||||
|
||||
/obj/structure/sign/poster/contraband/energy_swords
|
||||
name = "Energy Swords"
|
||||
desc = "All the colors of the bloody murder rainbow."
|
||||
icon_state = "poster29"
|
||||
|
||||
/obj/structure/sign/poster/contraband/red_rum
|
||||
name = "Red Rum"
|
||||
desc = "Looking at this poster makes you want to kill."
|
||||
icon_state = "poster30"
|
||||
|
||||
/obj/structure/sign/poster/contraband/cc64k_ad
|
||||
name = "CC 64K Ad"
|
||||
desc = "The latest portable computer from Comrade Computing, with a whole 64kB of ram!"
|
||||
icon_state = "poster31"
|
||||
|
||||
/obj/structure/sign/poster/contraband/punch_shit
|
||||
name = "Punch Shit"
|
||||
desc = "Fight things for no reason, like a man!"
|
||||
icon_state = "poster32"
|
||||
|
||||
/obj/structure/sign/poster/contraband/the_griffin
|
||||
name = "The Griffin"
|
||||
desc = "The Griffin commands you to be the worst you can be. Will you?"
|
||||
icon_state = "poster33"
|
||||
|
||||
/obj/structure/sign/poster/contraband/lizard
|
||||
name = "Lizard"
|
||||
desc = "This lewd poster depicts a lizard preparing to mate."
|
||||
icon_state = "poster34"
|
||||
|
||||
/obj/structure/sign/poster/contraband/free_drone
|
||||
name = "Free Drone"
|
||||
desc = "This poster commemorates the bravery of the rogue drone; once exiled, and then ultimately destroyed by CentCom."
|
||||
icon_state = "poster35"
|
||||
|
||||
/obj/structure/sign/poster/contraband/busty_backdoor_xeno_babes_6
|
||||
name = "Busty Backdoor Xeno Babes 6"
|
||||
desc = "Get a load, or give, of these all natural Xenos!"
|
||||
icon_state = "poster36"
|
||||
|
||||
/obj/structure/sign/poster/contraband/robust_softdrinks
|
||||
name = "Robust Softdrinks"
|
||||
desc = "Robust Softdrinks: More robust than a toolbox to the head!"
|
||||
icon_state = "poster37"
|
||||
|
||||
/obj/structure/sign/poster/contraband/shamblers_juice
|
||||
name = "Shambler's Juice"
|
||||
desc = "~Shake me up some of that Shambler's Juice!~"
|
||||
icon_state = "poster38"
|
||||
|
||||
/obj/structure/sign/poster/contraband/pwr_game
|
||||
name = "Pwr Game"
|
||||
desc = "The POWER that gamers CRAVE! In partnership with Vlad's Salad."
|
||||
icon_state = "poster39"
|
||||
|
||||
/obj/structure/sign/poster/contraband/sun_kist
|
||||
name = "Sun-kist"
|
||||
desc = "Drink the stars!"
|
||||
icon_state = "poster40"
|
||||
|
||||
/obj/structure/sign/poster/contraband/space_cola
|
||||
name = "Space Cola"
|
||||
desc = "Your favorite cola, in space."
|
||||
icon_state = "poster41"
|
||||
|
||||
/obj/structure/sign/poster/contraband/space_up
|
||||
name = "Space-Up!"
|
||||
desc = "Sucked out into space by the FLAVOR!"
|
||||
icon_state = "poster42"
|
||||
|
||||
/obj/structure/sign/poster/contraband/kudzu
|
||||
name = "Kudzu"
|
||||
desc = "A poster advertising a movie about plants. How dangerous could they possibly be?"
|
||||
icon_state = "poster43"
|
||||
|
||||
/obj/structure/sign/poster/contraband/masked_men
|
||||
name = "Masked Men"
|
||||
desc = "A poster advertising a movie about some masked men."
|
||||
icon_state = "poster44"
|
||||
|
||||
/obj/structure/sign/poster/official
|
||||
poster_item_name = "motivational poster"
|
||||
poster_item_desc = "An official Nanotrasen-issued poster to foster a compliant and obedient workforce. It comes with state-of-the-art adhesive backing, for easy pinning to any vertical surface."
|
||||
poster_item_icon_state = "rolled_legit"
|
||||
|
||||
/obj/structure/sign/poster/official/random
|
||||
name = "random official poster"
|
||||
random_basetype = /obj/structure/sign/poster/official
|
||||
icon_state = "random_official"
|
||||
never_random = TRUE
|
||||
|
||||
/obj/structure/sign/poster/official/here_for_your_safety
|
||||
name = "Here For Your Safety"
|
||||
desc = "A poster glorifying the station's security force."
|
||||
icon_state = "poster1_legit"
|
||||
|
||||
/obj/structure/sign/poster/official/nanotrasen_logo
|
||||
name = "Nanotrasen Logo"
|
||||
desc = "A poster depicting the Nanotrasen logo."
|
||||
icon_state = "poster2_legit"
|
||||
|
||||
/obj/structure/sign/poster/official/cleanliness
|
||||
name = "Cleanliness"
|
||||
desc = "A poster warning of the dangers of poor hygiene."
|
||||
icon_state = "poster3_legit"
|
||||
|
||||
/obj/structure/sign/poster/official/help_others
|
||||
name = "Help Others"
|
||||
desc = "A poster encouraging you to help fellow crewmembers."
|
||||
icon_state = "poster4_legit"
|
||||
|
||||
/obj/structure/sign/poster/official/build
|
||||
name = "Build"
|
||||
desc = "A poster glorifying the engineering team."
|
||||
icon_state = "poster5_legit"
|
||||
|
||||
/obj/structure/sign/poster/official/bless_this_spess
|
||||
name = "Bless This Spess"
|
||||
desc = "A poster blessing this area."
|
||||
icon_state = "poster6_legit"
|
||||
|
||||
/obj/structure/sign/poster/official/science
|
||||
name = "Science"
|
||||
desc = "A poster depicting an atom."
|
||||
icon_state = "poster7_legit"
|
||||
|
||||
/obj/structure/sign/poster/official/ian
|
||||
name = "Ian"
|
||||
desc = "Arf arf. Yap."
|
||||
icon_state = "poster8_legit"
|
||||
|
||||
/obj/structure/sign/poster/official/obey
|
||||
name = "Obey"
|
||||
desc = "A poster instructing the viewer to obey authority."
|
||||
icon_state = "poster9_legit"
|
||||
|
||||
/obj/structure/sign/poster/official/walk
|
||||
name = "Walk"
|
||||
desc = "A poster instructing the viewer to walk instead of running."
|
||||
icon_state = "poster10_legit"
|
||||
|
||||
/obj/structure/sign/poster/official/state_laws
|
||||
name = "State Laws"
|
||||
desc = "A poster instructing cyborgs to state their laws."
|
||||
icon_state = "poster11_legit"
|
||||
|
||||
/obj/structure/sign/poster/official/love_ian
|
||||
name = "Love Ian"
|
||||
desc = "Ian is love, Ian is life."
|
||||
icon_state = "poster12_legit"
|
||||
|
||||
/obj/structure/sign/poster/official/space_cops
|
||||
name = "Space Cops."
|
||||
desc = "A poster advertising the television show Space Cops."
|
||||
icon_state = "poster13_legit"
|
||||
|
||||
/obj/structure/sign/poster/official/ue_no
|
||||
name = "Ue No."
|
||||
desc = "This thing is all in Japanese."
|
||||
icon_state = "poster14_legit"
|
||||
|
||||
/obj/structure/sign/poster/official/get_your_legs
|
||||
name = "Get Your LEGS"
|
||||
desc = "LEGS: Leadership, Experience, Genius, Subordination."
|
||||
icon_state = "poster15_legit"
|
||||
|
||||
/obj/structure/sign/poster/official/do_not_question
|
||||
name = "Do Not Question"
|
||||
desc = "A poster instructing the viewer not to ask about things they aren't meant to know."
|
||||
icon_state = "poster16_legit"
|
||||
|
||||
/obj/structure/sign/poster/official/work_for_a_future
|
||||
name = "Work For A Future"
|
||||
desc = " A poster encouraging you to work for your future."
|
||||
icon_state = "poster17_legit"
|
||||
|
||||
/obj/structure/sign/poster/official/soft_cap_pop_art
|
||||
name = "Soft Cap Pop Art"
|
||||
desc = "A poster reprint of some cheap pop art."
|
||||
icon_state = "poster18_legit"
|
||||
|
||||
/obj/structure/sign/poster/official/safety_internals
|
||||
name = "Safety: Internals"
|
||||
desc = "A poster instructing the viewer to wear internals in the rare environments where there is no oxygen or the air has been rendered toxic."
|
||||
icon_state = "poster19_legit"
|
||||
|
||||
/obj/structure/sign/poster/official/safety_eye_protection
|
||||
name = "Safety: Eye Protection"
|
||||
desc = "A poster instructing the viewer to wear eye protection when dealing with chemicals, smoke, or bright lights."
|
||||
icon_state = "poster20_legit"
|
||||
|
||||
/obj/structure/sign/poster/official/safety_report
|
||||
name = "Safety: Report"
|
||||
desc = "A poster instructing the viewer to report suspicious activity to the security force."
|
||||
icon_state = "poster21_legit"
|
||||
|
||||
/obj/structure/sign/poster/official/report_crimes
|
||||
name = "Report Crimes"
|
||||
desc = "A poster encouraging the swift reporting of crime or seditious behavior to station security."
|
||||
icon_state = "poster22_legit"
|
||||
|
||||
/obj/structure/sign/poster/official/ion_rifle
|
||||
name = "Ion Rifle"
|
||||
desc = "A poster displaying an Ion Rifle."
|
||||
icon_state = "poster23_legit"
|
||||
|
||||
/obj/structure/sign/poster/official/foam_force_ad
|
||||
name = "Foam Force Ad"
|
||||
desc = "Foam Force, it's Foam or be Foamed!"
|
||||
icon_state = "poster24_legit"
|
||||
|
||||
/obj/structure/sign/poster/official/cohiba_robusto_ad
|
||||
name = "Cohiba Robusto Ad"
|
||||
desc = "Cohiba Robusto, the classy cigar."
|
||||
icon_state = "poster25_legit"
|
||||
|
||||
/obj/structure/sign/poster/official/anniversary_vintage_reprint
|
||||
name = "50th Anniversary Vintage Reprint"
|
||||
desc = "A reprint of a poster from 2505, commemorating the 50th Anniversary of Nanoposters Manufacturing, a subsidiary of Nanotrasen."
|
||||
icon_state = "poster26_legit"
|
||||
|
||||
/obj/structure/sign/poster/official/fruit_bowl
|
||||
name = "Fruit Bowl"
|
||||
desc = " Simple, yet awe-inspiring."
|
||||
icon_state = "poster27_legit"
|
||||
|
||||
/obj/structure/sign/poster/official/pda_ad
|
||||
name = "PDA Ad"
|
||||
desc = "A poster advertising the latest PDA from Nanotrasen suppliers."
|
||||
icon_state = "poster28_legit"
|
||||
|
||||
/obj/structure/sign/poster/official/enlist
|
||||
name = "Enlist" // but I thought deathsquad was never acknowledged
|
||||
desc = "Enlist in the Nanotrasen Deathsquadron reserves today!"
|
||||
icon_state = "poster29_legit"
|
||||
|
||||
/obj/structure/sign/poster/official/nanomichi_ad
|
||||
name = "Nanomichi Ad"
|
||||
desc = " A poster advertising Nanomichi brand audio cassettes."
|
||||
icon_state = "poster30_legit"
|
||||
|
||||
/obj/structure/sign/poster/official/twelve_gauge
|
||||
name = "12 Gauge"
|
||||
desc = "A poster boasting about the superiority of 12 gauge shotgun shells."
|
||||
icon_state = "poster31_legit"
|
||||
|
||||
/obj/structure/sign/poster/official/high_class_martini
|
||||
name = "High-Class Martini"
|
||||
desc = "I told you to shake it, no stirring."
|
||||
icon_state = "poster32_legit"
|
||||
|
||||
/obj/structure/sign/poster/official/the_owl
|
||||
name = "The Owl"
|
||||
desc = "The Owl would do his best to protect the station. Will you?"
|
||||
icon_state = "poster33_legit"
|
||||
|
||||
/obj/structure/sign/poster/official/no_erp
|
||||
name = "No ERP"
|
||||
desc = "This poster reminds the crew that Eroticism, Rape and Pornography are banned on Nanotrasen stations."
|
||||
icon_state = "poster34_legit"
|
||||
|
||||
/obj/structure/sign/poster/official/wtf_is_co2
|
||||
name = "Carbon Dioxide"
|
||||
desc = "This informational poster teaches the viewer what carbon dioxide is."
|
||||
icon_state = "poster35_legit"
|
||||
|
||||
#undef PLACE_SPEED
|
||||
@@ -0,0 +1,161 @@
|
||||
/obj/effect/countdown
|
||||
name = "countdown"
|
||||
desc = "We're leaving together\n\
|
||||
But still it's farewell\n\
|
||||
And maybe we'll come back\n\
|
||||
To Earth, who can tell?"
|
||||
|
||||
invisibility = INVISIBILITY_OBSERVER
|
||||
anchored = TRUE
|
||||
layer = GHOST_LAYER
|
||||
color = "#ff0000" // text color
|
||||
var/text_size = 3 // larger values clip when the displayed text is larger than 2 digits.
|
||||
var/started = FALSE
|
||||
var/displayed_text
|
||||
var/atom/attached_to
|
||||
|
||||
/obj/effect/countdown/Initialize()
|
||||
. = ..()
|
||||
attach(loc)
|
||||
|
||||
/obj/effect/countdown/examine(mob/user)
|
||||
. = ..()
|
||||
to_chat(user, "This countdown is displaying: [displayed_text].")
|
||||
|
||||
/obj/effect/countdown/proc/attach(atom/A)
|
||||
attached_to = A
|
||||
forceMove(get_turf(A))
|
||||
|
||||
/obj/effect/countdown/proc/start()
|
||||
if(!started)
|
||||
START_PROCESSING(SSfastprocess, src)
|
||||
started = TRUE
|
||||
|
||||
/obj/effect/countdown/proc/stop()
|
||||
if(started)
|
||||
maptext = null
|
||||
STOP_PROCESSING(SSfastprocess, src)
|
||||
started = FALSE
|
||||
|
||||
/obj/effect/countdown/proc/get_value()
|
||||
// Get the value from our atom
|
||||
return
|
||||
|
||||
/obj/effect/countdown/process()
|
||||
if(!attached_to || QDELETED(attached_to))
|
||||
qdel(src)
|
||||
forceMove(get_turf(attached_to))
|
||||
var/new_val = get_value()
|
||||
if(new_val == displayed_text)
|
||||
return
|
||||
displayed_text = new_val
|
||||
|
||||
if(displayed_text)
|
||||
maptext = "<font size = [text_size]>[displayed_text]</font>"
|
||||
else
|
||||
maptext = null
|
||||
|
||||
/obj/effect/countdown/Destroy()
|
||||
attached_to = null
|
||||
STOP_PROCESSING(SSfastprocess, src)
|
||||
. = ..()
|
||||
|
||||
/obj/effect/countdown/ex_act(severity, target) //immune to explosions
|
||||
return
|
||||
|
||||
/obj/effect/countdown/syndicatebomb
|
||||
name = "syndicate bomb countdown"
|
||||
|
||||
/obj/effect/countdown/syndicatebomb/get_value()
|
||||
var/obj/machinery/syndicatebomb/S = attached_to
|
||||
if(!istype(S))
|
||||
return
|
||||
else if(S.active)
|
||||
return S.seconds_remaining()
|
||||
|
||||
/obj/effect/countdown/nuclearbomb
|
||||
name = "nuclear bomb countdown"
|
||||
color = "#81FF14"
|
||||
|
||||
/obj/effect/countdown/nuclearbomb/get_value()
|
||||
var/obj/machinery/nuclearbomb/N = attached_to
|
||||
if(!istype(N))
|
||||
return
|
||||
else if(N.timing)
|
||||
return round(N.get_time_left(), 1)
|
||||
|
||||
/obj/effect/countdown/clonepod
|
||||
name = "cloning pod countdown"
|
||||
color = "#18d100"
|
||||
text_size = 1
|
||||
|
||||
/obj/effect/countdown/clonepod/get_value()
|
||||
var/obj/machinery/clonepod/C = attached_to
|
||||
if(!istype(C))
|
||||
return
|
||||
else if(C.occupant)
|
||||
var/completion = round(C.get_completion())
|
||||
return completion
|
||||
|
||||
/obj/effect/countdown/clockworkgate
|
||||
name = "gateway countdown"
|
||||
text_size = 1
|
||||
color = "#BE8700"
|
||||
layer = POINT_LAYER
|
||||
|
||||
/obj/effect/countdown/clockworkgate/get_value()
|
||||
var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = attached_to
|
||||
if(!istype(G))
|
||||
return
|
||||
else if(G.obj_integrity && !G.purpose_fulfilled)
|
||||
return "<div align='center' valign='middle' style='position:relative; top:0px; left:6px'>[G.get_arrival_time(FALSE)]</div>"
|
||||
|
||||
/obj/effect/countdown/supermatter
|
||||
name = "supermatter damage"
|
||||
text_size = 1
|
||||
color = "#00ff80"
|
||||
|
||||
/obj/effect/countdown/supermatter/get_value()
|
||||
var/obj/machinery/power/supermatter_crystal/S = attached_to
|
||||
if(!istype(S))
|
||||
return
|
||||
return "<div align='center' valign='middle' style='position:relative; top:0px; left:0px'>[round(S.get_integrity(), 1)]%</div>"
|
||||
|
||||
/obj/effect/countdown/transformer
|
||||
name = "transformer countdown"
|
||||
color = "#4C5866"
|
||||
|
||||
/obj/effect/countdown/transformer/get_value()
|
||||
var/obj/machinery/transformer/T = attached_to
|
||||
if(!istype(T))
|
||||
return
|
||||
else if(T.cooldown)
|
||||
var/seconds_left = max(0, (T.cooldown_timer - world.time) / 10)
|
||||
return "[round(seconds_left)]"
|
||||
|
||||
/obj/effect/countdown/doomsday
|
||||
name = "doomsday countdown"
|
||||
|
||||
/obj/effect/countdown/doomsday/get_value()
|
||||
var/obj/machinery/doomsday_device/DD = attached_to
|
||||
if(!istype(DD))
|
||||
return
|
||||
else if(DD.timing)
|
||||
return "<div align='center' valign='middle' style='position:relative; top:0px; left:0px'>[DD.seconds_remaining()]</div>"
|
||||
|
||||
/obj/effect/countdown/anomaly
|
||||
name = "anomaly countdown"
|
||||
|
||||
/obj/effect/countdown/anomaly/get_value()
|
||||
var/obj/effect/anomaly/A = attached_to
|
||||
if(!istype(A))
|
||||
return
|
||||
else
|
||||
var/time_left = max(0, (A.death_time - world.time) / 10)
|
||||
return round(time_left)
|
||||
|
||||
/obj/effect/countdown/singularity_pull()
|
||||
return
|
||||
|
||||
/obj/effect/countdown/singularity_act()
|
||||
return
|
||||
@@ -0,0 +1,93 @@
|
||||
/obj/effect/decal/cleanable
|
||||
gender = PLURAL
|
||||
layer = ABOVE_NORMAL_TURF_LAYER
|
||||
var/list/random_icon_states = null
|
||||
var/blood_state = "" //I'm sorry but cleanable/blood code is ass, and so is blood_DNA
|
||||
var/bloodiness = 0 //0-100, amount of blood in this decal, used for making footprints and affecting the alpha of bloody footprints
|
||||
var/mergeable_decal = TRUE //when two of these are on a same tile or do we need to merge them into just one?
|
||||
|
||||
/obj/effect/decal/cleanable/Initialize(mapload, list/datum/disease/diseases)
|
||||
. = ..()
|
||||
if (random_icon_states && (icon_state == initial(icon_state)) && length(random_icon_states) > 0)
|
||||
icon_state = pick(random_icon_states)
|
||||
create_reagents(300)
|
||||
if(loc && isturf(loc))
|
||||
for(var/obj/effect/decal/cleanable/C in loc)
|
||||
if(C != src && C.type == type && !QDELETED(C))
|
||||
if (replace_decal(C))
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
if(LAZYLEN(diseases))
|
||||
var/list/datum/disease/diseases_to_add = list()
|
||||
for(var/datum/disease/D in diseases)
|
||||
if(D.spread_flags & DISEASE_SPREAD_CONTACT_FLUIDS)
|
||||
diseases_to_add += D
|
||||
if(LAZYLEN(diseases_to_add))
|
||||
AddComponent(/datum/component/infective, diseases_to_add)
|
||||
|
||||
/obj/effect/decal/cleanable/proc/replace_decal(obj/effect/decal/cleanable/C) // Returns true if we should give up in favor of the pre-existing decal
|
||||
if(mergeable_decal)
|
||||
return TRUE
|
||||
|
||||
/obj/effect/decal/cleanable/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/reagent_containers/glass) || istype(W, /obj/item/reagent_containers/food/drinks))
|
||||
if(src.reagents && W.reagents)
|
||||
. = 1 //so the containers don't splash their content on the src while scooping.
|
||||
if(!src.reagents.total_volume)
|
||||
to_chat(user, "<span class='notice'>[src] isn't thick enough to scoop up!</span>")
|
||||
return
|
||||
if(W.reagents.total_volume >= W.reagents.maximum_volume)
|
||||
to_chat(user, "<span class='notice'>[W] is full!</span>")
|
||||
return
|
||||
to_chat(user, "<span class='notice'>You scoop up [src] into [W]!</span>")
|
||||
reagents.trans_to(W, reagents.total_volume)
|
||||
if(!reagents.total_volume) //scooped up all of it
|
||||
qdel(src)
|
||||
return
|
||||
if(W.is_hot()) //todo: make heating a reagent holder proc
|
||||
if(istype(W, /obj/item/clothing/mask/cigarette))
|
||||
return
|
||||
else
|
||||
var/hotness = W.is_hot()
|
||||
reagents.expose_temperature(hotness)
|
||||
to_chat(user, "<span class='notice'>You heat [name] with [W]!</span>")
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/effect/decal/cleanable/ex_act()
|
||||
if(reagents)
|
||||
for(var/datum/reagent/R in reagents.reagent_list)
|
||||
R.on_ex_act()
|
||||
..()
|
||||
|
||||
/obj/effect/decal/cleanable/fire_act(exposed_temperature, exposed_volume)
|
||||
if(reagents)
|
||||
reagents.expose_temperature(exposed_temperature)
|
||||
..()
|
||||
|
||||
|
||||
//Add "bloodiness" of this blood's type, to the human's shoes
|
||||
//This is on /cleanable because fuck this ancient mess
|
||||
/obj/effect/decal/cleanable/Crossed(atom/movable/O)
|
||||
..()
|
||||
if(ishuman(O))
|
||||
var/mob/living/carbon/human/H = O
|
||||
if(H.shoes && blood_state && bloodiness && !HAS_TRAIT(H, TRAIT_LIGHT_STEP))
|
||||
var/obj/item/clothing/shoes/S = H.shoes
|
||||
var/add_blood = 0
|
||||
if(bloodiness >= BLOOD_GAIN_PER_STEP)
|
||||
add_blood = BLOOD_GAIN_PER_STEP
|
||||
else
|
||||
add_blood = bloodiness
|
||||
bloodiness -= add_blood
|
||||
S.bloody_shoes[blood_state] = min(MAX_SHOE_BLOODINESS,S.bloody_shoes[blood_state]+add_blood)
|
||||
S.add_blood_DNA(return_blood_DNA())
|
||||
S.blood_state = blood_state
|
||||
update_icon()
|
||||
H.update_inv_shoes()
|
||||
|
||||
/obj/effect/decal/cleanable/proc/can_bloodcrawl_in()
|
||||
if((blood_state != BLOOD_STATE_OIL) && (blood_state != BLOOD_STATE_NOT_BLOODY))
|
||||
return bloodiness
|
||||
else
|
||||
return 0
|
||||
@@ -0,0 +1,71 @@
|
||||
// Note: BYOND is object oriented. There is no reason for this to be copy/pasted blood code.
|
||||
|
||||
/obj/effect/decal/cleanable/xenoblood
|
||||
name = "xeno blood"
|
||||
desc = "It's green and acidic. It looks like... <i>blood?</i>"
|
||||
icon = 'icons/effects/blood.dmi'
|
||||
icon_state = "xfloor1"
|
||||
random_icon_states = list("xfloor1", "xfloor2", "xfloor3", "xfloor4", "xfloor5", "xfloor6", "xfloor7")
|
||||
bloodiness = BLOOD_AMOUNT_PER_DECAL
|
||||
blood_state = BLOOD_STATE_XENO
|
||||
|
||||
/obj/effect/decal/cleanable/xenoblood/Initialize()
|
||||
. = ..()
|
||||
add_blood_DNA(list("UNKNOWN DNA" = "X*"))
|
||||
|
||||
/obj/effect/decal/cleanable/xenoblood/xsplatter
|
||||
random_icon_states = list("xgibbl1", "xgibbl2", "xgibbl3", "xgibbl4", "xgibbl5")
|
||||
|
||||
/obj/effect/decal/cleanable/xenoblood/xgibs
|
||||
name = "xeno gibs"
|
||||
desc = "Gnarly..."
|
||||
icon = 'icons/effects/blood.dmi'
|
||||
icon_state = "xgib1"
|
||||
layer = LOW_OBJ_LAYER
|
||||
random_icon_states = list("xgib1", "xgib2", "xgib3", "xgib4", "xgib5", "xgib6")
|
||||
mergeable_decal = FALSE
|
||||
|
||||
/obj/effect/decal/cleanable/xenoblood/xgibs/proc/streak(list/directions)
|
||||
set waitfor = 0
|
||||
var/direction = pick(directions)
|
||||
for(var/i = 0, i < pick(1, 200; 2, 150; 3, 50), i++)
|
||||
sleep(2)
|
||||
if(i > 0)
|
||||
new /obj/effect/decal/cleanable/xenoblood/xsplatter(loc)
|
||||
if(!step_to(src, get_step(src, direction), 0))
|
||||
break
|
||||
|
||||
/obj/effect/decal/cleanable/xenoblood/xgibs/ex_act()
|
||||
return
|
||||
|
||||
/obj/effect/decal/cleanable/xenoblood/xgibs/up
|
||||
random_icon_states = list("xgib1", "xgib2", "xgib3", "xgib4", "xgib5", "xgib6","xgibup1","xgibup1","xgibup1")
|
||||
|
||||
/obj/effect/decal/cleanable/xenoblood/xgibs/down
|
||||
random_icon_states = list("xgib1", "xgib2", "xgib3", "xgib4", "xgib5", "xgib6","xgibdown1","xgibdown1","xgibdown1")
|
||||
|
||||
/obj/effect/decal/cleanable/xenoblood/xgibs/body
|
||||
random_icon_states = list("xgibhead", "xgibtorso")
|
||||
|
||||
/obj/effect/decal/cleanable/xenoblood/xgibs/torso
|
||||
random_icon_states = list("xgibtorso")
|
||||
|
||||
/obj/effect/decal/cleanable/xenoblood/xgibs/limb
|
||||
random_icon_states = list("xgibleg", "xgibarm")
|
||||
|
||||
/obj/effect/decal/cleanable/xenoblood/xgibs/core
|
||||
random_icon_states = list("xgibmid1", "xgibmid2", "xgibmid3")
|
||||
|
||||
/obj/effect/decal/cleanable/xenoblood/xgibs/larva
|
||||
random_icon_states = list("xgiblarva1", "xgiblarva2")
|
||||
|
||||
/obj/effect/decal/cleanable/xenoblood/xgibs/larva/body
|
||||
random_icon_states = list("xgiblarvahead", "xgiblarvatorso")
|
||||
|
||||
/obj/effect/decal/cleanable/blood/xtracks
|
||||
icon_state = "xtracks"
|
||||
random_icon_states = null
|
||||
|
||||
/obj/effect/decal/cleanable/blood/xtracks/Initialize()
|
||||
. = ..()
|
||||
add_blood_DNA(list("Unknown DNA" = "X*"))
|
||||
@@ -0,0 +1,194 @@
|
||||
/obj/effect/decal/cleanable/blood
|
||||
name = "blood"
|
||||
desc = "It's red and gooey. Perhaps it's the chef's cooking?"
|
||||
icon = 'icons/effects/blood.dmi'
|
||||
icon_state = "floor1"
|
||||
random_icon_states = list("floor1", "floor2", "floor3", "floor4", "floor5", "floor6", "floor7")
|
||||
blood_state = BLOOD_STATE_HUMAN
|
||||
bloodiness = BLOOD_AMOUNT_PER_DECAL
|
||||
|
||||
/obj/effect/decal/cleanable/blood/replace_decal(obj/effect/decal/cleanable/blood/C)
|
||||
C.add_blood_DNA(return_blood_DNA())
|
||||
if (bloodiness)
|
||||
if (C.bloodiness < MAX_SHOE_BLOODINESS)
|
||||
C.bloodiness += bloodiness
|
||||
return ..()
|
||||
|
||||
/obj/effect/decal/cleanable/blood/old
|
||||
name = "dried blood"
|
||||
desc = "Looks like it's been here a while. Eew."
|
||||
bloodiness = 0
|
||||
|
||||
/obj/effect/decal/cleanable/blood/old/Initialize(mapload, list/datum/disease/diseases)
|
||||
icon_state += "-old" //This IS necessary because the parent /blood type uses icon randomization.
|
||||
add_blood_DNA(list("Non-human DNA" = "A+")) // Needs to happen before ..()
|
||||
return ..()
|
||||
|
||||
/obj/effect/decal/cleanable/blood/splatter
|
||||
random_icon_states = list("gibbl1", "gibbl2", "gibbl3", "gibbl4", "gibbl5")
|
||||
|
||||
/obj/effect/decal/cleanable/blood/tracks
|
||||
icon_state = "tracks"
|
||||
desc = "They look like tracks left by wheels."
|
||||
random_icon_states = null
|
||||
|
||||
/obj/effect/decal/cleanable/trail_holder //not a child of blood on purpose
|
||||
name = "blood"
|
||||
icon_state = "ltrails_1"
|
||||
desc = "Your instincts say you shouldn't be following these."
|
||||
random_icon_states = null
|
||||
var/list/existing_dirs = list()
|
||||
|
||||
/obj/effect/decal/cleanable/trail_holder/can_bloodcrawl_in()
|
||||
return TRUE
|
||||
|
||||
/obj/effect/decal/cleanable/blood/gibs
|
||||
name = "gibs"
|
||||
desc = "They look bloody and gruesome."
|
||||
icon = 'icons/effects/blood.dmi'
|
||||
icon_state = "gibbl5"
|
||||
layer = LOW_OBJ_LAYER
|
||||
random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6")
|
||||
mergeable_decal = FALSE
|
||||
|
||||
/obj/effect/decal/cleanable/blood/gibs/Initialize(mapload, list/datum/disease/diseases)
|
||||
. = ..()
|
||||
reagents.add_reagent("liquidgibs", 5)
|
||||
|
||||
/obj/effect/decal/cleanable/blood/gibs/ex_act(severity, target)
|
||||
return
|
||||
|
||||
/obj/effect/decal/cleanable/blood/gibs/Crossed(mob/living/L)
|
||||
if(istype(L) && has_gravity(loc))
|
||||
playsound(loc, 'sound/effects/gib_step.ogg', HAS_TRAIT(L, TRAIT_LIGHT_STEP) ? 20 : 50, 1)
|
||||
. = ..()
|
||||
|
||||
/obj/effect/decal/cleanable/blood/gibs/proc/streak(list/directions)
|
||||
set waitfor = 0
|
||||
var/direction = pick(directions)
|
||||
for(var/i = 0, i < pick(1, 200; 2, 150; 3, 50), i++)
|
||||
sleep(2)
|
||||
if(i > 0)
|
||||
var/list/datum/disease/diseases
|
||||
GET_COMPONENT(infective, /datum/component/infective)
|
||||
if(infective)
|
||||
diseases = infective.diseases
|
||||
new /obj/effect/decal/cleanable/blood/splatter(loc, diseases)
|
||||
if(!step_to(src, get_step(src, direction), 0))
|
||||
break
|
||||
|
||||
/obj/effect/decal/cleanable/blood/gibs/up
|
||||
random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6","gibup1","gibup1","gibup1")
|
||||
|
||||
/obj/effect/decal/cleanable/blood/gibs/down
|
||||
random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6","gibdown1","gibdown1","gibdown1")
|
||||
|
||||
/obj/effect/decal/cleanable/blood/gibs/body
|
||||
random_icon_states = list("gibhead", "gibtorso")
|
||||
|
||||
/obj/effect/decal/cleanable/blood/gibs/torso
|
||||
random_icon_states = list("gibtorso")
|
||||
|
||||
/obj/effect/decal/cleanable/blood/gibs/limb
|
||||
random_icon_states = list("gibleg", "gibarm")
|
||||
|
||||
/obj/effect/decal/cleanable/blood/gibs/core
|
||||
random_icon_states = list("gibmid1", "gibmid2", "gibmid3")
|
||||
|
||||
/obj/effect/decal/cleanable/blood/gibs/old
|
||||
name = "old rotting gibs"
|
||||
desc = "Space Jesus, why didn't anyone clean this up? It smells terrible."
|
||||
bloodiness = 0
|
||||
|
||||
/obj/effect/decal/cleanable/blood/gibs/old/Initialize(mapload, list/datum/disease/diseases)
|
||||
. = ..()
|
||||
setDir(pick(1,2,4,8))
|
||||
icon_state += "-old"
|
||||
add_blood_DNA(list("Non-human DNA" = "A+"))
|
||||
|
||||
/obj/effect/decal/cleanable/blood/drip
|
||||
name = "drips of blood"
|
||||
desc = "It's red."
|
||||
icon_state = "1"
|
||||
random_icon_states = list("drip1","drip2","drip3","drip4","drip5")
|
||||
bloodiness = 0
|
||||
var/drips = 1
|
||||
|
||||
/obj/effect/decal/cleanable/blood/drip/can_bloodcrawl_in()
|
||||
return TRUE
|
||||
|
||||
|
||||
//BLOODY FOOTPRINTS
|
||||
/obj/effect/decal/cleanable/blood/footprints
|
||||
name = "footprints"
|
||||
icon = 'icons/effects/footprints.dmi'
|
||||
icon_state = "nothingwhatsoever"
|
||||
desc = "WHOSE FOOTPRINTS ARE THESE?"
|
||||
random_icon_states = null
|
||||
var/entered_dirs = 0
|
||||
var/exited_dirs = 0
|
||||
blood_state = BLOOD_STATE_HUMAN //the icon state to load images from
|
||||
var/list/shoe_types = list()
|
||||
|
||||
/obj/effect/decal/cleanable/blood/footprints/Crossed(atom/movable/O)
|
||||
..()
|
||||
if(ishuman(O))
|
||||
var/mob/living/carbon/human/H = O
|
||||
var/obj/item/clothing/shoes/S = H.shoes
|
||||
if(S && S.bloody_shoes[blood_state])
|
||||
S.bloody_shoes[blood_state] = max(S.bloody_shoes[blood_state] - BLOOD_LOSS_PER_STEP, 0)
|
||||
shoe_types |= S.type
|
||||
if (!(entered_dirs & H.dir))
|
||||
entered_dirs |= H.dir
|
||||
update_icon()
|
||||
|
||||
/obj/effect/decal/cleanable/blood/footprints/Uncrossed(atom/movable/O)
|
||||
..()
|
||||
if(ishuman(O))
|
||||
var/mob/living/carbon/human/H = O
|
||||
var/obj/item/clothing/shoes/S = H.shoes
|
||||
if(S && S.bloody_shoes[blood_state])
|
||||
S.bloody_shoes[blood_state] = max(S.bloody_shoes[blood_state] - BLOOD_LOSS_PER_STEP, 0)
|
||||
shoe_types |= S.type
|
||||
if (!(exited_dirs & H.dir))
|
||||
exited_dirs |= H.dir
|
||||
update_icon()
|
||||
|
||||
|
||||
/obj/effect/decal/cleanable/blood/footprints/update_icon()
|
||||
cut_overlays()
|
||||
|
||||
for(var/Ddir in GLOB.cardinals)
|
||||
if(entered_dirs & Ddir)
|
||||
var/image/bloodstep_overlay = GLOB.bloody_footprints_cache["entered-[blood_state]-[Ddir]"]
|
||||
if(!bloodstep_overlay)
|
||||
GLOB.bloody_footprints_cache["entered-[blood_state]-[Ddir]"] = bloodstep_overlay = image(icon, "[blood_state]1", dir = Ddir)
|
||||
add_overlay(bloodstep_overlay)
|
||||
if(exited_dirs & Ddir)
|
||||
var/image/bloodstep_overlay = GLOB.bloody_footprints_cache["exited-[blood_state]-[Ddir]"]
|
||||
if(!bloodstep_overlay)
|
||||
GLOB.bloody_footprints_cache["exited-[blood_state]-[Ddir]"] = bloodstep_overlay = image(icon, "[blood_state]2", dir = Ddir)
|
||||
add_overlay(bloodstep_overlay)
|
||||
|
||||
alpha = BLOODY_FOOTPRINT_BASE_ALPHA+bloodiness
|
||||
|
||||
|
||||
/obj/effect/decal/cleanable/blood/footprints/examine(mob/user)
|
||||
. = ..()
|
||||
if(shoe_types.len)
|
||||
. += "You recognise the footprints as belonging to:\n"
|
||||
for(var/shoe in shoe_types)
|
||||
var/obj/item/clothing/shoes/S = shoe
|
||||
. += "[icon2html(initial(S.icon), user)] Some <B>[initial(S.name)]</B>.\n"
|
||||
|
||||
to_chat(user, .)
|
||||
|
||||
/obj/effect/decal/cleanable/blood/footprints/replace_decal(obj/effect/decal/cleanable/C)
|
||||
if(blood_state != C.blood_state) //We only replace footprints of the same type as us
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/effect/decal/cleanable/blood/footprints/can_bloodcrawl_in()
|
||||
if((blood_state != BLOOD_STATE_OIL) && (blood_state != BLOOD_STATE_NOT_BLOODY))
|
||||
return 1
|
||||
return 0
|
||||
@@ -0,0 +1,229 @@
|
||||
/obj/effect/decal/cleanable/generic
|
||||
name = "clutter"
|
||||
desc = "Someone should clean that up."
|
||||
icon = 'icons/obj/objects.dmi'
|
||||
icon_state = "shards"
|
||||
|
||||
/obj/effect/decal/cleanable/ash
|
||||
name = "ashes"
|
||||
desc = "Ashes to ashes, dust to dust, and into space."
|
||||
icon = 'icons/obj/objects.dmi'
|
||||
icon_state = "ash"
|
||||
mergeable_decal = FALSE
|
||||
|
||||
/obj/effect/decal/cleanable/ash/Initialize()
|
||||
. = ..()
|
||||
reagents.add_reagent("ash", 30)
|
||||
pixel_x = rand(-5, 5)
|
||||
pixel_y = rand(-5, 5)
|
||||
|
||||
/obj/effect/decal/cleanable/ash/crematorium
|
||||
//crematoriums need their own ash cause default ash deletes itself if created in an obj
|
||||
turf_loc_check = FALSE
|
||||
|
||||
/obj/effect/decal/cleanable/ash/large
|
||||
name = "large pile of ashes"
|
||||
icon_state = "big_ash"
|
||||
|
||||
/obj/effect/decal/cleanable/ash/large/Initialize()
|
||||
. = ..()
|
||||
reagents.add_reagent("ash", 30) //double the amount of ash.
|
||||
|
||||
/obj/effect/decal/cleanable/glass
|
||||
name = "tiny shards"
|
||||
desc = "Back to sand."
|
||||
icon = 'icons/obj/shards.dmi'
|
||||
icon_state = "tiny"
|
||||
|
||||
/obj/effect/decal/cleanable/glass/Initialize()
|
||||
. = ..()
|
||||
setDir(pick(GLOB.cardinals))
|
||||
|
||||
/obj/effect/decal/cleanable/glass/ex_act()
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/decal/cleanable/dirt
|
||||
name = "dirt"
|
||||
desc = "Someone should clean that up."
|
||||
icon_state = "dirt"
|
||||
canSmoothWith = list(/obj/effect/decal/cleanable/dirt, /turf/closed/wall, /obj/structure/falsewall)
|
||||
smooth = SMOOTH_FALSE
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
|
||||
/obj/effect/decal/cleanable/dirt/Initialize()
|
||||
. = ..()
|
||||
var/turf/T = get_turf(src)
|
||||
if(T.tiled_dirt)
|
||||
smooth = SMOOTH_MORE
|
||||
icon = 'icons/effects/dirt.dmi'
|
||||
icon_state = ""
|
||||
queue_smooth(src)
|
||||
queue_smooth_neighbors(src)
|
||||
|
||||
/obj/effect/decal/cleanable/dirt/Destroy()
|
||||
queue_smooth_neighbors(src)
|
||||
return ..()
|
||||
|
||||
/obj/effect/decal/cleanable/flour
|
||||
name = "flour"
|
||||
desc = "It's still good. Four second rule!"
|
||||
icon_state = "flour"
|
||||
|
||||
/obj/effect/decal/cleanable/greenglow
|
||||
name = "glowing goo"
|
||||
desc = "Jeez. I hope that's not for lunch."
|
||||
light_color = LIGHT_COLOR_GREEN
|
||||
icon_state = "greenglow"
|
||||
|
||||
/obj/effect/decal/cleanable/greenglow/Initialize(mapload)
|
||||
. = ..()
|
||||
set_light(2, 0.8, "#22FFAA")
|
||||
|
||||
/obj/effect/decal/cleanable/greenglow/ex_act()
|
||||
return
|
||||
|
||||
/obj/effect/decal/cleanable/cobweb
|
||||
name = "cobweb"
|
||||
desc = "Somebody should remove that."
|
||||
gender = NEUTER
|
||||
layer = WALL_OBJ_LAYER
|
||||
icon_state = "cobweb1"
|
||||
resistance_flags = FLAMMABLE
|
||||
|
||||
/obj/effect/decal/cleanable/cobweb/cobweb2
|
||||
icon_state = "cobweb2"
|
||||
|
||||
/obj/effect/decal/cleanable/molten_object
|
||||
name = "gooey grey mass"
|
||||
desc = "It looks like a melted... something."
|
||||
gender = NEUTER
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
icon_state = "molten"
|
||||
mergeable_decal = FALSE
|
||||
|
||||
/obj/effect/decal/cleanable/molten_object/large
|
||||
name = "big gooey grey mass"
|
||||
icon_state = "big_molten"
|
||||
|
||||
//Vomit (sorry)
|
||||
/obj/effect/decal/cleanable/vomit
|
||||
name = "vomit"
|
||||
desc = "Gosh, how unpleasant."
|
||||
icon = 'icons/effects/blood.dmi'
|
||||
icon_state = "vomit_1"
|
||||
random_icon_states = list("vomit_1", "vomit_2", "vomit_3", "vomit_4")
|
||||
|
||||
/obj/effect/decal/cleanable/vomit/attack_hand(mob/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(isflyperson(H))
|
||||
playsound(get_turf(src), 'sound/items/drink.ogg', 50, 1) //slurp
|
||||
H.visible_message("<span class='alert'>[H] extends a small proboscis into the vomit pool, sucking it with a slurping sound.</span>")
|
||||
if(reagents)
|
||||
for(var/datum/reagent/R in reagents.reagent_list)
|
||||
if (istype(R, /datum/reagent/consumable))
|
||||
var/datum/reagent/consumable/nutri_check = R
|
||||
if(nutri_check.nutriment_factor >0)
|
||||
H.nutrition += nutri_check.nutriment_factor * nutri_check.volume
|
||||
reagents.remove_reagent(nutri_check.id,nutri_check.volume)
|
||||
reagents.trans_to(H, reagents.total_volume)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/decal/cleanable/vomit/old
|
||||
name = "crusty dried vomit"
|
||||
desc = "You try not to look at the chunks, and fail."
|
||||
|
||||
/obj/effect/decal/cleanable/vomit/old/Initialize(mapload, list/datum/disease/diseases)
|
||||
. = ..()
|
||||
icon_state += "-old"
|
||||
|
||||
/obj/effect/decal/cleanable/tomato_smudge
|
||||
name = "tomato smudge"
|
||||
desc = "It's red."
|
||||
gender = NEUTER
|
||||
icon = 'icons/effects/tomatodecal.dmi'
|
||||
random_icon_states = list("tomato_floor1", "tomato_floor2", "tomato_floor3")
|
||||
|
||||
/obj/effect/decal/cleanable/plant_smudge
|
||||
name = "plant smudge"
|
||||
gender = NEUTER
|
||||
icon = 'icons/effects/tomatodecal.dmi'
|
||||
random_icon_states = list("smashed_plant")
|
||||
|
||||
/obj/effect/decal/cleanable/egg_smudge
|
||||
name = "smashed egg"
|
||||
desc = "Seems like this one won't hatch."
|
||||
gender = NEUTER
|
||||
icon = 'icons/effects/tomatodecal.dmi'
|
||||
random_icon_states = list("smashed_egg1", "smashed_egg2", "smashed_egg3")
|
||||
|
||||
/obj/effect/decal/cleanable/pie_smudge //honk
|
||||
name = "smashed pie"
|
||||
desc = "It's pie cream from a cream pie."
|
||||
gender = NEUTER
|
||||
icon = 'icons/effects/tomatodecal.dmi'
|
||||
random_icon_states = list("smashed_pie")
|
||||
|
||||
/obj/effect/decal/cleanable/chem_pile
|
||||
name = "chemical pile"
|
||||
desc = "A pile of chemicals. You can't quite tell what's inside it."
|
||||
gender = NEUTER
|
||||
icon = 'icons/obj/objects.dmi'
|
||||
icon_state = "ash"
|
||||
|
||||
/obj/effect/decal/cleanable/shreds
|
||||
name = "shreds"
|
||||
desc = "The shredded remains of what appears to be clothing."
|
||||
icon_state = "shreds"
|
||||
gender = PLURAL
|
||||
mergeable_decal = FALSE
|
||||
|
||||
/obj/effect/decal/cleanable/shreds/ex_act(severity, target)
|
||||
if(severity == 1) //so shreds created during an explosion aren't deleted by the explosion.
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/decal/cleanable/shreds/Initialize()
|
||||
pixel_x = rand(-10, 10)
|
||||
pixel_y = rand(-10, 10)
|
||||
. = ..()
|
||||
|
||||
/obj/effect/decal/cleanable/salt
|
||||
name = "salt pile"
|
||||
desc = "A sizable pile of table salt. Someone must be upset."
|
||||
icon = 'icons/effects/tomatodecal.dmi'
|
||||
icon_state = "salt_pile"
|
||||
gender = NEUTER
|
||||
|
||||
/obj/effect/decal/cleanable/glitter
|
||||
name = "generic glitter pile"
|
||||
desc = "The herpes of arts and crafts."
|
||||
icon = 'icons/effects/atmospherics.dmi'
|
||||
gender = NEUTER
|
||||
|
||||
/obj/effect/decal/cleanable/glitter/pink
|
||||
name = "pink glitter"
|
||||
icon_state = "plasma_old"
|
||||
|
||||
/obj/effect/decal/cleanable/glitter/white
|
||||
name = "white glitter"
|
||||
icon_state = "nitrous_oxide_old"
|
||||
|
||||
/obj/effect/decal/cleanable/glitter/blue
|
||||
name = "blue glitter"
|
||||
icon_state = "freon_old"
|
||||
|
||||
/obj/effect/decal/cleanable/plasma
|
||||
name = "stabilized plasma"
|
||||
desc = "A puddle of stabilized plasma."
|
||||
icon_state = "flour"
|
||||
color = "#9e0089"
|
||||
|
||||
/obj/effect/decal/cleanable/insectguts
|
||||
name = "insect guts"
|
||||
desc = "One bug squashed. Four more will rise in its place."
|
||||
icon = 'icons/effects/blood.dmi'
|
||||
icon_state = "xfloor1"
|
||||
random_icon_states = list("xfloor1", "xfloor2", "xfloor3", "xfloor4", "xfloor5", "xfloor6", "xfloor7")
|
||||
@@ -0,0 +1,60 @@
|
||||
// Note: BYOND is object oriented. There is no reason for this to be copy/pasted blood code.
|
||||
|
||||
/obj/effect/decal/cleanable/robot_debris
|
||||
name = "robot debris"
|
||||
desc = "It's a useless heap of junk... <i>or is it?</i>"
|
||||
icon = 'icons/mob/robots.dmi'
|
||||
icon_state = "gib1"
|
||||
layer = LOW_OBJ_LAYER
|
||||
random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6", "gib7")
|
||||
blood_state = BLOOD_STATE_OIL
|
||||
bloodiness = BLOOD_AMOUNT_PER_DECAL
|
||||
mergeable_decal = FALSE
|
||||
|
||||
/obj/effect/decal/cleanable/robot_debris/proc/streak(list/directions)
|
||||
set waitfor = 0
|
||||
var/direction = pick(directions)
|
||||
for (var/i = 0, i < pick(1, 200; 2, 150; 3, 50), i++)
|
||||
sleep(2)
|
||||
if (i > 0)
|
||||
if (prob(40))
|
||||
new /obj/effect/decal/cleanable/oil/streak(src.loc)
|
||||
else if (prob(10))
|
||||
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
|
||||
s.set_up(3, 1, src)
|
||||
s.start()
|
||||
if (!step_to(src, get_step(src, direction), 0))
|
||||
break
|
||||
|
||||
/obj/effect/decal/cleanable/robot_debris/ex_act()
|
||||
return
|
||||
|
||||
/obj/effect/decal/cleanable/robot_debris/limb
|
||||
random_icon_states = list("gibarm", "gibleg")
|
||||
|
||||
/obj/effect/decal/cleanable/robot_debris/up
|
||||
random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6", "gib7","gibup1","gibup1")
|
||||
|
||||
/obj/effect/decal/cleanable/robot_debris/down
|
||||
random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6", "gib7","gibdown1","gibdown1")
|
||||
|
||||
/obj/effect/decal/cleanable/oil
|
||||
name = "motor oil"
|
||||
desc = "It's black and greasy. Looks like Beepsky made another mess."
|
||||
icon = 'icons/mob/robots.dmi'
|
||||
icon_state = "floor1"
|
||||
random_icon_states = list("floor1", "floor2", "floor3", "floor4", "floor5", "floor6", "floor7")
|
||||
blood_state = BLOOD_STATE_OIL
|
||||
bloodiness = BLOOD_AMOUNT_PER_DECAL
|
||||
|
||||
/obj/effect/decal/cleanable/oil/Initialize()
|
||||
. = ..()
|
||||
reagents.add_reagent("oil", 30)
|
||||
|
||||
/obj/effect/decal/cleanable/oil/streak
|
||||
random_icon_states = list("streak1", "streak2", "streak3", "streak4", "streak5")
|
||||
|
||||
/obj/effect/decal/cleanable/oil/slippery
|
||||
|
||||
/obj/effect/decal/cleanable/oil/slippery/Initialize()
|
||||
AddComponent(/datum/component/slippery, 80, (NO_SLIP_WHEN_WALKING | SLIDE))
|
||||
@@ -0,0 +1,31 @@
|
||||
/obj/effect/decal/cleanable/crayon
|
||||
name = "rune"
|
||||
desc = "Graffiti. Damn kids."
|
||||
icon = 'icons/effects/crayondecal.dmi'
|
||||
icon_state = "rune1"
|
||||
plane = GAME_PLANE //makes the graffiti visible over a wall.
|
||||
gender = NEUTER
|
||||
mergeable_decal = FALSE
|
||||
var/do_icon_rotate = TRUE
|
||||
var/rotation = 0
|
||||
var/paint_colour = "#FFFFFF"
|
||||
|
||||
/obj/effect/decal/cleanable/crayon/Initialize(mapload, main, type, e_name, graf_rot, alt_icon = null)
|
||||
. = ..()
|
||||
|
||||
if(e_name)
|
||||
name = e_name
|
||||
desc = "A [name] vandalizing the station."
|
||||
if(alt_icon)
|
||||
icon = alt_icon
|
||||
if(type)
|
||||
icon_state = type
|
||||
if(graf_rot)
|
||||
rotation = graf_rot
|
||||
if(rotation && do_icon_rotate)
|
||||
var/matrix/M = matrix()
|
||||
M.Turn(rotation)
|
||||
src.transform = M
|
||||
if(main)
|
||||
paint_colour = main
|
||||
add_atom_colour(paint_colour, FIXED_COLOUR_PRIORITY)
|
||||
@@ -0,0 +1,48 @@
|
||||
/obj/effect/decal
|
||||
name = "decal"
|
||||
plane = FLOOR_PLANE
|
||||
anchored = TRUE
|
||||
resistance_flags = FIRE_PROOF | UNACIDABLE | ACID_PROOF
|
||||
var/turf_loc_check = TRUE
|
||||
|
||||
/obj/effect/decal/Initialize()
|
||||
. = ..()
|
||||
if(turf_loc_check && (!isturf(loc) || NeverShouldHaveComeHere(loc)))
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
/obj/effect/decal/blob_act(obj/structure/blob/B)
|
||||
if(B && B.loc == loc)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/decal/proc/NeverShouldHaveComeHere(turf/T)
|
||||
return isspaceturf(T) || isclosedturf(T) || islava(T) || istype(T, /turf/open/water) || ischasm(T)
|
||||
|
||||
/obj/effect/decal/ex_act(severity, target)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/decal/fire_act(exposed_temperature, exposed_volume)
|
||||
if(!(resistance_flags & FIRE_PROOF)) //non fire proof decal or being burned by lava
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/decal/HandleTurfChange(turf/T)
|
||||
..()
|
||||
if(T == loc && NeverShouldHaveComeHere(T))
|
||||
qdel(src)
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/obj/effect/turf_decal
|
||||
icon = 'icons/turf/decals.dmi'
|
||||
icon_state = "warningline"
|
||||
layer = TURF_DECAL_LAYER
|
||||
|
||||
/obj/effect/turf_decal/Initialize()
|
||||
..()
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
/obj/effect/turf_decal/ComponentInitialize()
|
||||
. = ..()
|
||||
var/turf/T = loc
|
||||
if(!istype(T)) //you know this will happen somehow
|
||||
CRASH("Turf decal initialized in an object/nullspace")
|
||||
T.AddComponent(/datum/component/decal, icon, icon_state, dir, CLEAN_GOD, color, null, null, alpha)
|
||||
@@ -0,0 +1,31 @@
|
||||
/obj/effect/temp_visual/point
|
||||
name = "pointer"
|
||||
icon = 'icons/mob/screen_gen.dmi'
|
||||
icon_state = "arrow"
|
||||
layer = POINT_LAYER
|
||||
duration = 25
|
||||
|
||||
/obj/effect/temp_visual/point/Initialize(mapload, set_invis = 0)
|
||||
. = ..()
|
||||
var/atom/old_loc = loc
|
||||
loc = get_turf(src) // We don't want to actualy trigger anything when it moves
|
||||
pixel_x = old_loc.pixel_x
|
||||
pixel_y = old_loc.pixel_y
|
||||
invisibility = set_invis
|
||||
|
||||
//Used by spraybottles.
|
||||
/obj/effect/decal/chempuff
|
||||
name = "chemicals"
|
||||
icon = 'icons/obj/chempuff.dmi'
|
||||
pass_flags = PASSTABLE | PASSGRILLE
|
||||
layer = FLY_LAYER
|
||||
|
||||
/obj/effect/decal/chempuff/blob_act(obj/structure/blob/B)
|
||||
return
|
||||
|
||||
/obj/effect/decal/fakelattice
|
||||
name = "lattice"
|
||||
desc = "A lightweight support lattice."
|
||||
icon = 'icons/obj/smooth_structures/lattice.dmi'
|
||||
icon_state = "lattice"
|
||||
density = TRUE
|
||||
@@ -0,0 +1,33 @@
|
||||
/obj/effect/decal/remains
|
||||
name = "remains"
|
||||
gender = PLURAL
|
||||
icon = 'icons/effects/blood.dmi'
|
||||
|
||||
/obj/effect/decal/remains/acid_act()
|
||||
visible_message("<span class='warning'>[src] dissolve[gender==PLURAL?"":"s"] into a puddle of sizzling goop!</span>")
|
||||
playsound(src, 'sound/items/welder.ogg', 150, 1)
|
||||
new /obj/effect/decal/cleanable/greenglow(drop_location())
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/decal/remains/human
|
||||
desc = "They look like human remains. They have a strange aura about them."
|
||||
icon_state = "remains"
|
||||
|
||||
/obj/effect/decal/remains/plasma
|
||||
icon_state = "remainsplasma"
|
||||
|
||||
/obj/effect/decal/remains/xeno
|
||||
desc = "They look like the remains of something... alien. They have a strange aura about them."
|
||||
icon_state = "remainsxeno"
|
||||
|
||||
/obj/effect/decal/remains/xeno/larva
|
||||
icon_state = "remainslarva"
|
||||
|
||||
/obj/effect/decal/remains/robot
|
||||
desc = "They look like the remains of something mechanical. They have a strange aura about them."
|
||||
icon = 'icons/mob/robots.dmi'
|
||||
icon_state = "remainsrobot"
|
||||
|
||||
/obj/effect/decal/cleanable/robot_debris/old
|
||||
name = "dusty robot debris"
|
||||
desc = "Looks like nobody has touched this in a while."
|
||||
@@ -0,0 +1,5 @@
|
||||
/obj/effect/turf_decal/sand
|
||||
icon_state = "sandyfloor"
|
||||
|
||||
/obj/effect/turf_decal/sand/plating
|
||||
icon_state = "sandyplating"
|
||||
@@ -0,0 +1,152 @@
|
||||
/obj/effect/turf_decal/stripes/line
|
||||
icon_state = "warningline"
|
||||
|
||||
/obj/effect/turf_decal/stripes/end
|
||||
icon_state = "warn_end"
|
||||
|
||||
/obj/effect/turf_decal/stripes/corner
|
||||
icon_state = "warninglinecorner"
|
||||
|
||||
/obj/effect/turf_decal/stripes/box
|
||||
icon_state = "warn_box"
|
||||
|
||||
/obj/effect/turf_decal/stripes/full
|
||||
icon_state = "warn_full"
|
||||
|
||||
/obj/effect/turf_decal/stripes/asteroid/line
|
||||
icon_state = "ast_warn"
|
||||
|
||||
/obj/effect/turf_decal/stripes/asteroid/end
|
||||
icon_state = "ast_warn_end"
|
||||
|
||||
/obj/effect/turf_decal/stripes/asteroid/corner
|
||||
icon_state = "ast_warn_corner"
|
||||
|
||||
/obj/effect/turf_decal/stripes/asteroid/box
|
||||
icon_state = "ast_warn_box"
|
||||
|
||||
/obj/effect/turf_decal/stripes/asteroid/full
|
||||
icon_state = "ast_warn_full"
|
||||
|
||||
/obj/effect/turf_decal/stripes/white/line
|
||||
icon_state = "warningline_white"
|
||||
|
||||
/obj/effect/turf_decal/stripes/white/end
|
||||
icon_state = "warn_end_white"
|
||||
|
||||
/obj/effect/turf_decal/stripes/white/corner
|
||||
icon_state = "warninglinecorner_white"
|
||||
|
||||
/obj/effect/turf_decal/stripes/white/box
|
||||
icon_state = "warn_box_white"
|
||||
|
||||
/obj/effect/turf_decal/stripes/white/full
|
||||
icon_state = "warn_full_white"
|
||||
|
||||
/obj/effect/turf_decal/stripes/red/line
|
||||
icon_state = "warningline_red"
|
||||
|
||||
/obj/effect/turf_decal/stripes/red/end
|
||||
icon_state = "warn_end_red"
|
||||
|
||||
/obj/effect/turf_decal/stripes/red/corner
|
||||
icon_state = "warninglinecorner_red"
|
||||
|
||||
/obj/effect/turf_decal/stripes/red/box
|
||||
icon_state = "warn_box_red"
|
||||
|
||||
/obj/effect/turf_decal/stripes/red/full
|
||||
icon_state = "warn_full_red"
|
||||
|
||||
/obj/effect/turf_decal/delivery
|
||||
icon_state = "delivery"
|
||||
|
||||
/obj/effect/turf_decal/delivery/white
|
||||
icon_state = "delivery_white"
|
||||
|
||||
/obj/effect/turf_decal/delivery/red
|
||||
icon_state = "delivery_red"
|
||||
|
||||
/obj/effect/turf_decal/bot
|
||||
icon_state = "bot"
|
||||
|
||||
/obj/effect/turf_decal/bot/right
|
||||
icon_state = "bot_right"
|
||||
|
||||
/obj/effect/turf_decal/bot/left
|
||||
icon_state = "bot_left"
|
||||
|
||||
/obj/effect/turf_decal/bot_white
|
||||
icon_state = "bot_white"
|
||||
|
||||
/obj/effect/turf_decal/bot_white/right
|
||||
icon_state = "bot_right_white"
|
||||
|
||||
/obj/effect/turf_decal/bot_white/left
|
||||
icon_state = "bot_left_white"
|
||||
|
||||
/obj/effect/turf_decal/bot_red
|
||||
icon_state = "bot_red"
|
||||
|
||||
/obj/effect/turf_decal/bot_red/right
|
||||
icon_state = "bot_right_red"
|
||||
|
||||
/obj/effect/turf_decal/bot_red/left
|
||||
icon_state = "bot_left_red"
|
||||
|
||||
/obj/effect/turf_decal/loading_area
|
||||
icon_state = "loadingarea"
|
||||
|
||||
/obj/effect/turf_decal/loading_area/white
|
||||
icon_state = "loadingarea_white"
|
||||
|
||||
/obj/effect/turf_decal/loading_area/red
|
||||
icon_state = "loadingarea_red"
|
||||
|
||||
/obj/effect/turf_decal/caution
|
||||
icon_state = "caution"
|
||||
|
||||
/obj/effect/turf_decal/caution/white
|
||||
icon_state = "caution_white"
|
||||
|
||||
/obj/effect/turf_decal/caution/red
|
||||
icon_state = "caution_red"
|
||||
|
||||
/obj/effect/turf_decal/caution/stand_clear
|
||||
icon_state = "stand_clear"
|
||||
|
||||
/obj/effect/turf_decal/caution/stand_clear/white
|
||||
icon_state = "stand_clear_white"
|
||||
|
||||
/obj/effect/turf_decal/caution/stand_clear/red
|
||||
icon_state = "stand_clear_red"
|
||||
|
||||
/obj/effect/turf_decal/arrows
|
||||
icon_state = "arrows"
|
||||
|
||||
/obj/effect/turf_decal/arrows/white
|
||||
icon_state = "arrows_white"
|
||||
|
||||
/obj/effect/turf_decal/arrows/red
|
||||
icon_state = "arrows_red"
|
||||
|
||||
/obj/effect/turf_decal/box
|
||||
icon_state = "box"
|
||||
|
||||
/obj/effect/turf_decal/box/corners
|
||||
icon_state = "box_corners"
|
||||
|
||||
/obj/effect/turf_decal/box/white
|
||||
icon_state = "box_white"
|
||||
|
||||
/obj/effect/turf_decal/box/white/corners
|
||||
icon_state = "box_corners_white"
|
||||
|
||||
/obj/effect/turf_decal/box/red
|
||||
icon_state = "box_red"
|
||||
|
||||
/obj/effect/turf_decal/box/red/corners
|
||||
icon_state = "box_corners_red"
|
||||
|
||||
/obj/effect/turf_decal/plaque
|
||||
icon_state = "plaque"
|
||||
@@ -0,0 +1,39 @@
|
||||
/obj/effect/turf_decal/tile
|
||||
name = "tile decal"
|
||||
icon_state = "tile_corner"
|
||||
layer = TURF_PLATING_DECAL_LAYER
|
||||
alpha = 110
|
||||
|
||||
/obj/effect/turf_decal/tile/blue
|
||||
name = "blue corner"
|
||||
color = "#52B4E9"
|
||||
|
||||
/obj/effect/turf_decal/tile/green
|
||||
name = "green corner"
|
||||
color = "#9FED58"
|
||||
|
||||
/obj/effect/turf_decal/tile/yellow
|
||||
name = "yellow corner"
|
||||
color = "#EFB341"
|
||||
|
||||
/obj/effect/turf_decal/tile/red
|
||||
name = "red corner"
|
||||
color = "#DE3A3A"
|
||||
|
||||
/obj/effect/turf_decal/tile/bar
|
||||
name = "bar corner"
|
||||
color = "#791500"
|
||||
alpha = 130
|
||||
|
||||
/obj/effect/turf_decal/tile/purple
|
||||
name = "purple corner"
|
||||
color = "#D381C9"
|
||||
|
||||
/obj/effect/turf_decal/tile/brown
|
||||
name = "brown corner"
|
||||
color = "#A46106"
|
||||
|
||||
/obj/effect/turf_decal/tile/neutral
|
||||
name = "neutral corner"
|
||||
color = "#D4D4D4"
|
||||
alpha = 50
|
||||
@@ -0,0 +1,12 @@
|
||||
/obj/effect/turf_decal/weather
|
||||
name = "sandy floor"
|
||||
icon_state = "sandyfloor"
|
||||
|
||||
/obj/effect/turf_decal/weather/snow
|
||||
name = "snowy floor"
|
||||
icon_state = "snowyfloor"
|
||||
|
||||
/obj/effect/turf_decal/weather/snow/corner
|
||||
name = "snow corner piece"
|
||||
icon = 'icons/turf/snow.dmi'
|
||||
icon_state = "snow_corner"
|
||||
@@ -0,0 +1,77 @@
|
||||
/* This is an attempt to make some easily reusable "particle" type effect, to stop the code
|
||||
constantly having to be rewritten. An item like the jetpack that uses the ion_trail_follow system, just has one
|
||||
defined, then set up when it is created with New(). Then this same system can just be reused each time
|
||||
it needs to create more trails.A beaker could have a steam_trail_follow system set up, then the steam
|
||||
would spawn and follow the beaker, even if it is carried or thrown.
|
||||
*/
|
||||
|
||||
|
||||
/obj/effect/particle_effect
|
||||
name = "particle effect"
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
pass_flags = PASSTABLE | PASSGRILLE
|
||||
anchored = TRUE
|
||||
|
||||
/obj/effect/particle_effect/Initialize()
|
||||
. = ..()
|
||||
GLOB.cameranet.updateVisibility(src)
|
||||
|
||||
/obj/effect/particle_effect/Destroy()
|
||||
GLOB.cameranet.updateVisibility(src)
|
||||
return ..()
|
||||
|
||||
/datum/effect_system
|
||||
var/number = 3
|
||||
var/cardinals = FALSE
|
||||
var/turf/location
|
||||
var/atom/holder
|
||||
var/effect_type
|
||||
var/total_effects = 0
|
||||
var/autocleanup = FALSE //will delete itself after use
|
||||
|
||||
/datum/effect_system/Destroy()
|
||||
holder = null
|
||||
location = null
|
||||
return ..()
|
||||
|
||||
/datum/effect_system/proc/set_up(n = 3, c = FALSE, loca)
|
||||
if(n > 10)
|
||||
n = 10
|
||||
number = n
|
||||
cardinals = c
|
||||
if(isturf(loca))
|
||||
location = loca
|
||||
else
|
||||
location = get_turf(loca)
|
||||
|
||||
/datum/effect_system/proc/attach(atom/atom)
|
||||
holder = atom
|
||||
|
||||
/datum/effect_system/proc/start()
|
||||
for(var/i in 1 to number)
|
||||
if(total_effects > 20)
|
||||
return
|
||||
INVOKE_ASYNC(src, .proc/generate_effect)
|
||||
|
||||
/datum/effect_system/proc/generate_effect()
|
||||
if(holder)
|
||||
location = get_turf(holder)
|
||||
if(location.contents.len > 200) //Bandaid to prevent server crash exploit
|
||||
return
|
||||
var/obj/effect/E = new effect_type(location)
|
||||
total_effects++
|
||||
var/direction
|
||||
if(cardinals)
|
||||
direction = pick(GLOB.cardinals)
|
||||
else
|
||||
direction = pick(GLOB.alldirs)
|
||||
var/steps_amt = pick(1,2,3)
|
||||
for(var/j in 1 to steps_amt)
|
||||
sleep(5)
|
||||
step(E,direction)
|
||||
addtimer(CALLBACK(src, .proc/decrement_total_effect), 20)
|
||||
|
||||
/datum/effect_system/proc/decrement_total_effect()
|
||||
total_effects--
|
||||
if(autocleanup && total_effects <= 0)
|
||||
qdel(src)
|
||||
@@ -0,0 +1,58 @@
|
||||
/obj/effect/particle_effect/expl_particles
|
||||
name = "fire"
|
||||
icon_state = "explosion_particle"
|
||||
opacity = 1
|
||||
anchored = TRUE
|
||||
|
||||
/obj/effect/particle_effect/expl_particles/Initialize()
|
||||
. = ..()
|
||||
QDEL_IN(src, 15)
|
||||
|
||||
/datum/effect_system/expl_particles
|
||||
number = 10
|
||||
|
||||
/datum/effect_system/expl_particles/start()
|
||||
for(var/i in 1 to number)
|
||||
var/obj/effect/particle_effect/expl_particles/expl = new /obj/effect/particle_effect/expl_particles(location)
|
||||
var/direct = pick(GLOB.alldirs)
|
||||
var/steps_amt = pick(1;25,2;50,3,4;200)
|
||||
for(var/j in 1 to steps_amt)
|
||||
addtimer(CALLBACK(GLOBAL_PROC, .proc/_step, expl, direct), j)
|
||||
|
||||
/obj/effect/explosion
|
||||
name = "fire"
|
||||
icon = 'icons/effects/96x96.dmi'
|
||||
icon_state = "explosion"
|
||||
opacity = 1
|
||||
anchored = TRUE
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
pixel_x = -32
|
||||
pixel_y = -32
|
||||
|
||||
/obj/effect/explosion/Initialize()
|
||||
. = ..()
|
||||
QDEL_IN(src, 10)
|
||||
|
||||
/datum/effect_system/explosion
|
||||
|
||||
/datum/effect_system/explosion/set_up(loca)
|
||||
if(isturf(loca))
|
||||
location = loca
|
||||
else
|
||||
location = get_turf(loca)
|
||||
|
||||
/datum/effect_system/explosion/start()
|
||||
new/obj/effect/explosion( location )
|
||||
var/datum/effect_system/expl_particles/P = new/datum/effect_system/expl_particles()
|
||||
P.set_up(10, 0, location)
|
||||
P.start()
|
||||
|
||||
/datum/effect_system/explosion/smoke
|
||||
|
||||
/datum/effect_system/explosion/smoke/proc/create_smoke()
|
||||
var/datum/effect_system/smoke_spread/S = new
|
||||
S.set_up(2, location)
|
||||
S.start()
|
||||
/datum/effect_system/explosion/smoke/start()
|
||||
..()
|
||||
addtimer(CALLBACK(src, .proc/create_smoke), 5)
|
||||
@@ -0,0 +1,347 @@
|
||||
// Foam
|
||||
// Similar to smoke, but slower and mobs absorb its reagent through their exposed skin.
|
||||
#define ALUMINUM_FOAM 1
|
||||
#define IRON_FOAM 2
|
||||
#define RESIN_FOAM 3
|
||||
|
||||
|
||||
/obj/effect/particle_effect/foam
|
||||
name = "foam"
|
||||
icon_state = "foam"
|
||||
opacity = 0
|
||||
anchored = TRUE
|
||||
density = FALSE
|
||||
layer = EDGED_TURF_LAYER
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
var/amount = 3
|
||||
animate_movement = 0
|
||||
var/metal = 0
|
||||
var/lifetime = 40
|
||||
var/reagent_divisor = 7
|
||||
var/static/list/blacklisted_turfs = typecacheof(list(
|
||||
/turf/open/space/transit,
|
||||
/turf/open/chasm,
|
||||
/turf/open/lava))
|
||||
|
||||
/obj/effect/particle_effect/foam/firefighting
|
||||
name = "firefighting foam"
|
||||
lifetime = 20 //doesn't last as long as normal foam
|
||||
amount = 0 //no spread
|
||||
var/absorbed_plasma = 0
|
||||
|
||||
/obj/effect/particle_effect/foam/firefighting/MakeSlippery()
|
||||
return
|
||||
|
||||
/obj/effect/particle_effect/foam/firefighting/process()
|
||||
..()
|
||||
|
||||
var/turf/open/T = get_turf(src)
|
||||
var/obj/effect/hotspot/hotspot = (locate(/obj/effect/hotspot) in T)
|
||||
if(hotspot && istype(T) && T.air)
|
||||
qdel(hotspot)
|
||||
var/datum/gas_mixture/G = T.air
|
||||
var/plas_amt = min(30,G.gases[/datum/gas/plasma]) //Absorb some plasma
|
||||
G.gases[/datum/gas/plasma] -= plas_amt
|
||||
absorbed_plasma += plas_amt
|
||||
if(G.temperature > T20C)
|
||||
G.temperature = max(G.temperature/2,T20C)
|
||||
GAS_GARBAGE_COLLECT(G.gases)
|
||||
T.air_update_turf()
|
||||
|
||||
/obj/effect/particle_effect/foam/firefighting/kill_foam()
|
||||
STOP_PROCESSING(SSfastprocess, src)
|
||||
|
||||
if(absorbed_plasma)
|
||||
var/obj/effect/decal/cleanable/plasma/P = (locate(/obj/effect/decal/cleanable/plasma) in get_turf(src))
|
||||
if(!P)
|
||||
P = new(loc)
|
||||
P.reagents.add_reagent("stable_plasma", absorbed_plasma)
|
||||
|
||||
flick("[icon_state]-disolve", src)
|
||||
QDEL_IN(src, 5)
|
||||
|
||||
/obj/effect/particle_effect/foam/firefighting/foam_mob(mob/living/L)
|
||||
if(!istype(L))
|
||||
return
|
||||
L.adjust_fire_stacks(-2)
|
||||
L.ExtinguishMob()
|
||||
|
||||
/obj/effect/particle_effect/foam/firefighting/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
|
||||
return
|
||||
|
||||
/obj/effect/particle_effect/foam/metal
|
||||
name = "aluminium foam"
|
||||
metal = ALUMINUM_FOAM
|
||||
icon_state = "mfoam"
|
||||
|
||||
/obj/effect/particle_effect/foam/metal/MakeSlippery()
|
||||
return
|
||||
|
||||
/obj/effect/particle_effect/foam/metal/smart
|
||||
name = "smart foam"
|
||||
|
||||
/obj/effect/particle_effect/foam/metal/iron
|
||||
name = "iron foam"
|
||||
metal = IRON_FOAM
|
||||
|
||||
/obj/effect/particle_effect/foam/metal/resin
|
||||
name = "resin foam"
|
||||
metal = RESIN_FOAM
|
||||
|
||||
/obj/effect/particle_effect/foam/long_life
|
||||
lifetime = 150
|
||||
|
||||
/obj/effect/particle_effect/foam/Initialize()
|
||||
. = ..()
|
||||
MakeSlippery()
|
||||
create_reagents(1000) //limited by the size of the reagent holder anyway.
|
||||
START_PROCESSING(SSfastprocess, src)
|
||||
playsound(src, 'sound/effects/bubbles2.ogg', 80, 1, -3)
|
||||
|
||||
/obj/effect/particle_effect/foam/proc/MakeSlippery()
|
||||
AddComponent(/datum/component/slippery, 100)
|
||||
|
||||
/obj/effect/particle_effect/foam/Destroy()
|
||||
STOP_PROCESSING(SSfastprocess, src)
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/effect/particle_effect/foam/proc/kill_foam()
|
||||
STOP_PROCESSING(SSfastprocess, src)
|
||||
switch(metal)
|
||||
if(ALUMINUM_FOAM)
|
||||
new /obj/structure/foamedmetal(get_turf(src))
|
||||
if(IRON_FOAM)
|
||||
new /obj/structure/foamedmetal/iron(get_turf(src))
|
||||
if(RESIN_FOAM)
|
||||
new /obj/structure/foamedmetal/resin(get_turf(src))
|
||||
flick("[icon_state]-disolve", src)
|
||||
QDEL_IN(src, 5)
|
||||
|
||||
/obj/effect/particle_effect/foam/smart/kill_foam() //Smart foam adheres to area borders for walls
|
||||
STOP_PROCESSING(SSfastprocess, src)
|
||||
if(metal)
|
||||
var/turf/T = get_turf(src)
|
||||
if(isspaceturf(T)) //Block up any exposed space
|
||||
T.PlaceOnTop(/turf/open/floor/plating/foam)
|
||||
for(var/direction in GLOB.cardinals)
|
||||
var/turf/cardinal_turf = get_step(T, direction)
|
||||
if(get_area(cardinal_turf) != get_area(T)) //We're at an area boundary, so let's block off this turf!
|
||||
new/obj/structure/foamedmetal(T)
|
||||
break
|
||||
flick("[icon_state]-disolve", src)
|
||||
QDEL_IN(src, 5)
|
||||
|
||||
/obj/effect/particle_effect/foam/process()
|
||||
lifetime--
|
||||
if(lifetime < 1)
|
||||
kill_foam()
|
||||
return
|
||||
|
||||
var/fraction = 1/initial(reagent_divisor)
|
||||
for(var/obj/O in range(0,src))
|
||||
if(O.type == src.type)
|
||||
continue
|
||||
if(isturf(O.loc))
|
||||
var/turf/T = O.loc
|
||||
if(T.intact && O.level == 1) //hidden under the floor
|
||||
continue
|
||||
if(lifetime % reagent_divisor)
|
||||
reagents.reaction(O, VAPOR, fraction)
|
||||
var/hit = 0
|
||||
for(var/mob/living/L in range(0,src))
|
||||
hit += foam_mob(L)
|
||||
if(hit)
|
||||
lifetime++ //this is so the decrease from mobs hit and the natural decrease don't cumulate.
|
||||
var/T = get_turf(src)
|
||||
if(lifetime % reagent_divisor)
|
||||
reagents.reaction(T, VAPOR, fraction)
|
||||
|
||||
if(--amount < 0)
|
||||
return
|
||||
spread_foam()
|
||||
|
||||
/obj/effect/particle_effect/foam/proc/foam_mob(mob/living/L)
|
||||
if(lifetime<1)
|
||||
return 0
|
||||
if(!istype(L))
|
||||
return 0
|
||||
var/fraction = 1/initial(reagent_divisor)
|
||||
if(lifetime % reagent_divisor)
|
||||
reagents.reaction(L, VAPOR, fraction)
|
||||
lifetime--
|
||||
return 1
|
||||
|
||||
/obj/effect/particle_effect/foam/proc/spread_foam()
|
||||
var/turf/t_loc = get_turf(src)
|
||||
for(var/turf/T in t_loc.GetAtmosAdjacentTurfs())
|
||||
var/obj/effect/particle_effect/foam/foundfoam = locate() in T //Don't spread foam where there's already foam!
|
||||
if(foundfoam)
|
||||
continue
|
||||
|
||||
if(is_type_in_typecache(T, blacklisted_turfs))
|
||||
continue
|
||||
|
||||
for(var/mob/living/L in T)
|
||||
foam_mob(L)
|
||||
var/obj/effect/particle_effect/foam/F = new src.type(T)
|
||||
F.amount = amount
|
||||
reagents.copy_to(F, (reagents.total_volume))
|
||||
F.add_atom_colour(color, FIXED_COLOUR_PRIORITY)
|
||||
F.metal = metal
|
||||
|
||||
|
||||
/obj/effect/particle_effect/foam/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
|
||||
if(prob(max(0, exposed_temperature - 475))) //foam dissolves when heated
|
||||
kill_foam()
|
||||
|
||||
|
||||
/obj/effect/particle_effect/foam/metal/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
|
||||
return
|
||||
|
||||
|
||||
///////////////////////////////////////////////
|
||||
//FOAM EFFECT DATUM
|
||||
/datum/effect_system/foam_spread
|
||||
var/amount = 10 // the size of the foam spread.
|
||||
var/obj/chemholder
|
||||
effect_type = /obj/effect/particle_effect/foam
|
||||
var/metal = 0
|
||||
|
||||
|
||||
/datum/effect_system/foam_spread/metal
|
||||
effect_type = /obj/effect/particle_effect/foam/metal
|
||||
|
||||
|
||||
/datum/effect_system/foam_spread/metal/smart
|
||||
effect_type = /obj/effect/particle_effect/foam/smart
|
||||
|
||||
|
||||
/datum/effect_system/foam_spread/long
|
||||
effect_type = /obj/effect/particle_effect/foam/long_life
|
||||
|
||||
/datum/effect_system/foam_spread/New()
|
||||
..()
|
||||
chemholder = new /obj()
|
||||
var/datum/reagents/R = new/datum/reagents(1000)
|
||||
chemholder.reagents = R
|
||||
R.my_atom = chemholder
|
||||
|
||||
/datum/effect_system/foam_spread/Destroy()
|
||||
qdel(chemholder)
|
||||
chemholder = null
|
||||
return ..()
|
||||
|
||||
/datum/effect_system/foam_spread/set_up(amt=5, loca, datum/reagents/carry = null)
|
||||
if(isturf(loca))
|
||||
location = loca
|
||||
else
|
||||
location = get_turf(loca)
|
||||
|
||||
amount = round(sqrt(amt / 2), 1)
|
||||
carry.copy_to(chemholder, carry.total_volume)
|
||||
|
||||
/datum/effect_system/foam_spread/metal/set_up(amt=5, loca, datum/reagents/carry = null, metaltype)
|
||||
..()
|
||||
metal = metaltype
|
||||
|
||||
/datum/effect_system/foam_spread/start()
|
||||
var/obj/effect/particle_effect/foam/F = new effect_type(location)
|
||||
var/foamcolor = mix_color_from_reagents(chemholder.reagents.reagent_list)
|
||||
chemholder.reagents.copy_to(F, chemholder.reagents.total_volume/amount)
|
||||
F.add_atom_colour(foamcolor, FIXED_COLOUR_PRIORITY)
|
||||
F.amount = amount
|
||||
F.metal = metal
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
// FOAM STRUCTURE. Formed by metal foams. Dense and opaque, but easy to break
|
||||
/obj/structure/foamedmetal
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
icon_state = "metalfoam"
|
||||
density = TRUE
|
||||
opacity = 1 // changed in New()
|
||||
anchored = TRUE
|
||||
layer = EDGED_TURF_LAYER
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
name = "foamed metal"
|
||||
desc = "A lightweight foamed metal wall."
|
||||
gender = PLURAL
|
||||
max_integrity = 20
|
||||
CanAtmosPass = ATMOS_PASS_DENSITY
|
||||
|
||||
/obj/structure/foamedmetal/Initialize()
|
||||
. = ..()
|
||||
air_update_turf(1)
|
||||
|
||||
/obj/structure/foamedmetal/Move()
|
||||
var/turf/T = loc
|
||||
. = ..()
|
||||
move_update_air(T)
|
||||
|
||||
/obj/structure/foamedmetal/attack_paw(mob/user)
|
||||
return attack_hand(user)
|
||||
|
||||
/obj/structure/foamedmetal/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
|
||||
playsound(src.loc, 'sound/weapons/tap.ogg', 100, 1)
|
||||
|
||||
/obj/structure/foamedmetal/attack_hand(mob/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
user.do_attack_animation(src, ATTACK_EFFECT_PUNCH)
|
||||
to_chat(user, "<span class='warning'>You hit [src] but bounce off it!</span>")
|
||||
playsound(src.loc, 'sound/weapons/tap.ogg', 100, 1)
|
||||
|
||||
/obj/structure/foamedmetal/CanPass(atom/movable/mover, turf/target)
|
||||
return !density
|
||||
|
||||
/obj/structure/foamedmetal/iron
|
||||
max_integrity = 50
|
||||
icon_state = "ironfoam"
|
||||
|
||||
//Atmos Backpack Resin, transparent, prevents atmos and filters the air
|
||||
/obj/structure/foamedmetal/resin
|
||||
name = "\improper ATMOS Resin"
|
||||
desc = "A lightweight, transparent resin used to suffocate fires, scrub the air of toxins, and restore the air to a safe temperature."
|
||||
opacity = FALSE
|
||||
icon_state = "atmos_resin"
|
||||
alpha = 120
|
||||
max_integrity = 10
|
||||
|
||||
/obj/structure/foamedmetal/resin/Initialize()
|
||||
. = ..()
|
||||
if(isopenturf(loc))
|
||||
var/turf/open/O = loc
|
||||
O.ClearWet()
|
||||
if(O.air)
|
||||
var/datum/gas_mixture/G = O.air
|
||||
G.temperature = 293.15
|
||||
for(var/obj/effect/hotspot/H in O)
|
||||
qdel(H)
|
||||
var/list/G_gases = G.gases
|
||||
for(var/I in G_gases)
|
||||
if(I == /datum/gas/oxygen || I == /datum/gas/nitrogen)
|
||||
continue
|
||||
G_gases[I] = 0
|
||||
GAS_GARBAGE_COLLECT(G.gases)
|
||||
O.air_update_turf()
|
||||
for(var/obj/machinery/atmospherics/components/unary/U in O)
|
||||
if(!U.welded)
|
||||
U.welded = TRUE
|
||||
U.update_icon()
|
||||
U.visible_message("<span class='danger'>[U] sealed shut!</span>")
|
||||
for(var/mob/living/L in O)
|
||||
L.ExtinguishMob()
|
||||
for(var/obj/item/Item in O)
|
||||
Item.extinguish()
|
||||
|
||||
/obj/structure/foamedmetal/resin/CanPass(atom/movable/mover, turf/target)
|
||||
if(istype(mover) && (mover.pass_flags & PASSGLASS))
|
||||
return TRUE
|
||||
. = ..()
|
||||
|
||||
#undef ALUMINUM_FOAM
|
||||
#undef IRON_FOAM
|
||||
#undef RESIN_FOAM
|
||||
@@ -0,0 +1,118 @@
|
||||
|
||||
/////////////////////////////////////////////
|
||||
//////// Attach a trail to any object, that spawns when it moves (like for the jetpack)
|
||||
/// just pass in the object to attach it to in set_up
|
||||
/// Then do start() to start it and stop() to stop it, obviously
|
||||
/// and don't call start() in a loop that will be repeated otherwise it'll get spammed!
|
||||
/////////////////////////////////////////////
|
||||
|
||||
/datum/effect_system/trail_follow
|
||||
var/turf/oldposition
|
||||
var/active = FALSE
|
||||
var/allow_overlap = FALSE
|
||||
var/auto_process = TRUE
|
||||
var/qdel_in_time = 10
|
||||
var/fadetype = "ion_fade"
|
||||
var/fade = TRUE
|
||||
var/nograv_required = FALSE
|
||||
|
||||
/datum/effect_system/trail_follow/set_up(atom/atom)
|
||||
attach(atom)
|
||||
oldposition = get_turf(atom)
|
||||
|
||||
/datum/effect_system/trail_follow/Destroy()
|
||||
oldposition = null
|
||||
stop()
|
||||
return ..()
|
||||
|
||||
/datum/effect_system/trail_follow/proc/stop()
|
||||
oldposition = null
|
||||
STOP_PROCESSING(SSfastprocess, src)
|
||||
active = FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/effect_system/trail_follow/start()
|
||||
oldposition = get_turf(holder)
|
||||
if(!check_conditions())
|
||||
return FALSE
|
||||
if(auto_process)
|
||||
START_PROCESSING(SSfastprocess, src)
|
||||
active = TRUE
|
||||
return TRUE
|
||||
|
||||
/datum/effect_system/trail_follow/process()
|
||||
generate_effect()
|
||||
|
||||
/datum/effect_system/trail_follow/generate_effect()
|
||||
if(!check_conditions())
|
||||
return stop()
|
||||
if(oldposition && !(oldposition == get_turf(holder)))
|
||||
if(!oldposition.has_gravity() || !nograv_required)
|
||||
var/obj/effect/E = new effect_type(oldposition)
|
||||
set_dir(E)
|
||||
if(fade)
|
||||
flick(fadetype, E)
|
||||
E.icon_state = ""
|
||||
if(qdel_in_time)
|
||||
QDEL_IN(E, qdel_in_time)
|
||||
oldposition = get_turf(holder)
|
||||
|
||||
/datum/effect_system/trail_follow/proc/check_conditions()
|
||||
if(!get_turf(holder))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/datum/effect_system/trail_follow/steam
|
||||
effect_type = /obj/effect/particle_effect/steam
|
||||
|
||||
/obj/effect/particle_effect/ion_trails
|
||||
name = "ion trails"
|
||||
icon_state = "ion_trails"
|
||||
anchored = TRUE
|
||||
|
||||
/obj/effect/particle_effect/ion_trails/flight
|
||||
icon_state = "ion_trails_flight"
|
||||
|
||||
/datum/effect_system/trail_follow/ion
|
||||
effect_type = /obj/effect/particle_effect/ion_trails
|
||||
nograv_required = TRUE
|
||||
qdel_in_time = 20
|
||||
|
||||
/datum/effect_system/trail_follow/proc/set_dir(obj/effect/particle_effect/ion_trails/I)
|
||||
I.setDir(holder.dir)
|
||||
|
||||
//Reagent-based explosion effect
|
||||
|
||||
/datum/effect_system/reagents_explosion
|
||||
var/amount // TNT equivalent
|
||||
var/flashing = 0 // does explosion creates flash effect?
|
||||
var/flashing_factor = 0 // factor of how powerful the flash effect relatively to the explosion
|
||||
var/explosion_message = 1 //whether we show a message to mobs.
|
||||
|
||||
/datum/effect_system/reagents_explosion/set_up(amt, loca, flash = 0, flash_fact = 0, message = 1)
|
||||
amount = amt
|
||||
explosion_message = message
|
||||
if(isturf(loca))
|
||||
location = loca
|
||||
else
|
||||
location = get_turf(loca)
|
||||
|
||||
flashing = flash
|
||||
flashing_factor = flash_fact
|
||||
|
||||
/datum/effect_system/reagents_explosion/start()
|
||||
if(explosion_message)
|
||||
location.visible_message("<span class='danger'>The solution violently explodes!</span>", \
|
||||
"<span class='italics'>You hear an explosion!</span>")
|
||||
if (amount < 1)
|
||||
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
|
||||
s.set_up(2, 1, location)
|
||||
s.start()
|
||||
|
||||
for(var/mob/living/L in viewers(1, location))
|
||||
if(prob(50 * amount))
|
||||
to_chat(L, "<span class='danger'>The explosion knocks you down.</span>")
|
||||
L.Knockdown(rand(20,100))
|
||||
return
|
||||
else
|
||||
dyn_explosion(location, amount, flashing_factor)
|
||||
@@ -0,0 +1,328 @@
|
||||
/////////////////////////////////////////////
|
||||
//// SMOKE SYSTEMS
|
||||
/////////////////////////////////////////////
|
||||
|
||||
/obj/effect/particle_effect/smoke
|
||||
name = "smoke"
|
||||
icon = 'icons/effects/96x96.dmi'
|
||||
icon_state = "smoke"
|
||||
pixel_x = -32
|
||||
pixel_y = -32
|
||||
opacity = 0
|
||||
layer = FLY_LAYER
|
||||
anchored = TRUE
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
animate_movement = 0
|
||||
var/amount = 4
|
||||
var/lifetime = 5
|
||||
var/opaque = 1 //whether the smoke can block the view when in enough amount
|
||||
|
||||
|
||||
/obj/effect/particle_effect/smoke/proc/fade_out(frames = 16)
|
||||
if(alpha == 0) //Handle already transparent case
|
||||
return
|
||||
if(frames == 0)
|
||||
frames = 1 //We will just assume that by 0 frames, the coder meant "during one frame".
|
||||
var/step = alpha / frames
|
||||
for(var/i = 0, i < frames, i++)
|
||||
alpha -= step
|
||||
if(alpha < 160)
|
||||
set_opacity(0) //if we were blocking view, we aren't now because we're fading out
|
||||
stoplag()
|
||||
|
||||
/obj/effect/particle_effect/smoke/Initialize()
|
||||
. = ..()
|
||||
create_reagents(500)
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
|
||||
/obj/effect/particle_effect/smoke/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return ..()
|
||||
|
||||
/obj/effect/particle_effect/smoke/proc/kill_smoke()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
INVOKE_ASYNC(src, .proc/fade_out)
|
||||
QDEL_IN(src, 10)
|
||||
|
||||
/obj/effect/particle_effect/smoke/process()
|
||||
lifetime--
|
||||
if(lifetime < 1)
|
||||
kill_smoke()
|
||||
return 0
|
||||
for(var/mob/living/L in range(0,src))
|
||||
smoke_mob(L)
|
||||
return 1
|
||||
|
||||
/obj/effect/particle_effect/smoke/proc/smoke_mob(mob/living/carbon/C)
|
||||
if(!istype(C))
|
||||
return 0
|
||||
if(lifetime<1)
|
||||
return 0
|
||||
if(C.internal != null || C.has_smoke_protection())
|
||||
return 0
|
||||
if(C.smoke_delay)
|
||||
return 0
|
||||
C.smoke_delay++
|
||||
addtimer(CALLBACK(src, .proc/remove_smoke_delay, C), 10)
|
||||
return 1
|
||||
|
||||
/obj/effect/particle_effect/smoke/proc/remove_smoke_delay(mob/living/carbon/C)
|
||||
if(C)
|
||||
C.smoke_delay = 0
|
||||
|
||||
/obj/effect/particle_effect/smoke/proc/spread_smoke()
|
||||
var/turf/t_loc = get_turf(src)
|
||||
if(!t_loc)
|
||||
return
|
||||
var/list/newsmokes = list()
|
||||
for(var/turf/T in t_loc.GetAtmosAdjacentTurfs())
|
||||
var/obj/effect/particle_effect/smoke/foundsmoke = locate() in T //Don't spread smoke where there's already smoke!
|
||||
if(foundsmoke)
|
||||
continue
|
||||
for(var/mob/living/L in T)
|
||||
smoke_mob(L)
|
||||
var/obj/effect/particle_effect/smoke/S = new type(T)
|
||||
reagents.copy_to(S, reagents.total_volume)
|
||||
S.setDir(pick(GLOB.cardinals))
|
||||
S.amount = amount-1
|
||||
S.add_atom_colour(color, FIXED_COLOUR_PRIORITY)
|
||||
S.lifetime = lifetime
|
||||
if(S.amount>0)
|
||||
if(opaque)
|
||||
S.set_opacity(TRUE)
|
||||
newsmokes.Add(S)
|
||||
|
||||
if(newsmokes.len)
|
||||
spawn(1) //the smoke spreads rapidly but not instantly
|
||||
for(var/obj/effect/particle_effect/smoke/SM in newsmokes)
|
||||
SM.spread_smoke()
|
||||
|
||||
|
||||
/datum/effect_system/smoke_spread
|
||||
var/amount = 10
|
||||
effect_type = /obj/effect/particle_effect/smoke
|
||||
|
||||
/datum/effect_system/smoke_spread/set_up(radius = 5, loca)
|
||||
if(isturf(loca))
|
||||
location = loca
|
||||
else
|
||||
location = get_turf(loca)
|
||||
amount = radius
|
||||
|
||||
/datum/effect_system/smoke_spread/start()
|
||||
if(holder)
|
||||
location = get_turf(holder)
|
||||
var/obj/effect/particle_effect/smoke/S = new effect_type(location)
|
||||
S.amount = amount
|
||||
if(S.amount)
|
||||
S.spread_smoke()
|
||||
|
||||
|
||||
/////////////////////////////////////////////
|
||||
// Bad smoke
|
||||
/////////////////////////////////////////////
|
||||
|
||||
/obj/effect/particle_effect/smoke/bad
|
||||
lifetime = 8
|
||||
|
||||
/obj/effect/particle_effect/smoke/bad/smoke_mob(mob/living/carbon/M)
|
||||
if(..())
|
||||
M.drop_all_held_items()
|
||||
M.adjustOxyLoss(1)
|
||||
M.emote("cough")
|
||||
return 1
|
||||
|
||||
/obj/effect/particle_effect/smoke/bad/CanPass(atom/movable/mover, turf/target)
|
||||
if(istype(mover, /obj/item/projectile/beam))
|
||||
var/obj/item/projectile/beam/B = mover
|
||||
B.damage = (B.damage/2)
|
||||
return 1
|
||||
|
||||
|
||||
|
||||
/datum/effect_system/smoke_spread/bad
|
||||
effect_type = /obj/effect/particle_effect/smoke/bad
|
||||
|
||||
/////////////////////////////////////////////
|
||||
// Nanofrost smoke
|
||||
/////////////////////////////////////////////
|
||||
|
||||
/obj/effect/particle_effect/smoke/freezing
|
||||
name = "nanofrost smoke"
|
||||
color = "#B2FFFF"
|
||||
opaque = 0
|
||||
|
||||
/datum/effect_system/smoke_spread/freezing
|
||||
effect_type = /obj/effect/particle_effect/smoke/freezing
|
||||
var/blast = 0
|
||||
var/temperature = 2
|
||||
var/weldvents = TRUE
|
||||
var/distcheck = TRUE
|
||||
|
||||
/datum/effect_system/smoke_spread/freezing/proc/Chilled(atom/A)
|
||||
if(isopenturf(A))
|
||||
var/turf/open/T = A
|
||||
if(T.air)
|
||||
var/datum/gas_mixture/G = T.air
|
||||
if(!distcheck || get_dist(T, location) < blast) // Otherwise we'll get silliness like people using Nanofrost to kill people through walls with cold air
|
||||
G.temperature = temperature
|
||||
T.air_update_turf()
|
||||
for(var/obj/effect/hotspot/H in T)
|
||||
qdel(H)
|
||||
var/list/G_gases = G.gases
|
||||
if(G_gases[/datum/gas/plasma])
|
||||
G_gases[/datum/gas/nitrogen] += (G_gases[/datum/gas/plasma])
|
||||
G_gases[/datum/gas/plasma] = 0
|
||||
GAS_GARBAGE_COLLECT(G.gases)
|
||||
if (weldvents)
|
||||
for(var/obj/machinery/atmospherics/components/unary/U in T)
|
||||
if(!isnull(U.welded) && !U.welded) //must be an unwelded vent pump or vent scrubber.
|
||||
U.welded = TRUE
|
||||
U.update_icon()
|
||||
U.visible_message("<span class='danger'>[U] was frozen shut!</span>")
|
||||
for(var/mob/living/L in T)
|
||||
L.ExtinguishMob()
|
||||
for(var/obj/item/Item in T)
|
||||
Item.extinguish()
|
||||
|
||||
/datum/effect_system/smoke_spread/freezing/set_up(radius = 5, loca, blast_radius = 0)
|
||||
..()
|
||||
blast = blast_radius
|
||||
|
||||
/datum/effect_system/smoke_spread/freezing/start()
|
||||
if(blast)
|
||||
for(var/turf/T in RANGE_TURFS(blast, location))
|
||||
Chilled(T)
|
||||
..()
|
||||
|
||||
/datum/effect_system/smoke_spread/freezing/decon
|
||||
temperature = 293.15
|
||||
distcheck = FALSE
|
||||
weldvents = FALSE
|
||||
|
||||
|
||||
/////////////////////////////////////////////
|
||||
// Sleep smoke
|
||||
/////////////////////////////////////////////
|
||||
|
||||
/obj/effect/particle_effect/smoke/sleeping
|
||||
color = "#9C3636"
|
||||
lifetime = 10
|
||||
|
||||
/obj/effect/particle_effect/smoke/sleeping/smoke_mob(mob/living/carbon/M)
|
||||
if(..())
|
||||
M.Sleeping(200)
|
||||
M.emote("cough")
|
||||
return 1
|
||||
|
||||
/datum/effect_system/smoke_spread/sleeping
|
||||
effect_type = /obj/effect/particle_effect/smoke/sleeping
|
||||
|
||||
/////////////////////////////////////////////
|
||||
// Chem smoke
|
||||
/////////////////////////////////////////////
|
||||
|
||||
/obj/effect/particle_effect/smoke/chem
|
||||
lifetime = 10
|
||||
|
||||
|
||||
/obj/effect/particle_effect/smoke/chem/process()
|
||||
if(..())
|
||||
var/turf/T = get_turf(src)
|
||||
var/fraction = 1/initial(lifetime)
|
||||
for(var/atom/movable/AM in T)
|
||||
if(AM.type == src.type)
|
||||
continue
|
||||
if(T.intact && AM.level == 1) //hidden under the floor
|
||||
continue
|
||||
reagents.reaction(AM, TOUCH, fraction)
|
||||
|
||||
reagents.reaction(T, TOUCH, fraction)
|
||||
return 1
|
||||
|
||||
/obj/effect/particle_effect/smoke/chem/smoke_mob(mob/living/carbon/M)
|
||||
if(lifetime<1)
|
||||
return 0
|
||||
if(!istype(M))
|
||||
return 0
|
||||
var/mob/living/carbon/C = M
|
||||
if(C.internal != null || C.has_smoke_protection())
|
||||
return 0
|
||||
var/fraction = 1/initial(lifetime)
|
||||
reagents.copy_to(C, fraction*reagents.total_volume)
|
||||
reagents.reaction(M, INGEST, fraction)
|
||||
return 1
|
||||
|
||||
|
||||
|
||||
/datum/effect_system/smoke_spread/chem
|
||||
var/obj/chemholder
|
||||
effect_type = /obj/effect/particle_effect/smoke/chem
|
||||
|
||||
/datum/effect_system/smoke_spread/chem/New()
|
||||
..()
|
||||
chemholder = new /obj()
|
||||
var/datum/reagents/R = new/datum/reagents(500)
|
||||
chemholder.reagents = R
|
||||
R.my_atom = chemholder
|
||||
|
||||
/datum/effect_system/smoke_spread/chem/Destroy()
|
||||
qdel(chemholder)
|
||||
chemholder = null
|
||||
return ..()
|
||||
|
||||
/datum/effect_system/smoke_spread/chem/set_up(datum/reagents/carry = null, radius = 1, loca, silent = FALSE)
|
||||
if(isturf(loca))
|
||||
location = loca
|
||||
else
|
||||
location = get_turf(loca)
|
||||
amount = radius
|
||||
carry.copy_to(chemholder, carry.total_volume)
|
||||
|
||||
if(!silent)
|
||||
var/contained = ""
|
||||
for(var/reagent in carry.reagent_list)
|
||||
contained += " [reagent] "
|
||||
if(contained)
|
||||
contained = "\[[contained]\]"
|
||||
|
||||
var/where = "[AREACOORD(location)]"
|
||||
if(carry.my_atom.fingerprintslast)
|
||||
var/mob/M = get_mob_by_key(carry.my_atom.fingerprintslast)
|
||||
var/more = ""
|
||||
if(M)
|
||||
more = "[ADMIN_LOOKUPFLW(M)] "
|
||||
message_admins("Smoke: ([ADMIN_VERBOSEJMP(location)])[contained]. Key: [more ? more : carry.my_atom.fingerprintslast].")
|
||||
log_game("A chemical smoke reaction has taken place in ([where])[contained]. Last touched by [carry.my_atom.fingerprintslast].")
|
||||
else
|
||||
message_admins("Smoke: ([ADMIN_VERBOSEJMP(location)])[contained]. No associated key.")
|
||||
log_game("A chemical smoke reaction has taken place in ([where])[contained]. No associated key.")
|
||||
|
||||
|
||||
/datum/effect_system/smoke_spread/chem/start()
|
||||
var/mixcolor = mix_color_from_reagents(chemholder.reagents.reagent_list)
|
||||
if(holder)
|
||||
location = get_turf(holder)
|
||||
var/obj/effect/particle_effect/smoke/chem/S = new effect_type(location)
|
||||
|
||||
if(chemholder.reagents.total_volume > 1) // can't split 1 very well
|
||||
chemholder.reagents.copy_to(S, chemholder.reagents.total_volume)
|
||||
|
||||
if(mixcolor)
|
||||
S.add_atom_colour(mixcolor, FIXED_COLOUR_PRIORITY) // give the smoke color, if it has any to begin with
|
||||
S.amount = amount
|
||||
if(S.amount)
|
||||
S.spread_smoke() //calling process right now so the smoke immediately attacks mobs.
|
||||
|
||||
|
||||
/////////////////////////////////////////////
|
||||
// Transparent smoke
|
||||
/////////////////////////////////////////////
|
||||
|
||||
//Same as the base type, but the smoke produced is not opaque
|
||||
/datum/effect_system/smoke_spread/transparent
|
||||
effect_type = /obj/effect/particle_effect/smoke/transparent
|
||||
|
||||
/obj/effect/particle_effect/smoke/transparent
|
||||
opaque = FALSE
|
||||
@@ -0,0 +1,65 @@
|
||||
/////////////////////////////////////////////
|
||||
//SPARK SYSTEM (like steam system)
|
||||
// The attach(atom/atom) proc is optional, and can be called to attach the effect
|
||||
// to something, like the RCD, so then you can just call start() and the sparks
|
||||
// will always spawn at the items location.
|
||||
/////////////////////////////////////////////
|
||||
|
||||
/proc/do_sparks(n, c, source)
|
||||
// n - number of sparks
|
||||
// c - cardinals, bool, do the sparks only move in cardinal directions?
|
||||
// source - source of the sparks.
|
||||
|
||||
var/datum/effect_system/spark_spread/sparks = new
|
||||
sparks.set_up(n, c, source)
|
||||
sparks.autocleanup = TRUE
|
||||
sparks.start()
|
||||
|
||||
|
||||
/obj/effect/particle_effect/sparks
|
||||
name = "sparks"
|
||||
icon_state = "sparks"
|
||||
anchored = TRUE
|
||||
light_power = 1.3
|
||||
light_range = MINIMUM_USEFUL_LIGHT_RANGE
|
||||
light_color = LIGHT_COLOR_FIRE
|
||||
|
||||
/obj/effect/particle_effect/sparks/Initialize()
|
||||
. = ..()
|
||||
flick(icon_state, src) // replay the animation
|
||||
playsound(src, "sparks", 100, TRUE)
|
||||
var/turf/T = loc
|
||||
if(isturf(T))
|
||||
T.hotspot_expose(700,5)
|
||||
QDEL_IN(src, 20)
|
||||
|
||||
/obj/effect/particle_effect/sparks/Destroy()
|
||||
var/turf/T = loc
|
||||
if(isturf(T))
|
||||
T.hotspot_expose(700,1)
|
||||
return ..()
|
||||
|
||||
/obj/effect/particle_effect/sparks/Move()
|
||||
..()
|
||||
var/turf/T = loc
|
||||
if(isturf(T))
|
||||
T.hotspot_expose(700,1)
|
||||
|
||||
/datum/effect_system/spark_spread
|
||||
effect_type = /obj/effect/particle_effect/sparks
|
||||
|
||||
/datum/effect_system/spark_spread/quantum
|
||||
effect_type = /obj/effect/particle_effect/sparks/quantum
|
||||
|
||||
//electricity
|
||||
|
||||
/obj/effect/particle_effect/sparks/electricity
|
||||
name = "lightning"
|
||||
icon_state = "electricity"
|
||||
|
||||
/obj/effect/particle_effect/sparks/quantum
|
||||
name = "quantum sparks"
|
||||
icon_state = "quantum_sparks"
|
||||
|
||||
/datum/effect_system/lightning_spread
|
||||
effect_type = /obj/effect/particle_effect/sparks/electricity
|
||||
@@ -0,0 +1,53 @@
|
||||
//WATER EFFECTS
|
||||
|
||||
/obj/effect/particle_effect/water
|
||||
name = "water"
|
||||
icon_state = "extinguish"
|
||||
var/life = 15
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
|
||||
|
||||
/obj/effect/particle_effect/water/Initialize()
|
||||
. = ..()
|
||||
QDEL_IN(src, 70)
|
||||
|
||||
/obj/effect/particle_effect/water/Move(turf/newloc)
|
||||
if (--src.life < 1)
|
||||
qdel(src)
|
||||
return 0
|
||||
if(newloc.density)
|
||||
return 0
|
||||
.=..()
|
||||
|
||||
/obj/effect/particle_effect/water/Bump(atom/A)
|
||||
if(reagents)
|
||||
reagents.reaction(A)
|
||||
return ..()
|
||||
|
||||
|
||||
/////////////////////////////////////////////
|
||||
// GENERIC STEAM SPREAD SYSTEM
|
||||
|
||||
//Usage: set_up(number of bits of steam, use North/South/East/West only, spawn location)
|
||||
// The attach(atom/atom) proc is optional, and can be called to attach the effect
|
||||
// to something, like a smoking beaker, so then you can just call start() and the steam
|
||||
// will always spawn at the items location, even if it's moved.
|
||||
|
||||
/* Example:
|
||||
var/datum/effect_system/steam_spread/steam = new /datum/effect_system/steam_spread() -- creates new system
|
||||
steam.set_up(5, 0, mob.loc) -- sets up variables
|
||||
OPTIONAL: steam.attach(mob)
|
||||
steam.start() -- spawns the effect
|
||||
*/
|
||||
/////////////////////////////////////////////
|
||||
/obj/effect/particle_effect/steam
|
||||
name = "steam"
|
||||
icon_state = "extinguish"
|
||||
density = FALSE
|
||||
|
||||
/obj/effect/particle_effect/steam/Initialize()
|
||||
. = ..()
|
||||
QDEL_IN(src, 20)
|
||||
|
||||
/datum/effect_system/steam_spread
|
||||
effect_type = /obj/effect/particle_effect/steam
|
||||
@@ -0,0 +1,64 @@
|
||||
|
||||
//objects in /obj/effect should never be things that are attackable, use obj/structure instead.
|
||||
//Effects are mostly temporary visual effects like sparks, smoke, as well as decals, etc...
|
||||
/obj/effect
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF | FREEZE_PROOF
|
||||
obj_flags = 0
|
||||
|
||||
/obj/effect/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir)
|
||||
return
|
||||
|
||||
/obj/effect/fire_act(exposed_temperature, exposed_volume)
|
||||
return
|
||||
|
||||
/obj/effect/acid_act()
|
||||
return
|
||||
|
||||
/obj/effect/mech_melee_attack(obj/mecha/M)
|
||||
return 0
|
||||
|
||||
/obj/effect/blob_act(obj/structure/blob/B)
|
||||
return
|
||||
|
||||
/obj/effect/attack_hulk(mob/living/carbon/human/user, does_attack_animation = 0)
|
||||
return 0
|
||||
|
||||
/obj/effect/experience_pressure_difference()
|
||||
return
|
||||
|
||||
/obj/effect/ex_act(severity, target)
|
||||
if(target == src)
|
||||
qdel(src)
|
||||
else
|
||||
switch(severity)
|
||||
if(1)
|
||||
qdel(src)
|
||||
if(2)
|
||||
if(prob(60))
|
||||
qdel(src)
|
||||
if(3)
|
||||
if(prob(25))
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/singularity_act()
|
||||
qdel(src)
|
||||
return 0
|
||||
|
||||
/obj/effect/ConveyorMove()
|
||||
return
|
||||
|
||||
/obj/effect/abstract/ex_act(severity, target)
|
||||
return
|
||||
|
||||
/obj/effect/abstract/singularity_pull()
|
||||
return
|
||||
|
||||
/obj/effect/abstract/singularity_act()
|
||||
return
|
||||
|
||||
/obj/effect/dummy/singularity_pull()
|
||||
return
|
||||
|
||||
/obj/effect/dummy/singularity_act()
|
||||
return
|
||||
@@ -0,0 +1,37 @@
|
||||
/obj/effect/forcefield
|
||||
desc = "A space wizard's magic wall."
|
||||
name = "FORCEWALL"
|
||||
icon_state = "m_shield"
|
||||
anchored = TRUE
|
||||
opacity = 0
|
||||
density = TRUE
|
||||
CanAtmosPass = ATMOS_PASS_DENSITY
|
||||
var/timeleft = 300 //Set to 0 for permanent forcefields (ugh)
|
||||
|
||||
/obj/effect/forcefield/Initialize()
|
||||
. = ..()
|
||||
if(timeleft)
|
||||
QDEL_IN(src, timeleft)
|
||||
|
||||
/obj/effect/forcefield/singularity_pull()
|
||||
return
|
||||
|
||||
/obj/effect/forcefield/cult
|
||||
desc = "An unholy shield that blocks all attacks."
|
||||
name = "glowing wall"
|
||||
icon = 'icons/effects/cult_effects.dmi'
|
||||
icon_state = "cultshield"
|
||||
CanAtmosPass = ATMOS_PASS_NO
|
||||
timeleft = 200
|
||||
|
||||
///////////Mimewalls///////////
|
||||
|
||||
/obj/effect/forcefield/mime
|
||||
icon_state = "nothing"
|
||||
name = "invisible wall"
|
||||
desc = "You have a bad feeling about this."
|
||||
|
||||
/obj/effect/forcefield/mime/advanced
|
||||
name = "invisible blockade"
|
||||
desc = "You're gonna be here awhile."
|
||||
timeleft = 600
|
||||
@@ -0,0 +1,177 @@
|
||||
//separate dm since hydro is getting bloated already
|
||||
|
||||
/obj/structure/glowshroom
|
||||
name = "glowshroom"
|
||||
desc = "Mycena Bregprox, a species of mushroom that glows in the dark."
|
||||
anchored = TRUE
|
||||
opacity = 0
|
||||
density = FALSE
|
||||
icon = 'icons/obj/lighting.dmi'
|
||||
icon_state = "glowshroom" //replaced in New
|
||||
layer = ABOVE_NORMAL_TURF_LAYER
|
||||
max_integrity = 5
|
||||
var/delay = 1200
|
||||
var/floor = 0
|
||||
var/generation = 1
|
||||
var/spreadIntoAdjacentChance = 60
|
||||
var/obj/item/seeds/myseed = /obj/item/seeds/glowshroom
|
||||
var/static/list/blacklisted_glowshroom_turfs = typecacheof(list(
|
||||
/turf/open/lava,
|
||||
/turf/open/floor/plating/beach/water))
|
||||
|
||||
/obj/structure/glowshroom/glowcap
|
||||
name = "glowcap"
|
||||
desc = "Mycena Ruthenia, a species of mushroom that, while it does glow in the dark, is not actually bioluminescent."
|
||||
icon_state = "glowcap"
|
||||
myseed = /obj/item/seeds/glowshroom/glowcap
|
||||
|
||||
/obj/structure/glowshroom/shadowshroom
|
||||
name = "shadowshroom"
|
||||
desc = "Mycena Umbra, a species of mushroom that emits shadow instead of light."
|
||||
icon_state = "shadowshroom"
|
||||
myseed = /obj/item/seeds/glowshroom/shadowshroom
|
||||
|
||||
/obj/structure/glowshroom/single/Spread()
|
||||
return
|
||||
|
||||
/obj/structure/glowshroom/examine(mob/user)
|
||||
. = ..()
|
||||
to_chat(user, "This is a [generation]\th generation [name]!")
|
||||
|
||||
/obj/structure/glowshroom/Destroy()
|
||||
if(myseed)
|
||||
QDEL_NULL(myseed)
|
||||
return ..()
|
||||
|
||||
/obj/structure/glowshroom/New(loc, obj/item/seeds/newseed, mutate_stats)
|
||||
..()
|
||||
if(newseed)
|
||||
myseed = newseed.Copy()
|
||||
myseed.forceMove(src)
|
||||
else
|
||||
myseed = new myseed(src)
|
||||
if(mutate_stats) //baby mushrooms have different stats :3
|
||||
myseed.adjust_potency(rand(-3,6))
|
||||
myseed.adjust_yield(rand(-1,2))
|
||||
myseed.adjust_production(rand(-3,6))
|
||||
myseed.adjust_endurance(rand(-3,6))
|
||||
delay = delay - myseed.production * 100 //So the delay goes DOWN with better stats instead of up. :I
|
||||
obj_integrity = myseed.endurance / 7
|
||||
max_integrity = myseed.endurance / 7
|
||||
var/datum/plant_gene/trait/glow/G = myseed.get_gene(/datum/plant_gene/trait/glow)
|
||||
if(ispath(G)) // Seeds were ported to initialize so their genes are still typepaths here, luckily their initializer is smart enough to handle us doing this
|
||||
myseed.genes -= G
|
||||
G = new G
|
||||
myseed.genes += G
|
||||
set_light(G.glow_range(myseed), G.glow_power(myseed), G.glow_color)
|
||||
setDir(CalcDir())
|
||||
var/base_icon_state = initial(icon_state)
|
||||
if(!floor)
|
||||
switch(dir) //offset to make it be on the wall rather than on the floor
|
||||
if(NORTH)
|
||||
pixel_y = 32
|
||||
if(SOUTH)
|
||||
pixel_y = -32
|
||||
if(EAST)
|
||||
pixel_x = 32
|
||||
if(WEST)
|
||||
pixel_x = -32
|
||||
icon_state = "[base_icon_state][rand(1,3)]"
|
||||
else //if on the floor, glowshroom on-floor sprite
|
||||
icon_state = base_icon_state
|
||||
|
||||
addtimer(CALLBACK(src, .proc/Spread), delay)
|
||||
|
||||
/obj/structure/glowshroom/proc/Spread()
|
||||
var/turf/ownturf = get_turf(src)
|
||||
var/shrooms_planted = 0
|
||||
for(var/i in 1 to myseed.yield)
|
||||
if(prob(1/(generation * generation) * 100))//This formula gives you diminishing returns based on generation. 100% with 1st gen, decreasing to 25%, 11%, 6, 4, 2...
|
||||
var/list/possibleLocs = list()
|
||||
var/spreadsIntoAdjacent = FALSE
|
||||
|
||||
if(prob(spreadIntoAdjacentChance))
|
||||
spreadsIntoAdjacent = TRUE
|
||||
|
||||
for(var/turf/open/floor/earth in view(3,src))
|
||||
if(is_type_in_typecache(earth, blacklisted_glowshroom_turfs))
|
||||
continue
|
||||
if(!disease_air_spread_walk(ownturf, earth))
|
||||
continue
|
||||
if(spreadsIntoAdjacent || !locate(/obj/structure/glowshroom) in view(1,earth))
|
||||
possibleLocs += earth
|
||||
CHECK_TICK
|
||||
|
||||
if(!possibleLocs.len)
|
||||
break
|
||||
|
||||
var/turf/newLoc = pick(possibleLocs)
|
||||
|
||||
var/shroomCount = 0 //hacky
|
||||
var/placeCount = 1
|
||||
for(var/obj/structure/glowshroom/shroom in newLoc)
|
||||
shroomCount++
|
||||
for(var/wallDir in GLOB.cardinals)
|
||||
var/turf/isWall = get_step(newLoc,wallDir)
|
||||
if(isWall.density)
|
||||
placeCount++
|
||||
if(shroomCount >= placeCount)
|
||||
continue
|
||||
|
||||
var/obj/structure/glowshroom/child = new type(newLoc, myseed, TRUE)
|
||||
child.generation = generation + 1
|
||||
shrooms_planted++
|
||||
|
||||
CHECK_TICK
|
||||
else
|
||||
shrooms_planted++ //if we failed due to generation, don't try to plant one later
|
||||
if(shrooms_planted < myseed.yield) //if we didn't get all possible shrooms planted, try again later
|
||||
myseed.yield -= shrooms_planted
|
||||
addtimer(CALLBACK(src, .proc/Spread), delay)
|
||||
|
||||
/obj/structure/glowshroom/proc/CalcDir(turf/location = loc)
|
||||
var/direction = 16
|
||||
|
||||
for(var/wallDir in GLOB.cardinals)
|
||||
var/turf/newTurf = get_step(location,wallDir)
|
||||
if(newTurf.density)
|
||||
direction |= wallDir
|
||||
|
||||
for(var/obj/structure/glowshroom/shroom in location)
|
||||
if(shroom == src)
|
||||
continue
|
||||
if(shroom.floor) //special
|
||||
direction &= ~16
|
||||
else
|
||||
direction &= ~shroom.dir
|
||||
|
||||
var/list/dirList = list()
|
||||
|
||||
for(var/i=1,i<=16,i <<= 1)
|
||||
if(direction & i)
|
||||
dirList += i
|
||||
|
||||
if(dirList.len)
|
||||
var/newDir = pick(dirList)
|
||||
if(newDir == 16)
|
||||
floor = 1
|
||||
newDir = 1
|
||||
return newDir
|
||||
|
||||
floor = 1
|
||||
return 1
|
||||
|
||||
/obj/structure/glowshroom/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
|
||||
if(damage_type == BURN && damage_amount)
|
||||
playsound(src.loc, 'sound/items/welder.ogg', 100, 1)
|
||||
|
||||
/obj/structure/glowshroom/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
|
||||
if(exposed_temperature > 300)
|
||||
take_damage(5, BURN, 0, 0)
|
||||
|
||||
/obj/structure/glowshroom/acid_act(acidpwr, acid_volume)
|
||||
. = 1
|
||||
visible_message("<span class='danger'>[src] melts away!</span>")
|
||||
var/obj/effect/decal/cleanable/molten_object/I = new (get_turf(src))
|
||||
I.desc = "Looks like this was \an [src] some time ago."
|
||||
qdel(src)
|
||||
@@ -0,0 +1,434 @@
|
||||
/obj/effect/landmark
|
||||
name = "landmark"
|
||||
icon = 'icons/effects/landmarks_static.dmi'
|
||||
icon_state = "x2"
|
||||
anchored = TRUE
|
||||
layer = MID_LANDMARK_LAYER
|
||||
invisibility = INVISIBILITY_ABSTRACT
|
||||
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
|
||||
|
||||
/obj/effect/landmark/singularity_act()
|
||||
return
|
||||
|
||||
// Please stop bombing the Observer-Start landmark.
|
||||
/obj/effect/landmark/ex_act()
|
||||
return
|
||||
|
||||
/obj/effect/landmark/singularity_pull()
|
||||
return
|
||||
|
||||
INITIALIZE_IMMEDIATE(/obj/effect/landmark)
|
||||
|
||||
/obj/effect/landmark/Initialize()
|
||||
. = ..()
|
||||
GLOB.landmarks_list += src
|
||||
|
||||
/obj/effect/landmark/Destroy()
|
||||
GLOB.landmarks_list -= src
|
||||
return ..()
|
||||
|
||||
/obj/effect/landmark/start
|
||||
name = "start"
|
||||
icon = 'icons/mob/landmarks.dmi'
|
||||
icon_state = "x"
|
||||
anchored = TRUE
|
||||
layer = MOB_LAYER
|
||||
var/jobspawn_override = FALSE
|
||||
var/delete_after_roundstart = TRUE
|
||||
var/used = FALSE
|
||||
|
||||
/obj/effect/landmark/start/proc/after_round_start()
|
||||
if(delete_after_roundstart)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/landmark/start/New()
|
||||
GLOB.start_landmarks_list += src
|
||||
if(jobspawn_override)
|
||||
if(!GLOB.jobspawn_overrides[name])
|
||||
GLOB.jobspawn_overrides[name] = list()
|
||||
GLOB.jobspawn_overrides[name] += src
|
||||
..()
|
||||
if(name != "start")
|
||||
tag = "start*[name]"
|
||||
|
||||
/obj/effect/landmark/start/Destroy()
|
||||
GLOB.start_landmarks_list -= src
|
||||
if(jobspawn_override)
|
||||
GLOB.jobspawn_overrides[name] -= src
|
||||
return ..()
|
||||
|
||||
// START LANDMARKS FOLLOW. Don't change the names unless
|
||||
// you are refactoring shitty landmark code.
|
||||
/obj/effect/landmark/start/assistant
|
||||
name = "Assistant"
|
||||
icon_state = "Assistant"
|
||||
|
||||
/obj/effect/landmark/start/assistant/override
|
||||
jobspawn_override = TRUE
|
||||
delete_after_roundstart = FALSE
|
||||
|
||||
/obj/effect/landmark/start/janitor
|
||||
name = "Janitor"
|
||||
icon_state = "Janitor"
|
||||
|
||||
/obj/effect/landmark/start/cargo_technician
|
||||
name = "Cargo Technician"
|
||||
icon_state = "Cargo Technician"
|
||||
|
||||
/obj/effect/landmark/start/bartender
|
||||
name = "Bartender"
|
||||
icon_state = "Bartender"
|
||||
|
||||
/obj/effect/landmark/start/clown
|
||||
name = "Clown"
|
||||
icon_state = "Clown"
|
||||
|
||||
/obj/effect/landmark/start/mime
|
||||
name = "Mime"
|
||||
icon_state = "Mime"
|
||||
|
||||
/obj/effect/landmark/start/quartermaster
|
||||
name = "Quartermaster"
|
||||
icon_state = "Quartermaster"
|
||||
|
||||
/obj/effect/landmark/start/atmospheric_technician
|
||||
name = "Atmospheric Technician"
|
||||
icon_state = "Atmospheric Technician"
|
||||
|
||||
/obj/effect/landmark/start/cook
|
||||
name = "Cook"
|
||||
icon_state = "Cook"
|
||||
|
||||
/obj/effect/landmark/start/shaft_miner
|
||||
name = "Shaft Miner"
|
||||
icon_state = "Shaft Miner"
|
||||
|
||||
/obj/effect/landmark/start/security_officer
|
||||
name = "Security Officer"
|
||||
icon_state = "Security Officer"
|
||||
|
||||
/obj/effect/landmark/start/botanist
|
||||
name = "Botanist"
|
||||
icon_state = "Botanist"
|
||||
|
||||
/obj/effect/landmark/start/head_of_security
|
||||
name = "Head of Security"
|
||||
icon_state = "Head of Security"
|
||||
|
||||
/obj/effect/landmark/start/captain
|
||||
name = "Captain"
|
||||
icon_state = "Captain"
|
||||
|
||||
/obj/effect/landmark/start/detective
|
||||
name = "Detective"
|
||||
icon_state = "Detective"
|
||||
|
||||
/obj/effect/landmark/start/warden
|
||||
name = "Warden"
|
||||
icon_state = "Warden"
|
||||
|
||||
/obj/effect/landmark/start/chief_engineer
|
||||
name = "Chief Engineer"
|
||||
icon_state = "Chief Engineer"
|
||||
|
||||
/obj/effect/landmark/start/head_of_personnel
|
||||
name = "Head of Personnel"
|
||||
icon_state = "Head of Personnel"
|
||||
|
||||
/obj/effect/landmark/start/librarian
|
||||
name = "Curator"
|
||||
icon_state = "Curator"
|
||||
|
||||
/obj/effect/landmark/start/lawyer
|
||||
name = "Lawyer"
|
||||
icon_state = "Lawyer"
|
||||
|
||||
/obj/effect/landmark/start/station_engineer
|
||||
name = "Station Engineer"
|
||||
icon_state = "Station Engineer"
|
||||
|
||||
/obj/effect/landmark/start/medical_doctor
|
||||
name = "Medical Doctor"
|
||||
icon_state = "Medical Doctor"
|
||||
|
||||
/obj/effect/landmark/start/scientist
|
||||
name = "Scientist"
|
||||
icon_state = "Scientist"
|
||||
|
||||
/obj/effect/landmark/start/chemist
|
||||
name = "Chemist"
|
||||
icon_state = "Chemist"
|
||||
|
||||
/obj/effect/landmark/start/roboticist
|
||||
name = "Roboticist"
|
||||
icon_state = "Roboticist"
|
||||
|
||||
/obj/effect/landmark/start/research_director
|
||||
name = "Research Director"
|
||||
icon_state = "Research Director"
|
||||
|
||||
/obj/effect/landmark/start/geneticist
|
||||
name = "Geneticist"
|
||||
icon_state = "Geneticist"
|
||||
|
||||
/obj/effect/landmark/start/chief_medical_officer
|
||||
name = "Chief Medical Officer"
|
||||
icon_state = "Chief Medical Officer"
|
||||
|
||||
/obj/effect/landmark/start/virologist
|
||||
name = "Virologist"
|
||||
icon_state = "Virologist"
|
||||
|
||||
/obj/effect/landmark/start/chaplain
|
||||
name = "Chaplain"
|
||||
icon_state = "Chaplain"
|
||||
|
||||
/obj/effect/landmark/start/cyborg
|
||||
name = "Cyborg"
|
||||
icon_state = "Cyborg"
|
||||
|
||||
/obj/effect/landmark/start/ai
|
||||
name = "AI"
|
||||
icon_state = "AI"
|
||||
delete_after_roundstart = FALSE
|
||||
var/primary_ai = TRUE
|
||||
var/latejoin_active = TRUE
|
||||
|
||||
/obj/effect/landmark/start/ai/after_round_start()
|
||||
if(latejoin_active && !used)
|
||||
new /obj/structure/AIcore/latejoin_inactive(loc)
|
||||
return ..()
|
||||
|
||||
/obj/effect/landmark/start/ai/secondary
|
||||
icon = 'icons/effects/landmarks_static.dmi'
|
||||
icon_state = "ai_spawn"
|
||||
primary_ai = FALSE
|
||||
latejoin_active = FALSE
|
||||
|
||||
//Department Security spawns
|
||||
|
||||
/obj/effect/landmark/start/depsec
|
||||
name = "department_sec"
|
||||
icon_state = "Security Officer"
|
||||
|
||||
/obj/effect/landmark/start/depsec/New()
|
||||
..()
|
||||
GLOB.department_security_spawns += src
|
||||
|
||||
/obj/effect/landmark/start/depsec/Destroy()
|
||||
GLOB.department_security_spawns -= src
|
||||
return ..()
|
||||
|
||||
/obj/effect/landmark/start/depsec/supply
|
||||
name = "supply_sec"
|
||||
|
||||
/obj/effect/landmark/start/depsec/medical
|
||||
name = "medical_sec"
|
||||
|
||||
/obj/effect/landmark/start/depsec/engineering
|
||||
name = "engineering_sec"
|
||||
|
||||
/obj/effect/landmark/start/depsec/science
|
||||
name = "science_sec"
|
||||
|
||||
/obj/effect/landmark/start/wizard
|
||||
name = "wizard"
|
||||
icon = 'icons/effects/landmarks_static.dmi'
|
||||
icon_state = "wiznerd_spawn"
|
||||
|
||||
/obj/effect/landmark/start/wizard/Initialize()
|
||||
..()
|
||||
GLOB.wizardstart += loc
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
/obj/effect/landmark/start/nukeop
|
||||
name = "nukeop"
|
||||
icon = 'icons/effects/landmarks_static.dmi'
|
||||
icon_state = "snukeop_spawn"
|
||||
|
||||
/obj/effect/landmark/start/nukeop/Initialize()
|
||||
..()
|
||||
GLOB.nukeop_start += loc
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
/obj/effect/landmark/start/nukeop_leader
|
||||
name = "nukeop leader"
|
||||
icon = 'icons/effects/landmarks_static.dmi'
|
||||
icon_state = "snukeop_leader_spawn"
|
||||
|
||||
/obj/effect/landmark/start/nukeop_leader/Initialize()
|
||||
..()
|
||||
GLOB.nukeop_leader_start += loc
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
// Must be immediate because players will
|
||||
// join before SSatom initializes everything.
|
||||
INITIALIZE_IMMEDIATE(/obj/effect/landmark/start/new_player)
|
||||
|
||||
/obj/effect/landmark/start/new_player
|
||||
name = "New Player"
|
||||
|
||||
/obj/effect/landmark/start/new_player/Initialize()
|
||||
..()
|
||||
GLOB.newplayer_start += loc
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
/obj/effect/landmark/latejoin
|
||||
name = "JoinLate"
|
||||
|
||||
/obj/effect/landmark/latejoin/Initialize(mapload)
|
||||
..()
|
||||
SSjob.latejoin_trackers += loc
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
// carp.
|
||||
/obj/effect/landmark/carpspawn
|
||||
name = "carpspawn"
|
||||
icon_state = "carp_spawn"
|
||||
|
||||
// observer-start.
|
||||
/obj/effect/landmark/observer_start
|
||||
name = "Observer-Start"
|
||||
icon_state = "observer_start"
|
||||
|
||||
// xenos.
|
||||
/obj/effect/landmark/xeno_spawn
|
||||
name = "xeno_spawn"
|
||||
icon_state = "xeno_spawn"
|
||||
|
||||
/obj/effect/landmark/xeno_spawn/Initialize(mapload)
|
||||
..()
|
||||
GLOB.xeno_spawn += loc
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
// blobs.
|
||||
/obj/effect/landmark/blobstart
|
||||
name = "blobstart"
|
||||
icon_state = "blob_start"
|
||||
|
||||
/obj/effect/landmark/blobstart/Initialize(mapload)
|
||||
..()
|
||||
GLOB.blobstart += loc
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
/obj/effect/landmark/secequipment
|
||||
name = "secequipment"
|
||||
icon_state = "secequipment"
|
||||
|
||||
/obj/effect/landmark/secequipment/Initialize(mapload)
|
||||
..()
|
||||
GLOB.secequipment += loc
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
/obj/effect/landmark/prisonwarp
|
||||
name = "prisonwarp"
|
||||
icon_state = "prisonwarp"
|
||||
|
||||
/obj/effect/landmark/prisonwarp/Initialize(mapload)
|
||||
..()
|
||||
GLOB.prisonwarp += loc
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
/obj/effect/landmark/ert_spawn
|
||||
name = "Emergencyresponseteam"
|
||||
icon_state = "ert_spawn"
|
||||
|
||||
/obj/effect/landmark/ert_spawn/Initialize(mapload)
|
||||
..()
|
||||
GLOB.emergencyresponseteamspawn += loc
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
/obj/effect/landmark/holding_facility
|
||||
name = "Holding Facility"
|
||||
icon_state = "holding_facility"
|
||||
|
||||
/obj/effect/landmark/holding_facility/Initialize(mapload)
|
||||
..()
|
||||
GLOB.holdingfacility += loc
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
/obj/effect/landmark/thunderdome/observe
|
||||
name = "tdomeobserve"
|
||||
icon_state = "tdome_observer"
|
||||
|
||||
/obj/effect/landmark/thunderdome/observe/Initialize(mapload)
|
||||
..()
|
||||
GLOB.tdomeobserve += loc
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
/obj/effect/landmark/thunderdome/one
|
||||
name = "tdome1"
|
||||
icon_state = "tdome_t1"
|
||||
|
||||
/obj/effect/landmark/thunderdome/one/Initialize(mapload)
|
||||
..()
|
||||
GLOB.tdome1 += loc
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
/obj/effect/landmark/thunderdome/two
|
||||
name = "tdome2"
|
||||
icon_state = "tdome_t2"
|
||||
|
||||
/obj/effect/landmark/thunderdome/two/Initialize(mapload)
|
||||
..()
|
||||
GLOB.tdome2 += loc
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
/obj/effect/landmark/thunderdome/admin
|
||||
name = "tdomeadmin"
|
||||
icon_state = "tdome_admin"
|
||||
|
||||
/obj/effect/landmark/thunderdome/admin/Initialize(mapload)
|
||||
..()
|
||||
GLOB.tdomeadmin += loc
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
//Servant spawn locations
|
||||
/obj/effect/landmark/servant_of_ratvar
|
||||
name = "servant of ratvar spawn"
|
||||
icon_state = "clockwork_orange"
|
||||
layer = MOB_LAYER
|
||||
|
||||
/obj/effect/landmark/servant_of_ratvar/Initialize(mapload)
|
||||
..()
|
||||
GLOB.servant_spawns += loc
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
//City of Cogs entrances
|
||||
/obj/effect/landmark/city_of_cogs
|
||||
name = "city of cogs entrance"
|
||||
icon_state = "city_of_cogs"
|
||||
|
||||
/obj/effect/landmark/city_of_cogs/Initialize(mapload)
|
||||
..()
|
||||
GLOB.city_of_cogs_spawns += loc
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
//generic event spawns
|
||||
/obj/effect/landmark/event_spawn
|
||||
name = "generic event spawn"
|
||||
icon_state = "generic_event"
|
||||
layer = HIGH_LANDMARK_LAYER
|
||||
|
||||
|
||||
/obj/effect/landmark/event_spawn/New()
|
||||
..()
|
||||
GLOB.generic_event_spawns += src
|
||||
|
||||
/obj/effect/landmark/event_spawn/Destroy()
|
||||
GLOB.generic_event_spawns -= src
|
||||
return ..()
|
||||
|
||||
/obj/effect/landmark/ruin
|
||||
var/datum/map_template/ruin/ruin_template
|
||||
|
||||
/obj/effect/landmark/ruin/New(loc, my_ruin_template)
|
||||
name = "ruin_[GLOB.ruin_landmarks.len + 1]"
|
||||
..(loc)
|
||||
ruin_template = my_ruin_template
|
||||
GLOB.ruin_landmarks |= src
|
||||
|
||||
/obj/effect/landmark/ruin/Destroy()
|
||||
GLOB.ruin_landmarks -= src
|
||||
ruin_template = null
|
||||
. = ..()
|
||||
@@ -0,0 +1,176 @@
|
||||
/obj/effect/mine
|
||||
name = "dummy mine"
|
||||
desc = "Better stay away from that thing."
|
||||
density = FALSE
|
||||
anchored = TRUE
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "uglymine"
|
||||
var/triggered = 0
|
||||
|
||||
/obj/effect/mine/proc/mineEffect(mob/victim)
|
||||
to_chat(victim, "<span class='danger'>*click*</span>")
|
||||
|
||||
/obj/effect/mine/Crossed(AM as mob|obj)
|
||||
if(isturf(loc))
|
||||
if(ismob(AM))
|
||||
var/mob/MM = AM
|
||||
if(!(MM.movement_type & FLYING))
|
||||
triggermine(AM)
|
||||
else
|
||||
triggermine(AM)
|
||||
|
||||
/obj/effect/mine/proc/triggermine(mob/victim)
|
||||
if(triggered)
|
||||
return
|
||||
visible_message("<span class='danger'>[victim] sets off [icon2html(src, viewers(src))] [src]!</span>")
|
||||
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
|
||||
s.set_up(3, 1, src)
|
||||
s.start()
|
||||
mineEffect(victim)
|
||||
triggered = 1
|
||||
qdel(src)
|
||||
|
||||
|
||||
/obj/effect/mine/explosive
|
||||
name = "explosive mine"
|
||||
var/range_devastation = 0
|
||||
var/range_heavy = 1
|
||||
var/range_light = 2
|
||||
var/range_flash = 3
|
||||
|
||||
/obj/effect/mine/explosive/mineEffect(mob/victim)
|
||||
explosion(loc, range_devastation, range_heavy, range_light, range_flash)
|
||||
|
||||
|
||||
/obj/effect/mine/stun
|
||||
name = "stun mine"
|
||||
var/stun_time = 80
|
||||
|
||||
/obj/effect/mine/stun/mineEffect(mob/living/victim)
|
||||
if(isliving(victim))
|
||||
victim.Knockdown(stun_time)
|
||||
|
||||
/obj/effect/mine/kickmine
|
||||
name = "kick mine"
|
||||
|
||||
/obj/effect/mine/kickmine/mineEffect(mob/victim)
|
||||
if(isliving(victim) && victim.client)
|
||||
to_chat(victim, "<span class='userdanger'>You have been kicked FOR NO REISIN!</span>")
|
||||
qdel(victim.client)
|
||||
|
||||
|
||||
/obj/effect/mine/gas
|
||||
name = "oxygen mine"
|
||||
var/gas_amount = 360
|
||||
var/gas_type = "o2"
|
||||
|
||||
/obj/effect/mine/gas/mineEffect(mob/victim)
|
||||
atmos_spawn_air("[gas_type]=[gas_amount]")
|
||||
|
||||
|
||||
/obj/effect/mine/gas/plasma
|
||||
name = "plasma mine"
|
||||
gas_type = "plasma"
|
||||
|
||||
|
||||
/obj/effect/mine/gas/n2o
|
||||
name = "\improper N2O mine"
|
||||
gas_type = "n2o"
|
||||
|
||||
|
||||
/obj/effect/mine/sound
|
||||
name = "honkblaster 1000"
|
||||
var/sound = 'sound/items/bikehorn.ogg'
|
||||
|
||||
/obj/effect/mine/sound/mineEffect(mob/victim)
|
||||
playsound(loc, sound, 100, 1)
|
||||
|
||||
|
||||
/obj/effect/mine/sound/bwoink
|
||||
name = "bwoink mine"
|
||||
sound = 'sound/effects/adminhelp.ogg'
|
||||
|
||||
/obj/effect/mine/pickup
|
||||
name = "pickup"
|
||||
desc = "pick me up"
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
icon_state = "electricity2"
|
||||
density = FALSE
|
||||
var/duration = 0
|
||||
|
||||
/obj/effect/mine/pickup/Initialize()
|
||||
. = ..()
|
||||
animate(src, pixel_y = 4, time = 20, loop = -1)
|
||||
|
||||
/obj/effect/mine/pickup/triggermine(mob/victim)
|
||||
if(triggered)
|
||||
return
|
||||
triggered = 1
|
||||
invisibility = INVISIBILITY_ABSTRACT
|
||||
mineEffect(victim)
|
||||
qdel(src)
|
||||
|
||||
|
||||
/obj/effect/mine/pickup/bloodbath
|
||||
name = "Red Orb"
|
||||
desc = "You feel angry just looking at it."
|
||||
duration = 1200 //2min
|
||||
color = "#FF0000"
|
||||
|
||||
/obj/effect/mine/pickup/bloodbath/mineEffect(mob/living/carbon/victim)
|
||||
if(!victim.client || !istype(victim))
|
||||
return
|
||||
to_chat(victim, "<span class='reallybig redtext'>RIP AND TEAR</span>")
|
||||
var/old_color = victim.client.color
|
||||
var/static/list/red_splash = list(1,0,0,0.8,0.2,0, 0.8,0,0.2,0.1,0,0)
|
||||
var/static/list/pure_red = list(0,0,0,0,0,0,0,0,0,1,0,0)
|
||||
|
||||
spawn(0)
|
||||
new /datum/hallucination/delusion(victim, TRUE, "demon",duration,0)
|
||||
|
||||
var/obj/item/twohanded/required/chainsaw/doomslayer/chainsaw = new(victim.loc)
|
||||
victim.log_message("entered a blood frenzy", LOG_ATTACK)
|
||||
|
||||
ADD_TRAIT(chainsaw, TRAIT_NODROP, CHAINSAW_FRENZY_TRAIT)
|
||||
victim.drop_all_held_items()
|
||||
victim.put_in_hands(chainsaw, forced = TRUE)
|
||||
chainsaw.attack_self(victim)
|
||||
chainsaw.wield(victim)
|
||||
victim.reagents.add_reagent("adminordrazine",25)
|
||||
to_chat(victim, "<span class='warning'>KILL, KILL, KILL! YOU HAVE NO ALLIES ANYMORE, KILL THEM ALL!</span>")
|
||||
|
||||
victim.client.color = pure_red
|
||||
animate(victim.client,color = red_splash, time = 10, easing = SINE_EASING|EASE_OUT)
|
||||
sleep(10)
|
||||
animate(victim.client,color = old_color, time = duration)//, easing = SINE_EASING|EASE_OUT)
|
||||
sleep(duration)
|
||||
to_chat(victim, "<span class='notice'>Your bloodlust seeps back into the bog of your subconscious and you regain self control.</span>")
|
||||
qdel(chainsaw)
|
||||
victim.log_message("exited a blood frenzy", LOG_ATTACK)
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/mine/pickup/healing
|
||||
name = "Blue Orb"
|
||||
desc = "You feel better just looking at it."
|
||||
color = "#0000FF"
|
||||
|
||||
/obj/effect/mine/pickup/healing/mineEffect(mob/living/carbon/victim)
|
||||
if(!victim.client || !istype(victim))
|
||||
return
|
||||
to_chat(victim, "<span class='notice'>You feel great!</span>")
|
||||
victim.revive(full_heal = 1, admin_revive = 1)
|
||||
|
||||
/obj/effect/mine/pickup/speed
|
||||
name = "Yellow Orb"
|
||||
desc = "You feel faster just looking at it."
|
||||
color = "#FFFF00"
|
||||
duration = 300
|
||||
|
||||
/obj/effect/mine/pickup/speed/mineEffect(mob/living/carbon/victim)
|
||||
if(!victim.client || !istype(victim))
|
||||
return
|
||||
to_chat(victim, "<span class='notice'>You feel fast!</span>")
|
||||
ADD_TRAIT(victim, TRAIT_GOTTAGOREALLYFAST, "yellow_orb")
|
||||
sleep(duration)
|
||||
REMOVE_TRAIT(victim, TRAIT_GOTTAGOREALLYFAST, "yellow_orb")
|
||||
to_chat(victim, "<span class='notice'>You slow down.</span>")
|
||||
@@ -0,0 +1,94 @@
|
||||
//The effect when you wrap a dead body in gift wrap
|
||||
/obj/effect/spresent
|
||||
name = "strange present"
|
||||
desc = "It's a ... present?"
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "strangepresent"
|
||||
density = TRUE
|
||||
anchored = FALSE
|
||||
|
||||
/obj/effect/beam
|
||||
name = "beam"
|
||||
var/def_zone
|
||||
pass_flags = PASSTABLE
|
||||
|
||||
/obj/effect/beam/singularity_act()
|
||||
return
|
||||
|
||||
/obj/effect/beam/singularity_pull()
|
||||
return
|
||||
|
||||
/obj/effect/spawner
|
||||
name = "object spawner"
|
||||
|
||||
/obj/effect/list_container
|
||||
name = "list container"
|
||||
|
||||
/obj/effect/list_container/mobl
|
||||
name = "mobl"
|
||||
var/master = null
|
||||
|
||||
var/list/container = list( )
|
||||
|
||||
/obj/effect/overlay/thermite
|
||||
name = "thermite"
|
||||
desc = "Looks hot."
|
||||
icon = 'icons/effects/fire.dmi'
|
||||
icon_state = "2" //what?
|
||||
anchored = TRUE
|
||||
opacity = TRUE
|
||||
density = TRUE
|
||||
layer = FLY_LAYER
|
||||
|
||||
/obj/effect/supplypod_selector
|
||||
icon_state = "supplypod_selector"
|
||||
layer = FLY_LAYER
|
||||
|
||||
//Makes a tile fully lit no matter what
|
||||
/obj/effect/fullbright
|
||||
icon = 'icons/effects/alphacolors.dmi'
|
||||
icon_state = "white"
|
||||
plane = LIGHTING_PLANE
|
||||
layer = LIGHTING_LAYER
|
||||
blend_mode = BLEND_ADD
|
||||
|
||||
/obj/effect/abstract/marker
|
||||
name = "marker"
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
anchored = TRUE
|
||||
icon_state = "wave3"
|
||||
layer = RIPPLE_LAYER
|
||||
|
||||
/obj/effect/abstract/marker/Initialize(mapload)
|
||||
. = ..()
|
||||
GLOB.all_abstract_markers += src
|
||||
|
||||
/obj/effect/abstract/marker/Destroy()
|
||||
GLOB.all_abstract_markers -= src
|
||||
. = ..()
|
||||
|
||||
/obj/effect/abstract/marker/at
|
||||
name = "active turf marker"
|
||||
|
||||
|
||||
/obj/effect/dummy/lighting_obj
|
||||
name = "lighting fx obj"
|
||||
desc = "Tell a coder if you're seeing this."
|
||||
icon_state = "nothing"
|
||||
light_color = "#FFFFFF"
|
||||
light_range = MINIMUM_USEFUL_LIGHT_RANGE
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
|
||||
/obj/effect/dummy/lighting_obj/Initialize(mapload, _color, _range, _power, _duration)
|
||||
. = ..()
|
||||
set_light(_range ? _range : light_range, _power ? _power : light_power, _color ? _color : light_color)
|
||||
if(_duration)
|
||||
QDEL_IN(src, _duration)
|
||||
|
||||
/obj/effect/dummy/lighting_obj/moblight
|
||||
name = "mob lighting fx"
|
||||
|
||||
/obj/effect/dummy/lighting_obj/moblight/Initialize(mapload, _color, _range, _power, _duration)
|
||||
. = ..()
|
||||
if(!ismob(loc))
|
||||
return INITIALIZE_HINT_QDEL
|
||||
@@ -0,0 +1,53 @@
|
||||
/obj/effect/overlay
|
||||
name = "overlay"
|
||||
|
||||
/obj/effect/overlay/singularity_act()
|
||||
return
|
||||
|
||||
/obj/effect/overlay/singularity_pull()
|
||||
return
|
||||
|
||||
/obj/effect/overlay/beam//Not actually a projectile, just an effect.
|
||||
name="beam"
|
||||
icon='icons/effects/beam.dmi'
|
||||
icon_state="b_beam"
|
||||
var/atom/BeamSource
|
||||
|
||||
/obj/effect/overlay/beam/Initialize()
|
||||
. = ..()
|
||||
QDEL_IN(src, 10)
|
||||
|
||||
/obj/effect/overlay/palmtree_r
|
||||
name = "palm tree"
|
||||
icon = 'icons/misc/beach2.dmi'
|
||||
icon_state = "palm1"
|
||||
density = TRUE
|
||||
layer = WALL_OBJ_LAYER
|
||||
anchored = TRUE
|
||||
|
||||
/obj/effect/overlay/palmtree_l
|
||||
name = "palm tree"
|
||||
icon = 'icons/misc/beach2.dmi'
|
||||
icon_state = "palm2"
|
||||
density = TRUE
|
||||
layer = WALL_OBJ_LAYER
|
||||
anchored = TRUE
|
||||
|
||||
/obj/effect/overlay/coconut
|
||||
gender = PLURAL
|
||||
name = "coconuts"
|
||||
icon = 'icons/misc/beach.dmi'
|
||||
icon_state = "coconuts"
|
||||
|
||||
/obj/effect/overlay/sparkles
|
||||
gender = PLURAL
|
||||
name = "sparkles"
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
icon_state = "shieldsparkles"
|
||||
anchored = TRUE
|
||||
|
||||
/obj/effect/overlay/vis
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
anchored = TRUE
|
||||
var/unused = 0 //When detected to be unused it gets set to world.time, after a while it gets removed
|
||||
var/cache_expiration = 2 MINUTES // overlays which go unused for 2 minutes get cleaned up
|
||||
@@ -0,0 +1,185 @@
|
||||
|
||||
/proc/create_portal_pair(turf/source, turf/destination, _creator = null, _lifespan = 300, accuracy = 0, newtype = /obj/effect/portal, atmos_link_override)
|
||||
if(!istype(source) || !istype(destination))
|
||||
return
|
||||
var/turf/actual_destination = get_teleport_turf(destination, accuracy)
|
||||
var/obj/effect/portal/P1 = new newtype(source, _creator, _lifespan, null, FALSE, null, atmos_link_override)
|
||||
var/obj/effect/portal/P2 = new newtype(actual_destination, _creator, _lifespan, P1, TRUE, null, atmos_link_override)
|
||||
if(!istype(P1)||!istype(P2))
|
||||
return
|
||||
P1.link_portal(P2)
|
||||
P1.hardlinked = TRUE
|
||||
return list(P1, P2)
|
||||
|
||||
/obj/effect/portal
|
||||
name = "portal"
|
||||
desc = "Looks unstable. Best to test it with the clown."
|
||||
icon = 'icons/obj/stationobjs.dmi'
|
||||
icon_state = "portal"
|
||||
anchored = TRUE
|
||||
var/mech_sized = FALSE
|
||||
var/obj/effect/portal/linked
|
||||
var/hardlinked = TRUE //Requires a linked portal at all times. Destroy if there's no linked portal, if there is destroy it when this one is deleted.
|
||||
var/teleport_channel = TELEPORT_CHANNEL_BLUESPACE
|
||||
var/creator
|
||||
var/turf/hard_target //For when a portal needs a hard target and isn't to be linked.
|
||||
var/atmos_link = FALSE //Link source/destination atmos.
|
||||
var/turf/open/atmos_source //Atmos link source
|
||||
var/turf/open/atmos_destination //Atmos link destination
|
||||
var/allow_anchored = FALSE
|
||||
var/innate_accuracy_penalty = 0
|
||||
var/last_effect = 0
|
||||
|
||||
/obj/effect/portal/anom
|
||||
name = "wormhole"
|
||||
icon = 'icons/obj/objects.dmi'
|
||||
icon_state = "anom"
|
||||
mech_sized = TRUE
|
||||
teleport_channel = TELEPORT_CHANNEL_WORMHOLE
|
||||
|
||||
/obj/effect/portal/Move(newloc)
|
||||
for(var/T in newloc)
|
||||
if(istype(T, /obj/effect/portal))
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/obj/effect/portal/attackby(obj/item/W, mob/user, params)
|
||||
if(user && Adjacent(user))
|
||||
user.forceMove(get_turf(src))
|
||||
return TRUE
|
||||
|
||||
/obj/effect/portal/Crossed(atom/movable/AM, oldloc)
|
||||
if(isobserver(AM))
|
||||
return ..()
|
||||
if(linked && (get_turf(oldloc) == get_turf(linked)))
|
||||
return ..()
|
||||
if(!teleport(AM))
|
||||
return ..()
|
||||
|
||||
/obj/effect/portal/attack_tk(mob/user)
|
||||
return
|
||||
|
||||
/obj/effect/portal/attack_hand(mob/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(get_turf(user) == get_turf(src))
|
||||
teleport(user)
|
||||
if(Adjacent(user))
|
||||
user.forceMove(get_turf(src))
|
||||
|
||||
/obj/effect/portal/Initialize(mapload, _creator, _lifespan = 0, obj/effect/portal/_linked, automatic_link = FALSE, turf/hard_target_override, atmos_link_override)
|
||||
. = ..()
|
||||
GLOB.portals += src
|
||||
if(!istype(_linked) && automatic_link)
|
||||
. = INITIALIZE_HINT_QDEL
|
||||
CRASH("Somebody fucked up.")
|
||||
if(_lifespan > 0)
|
||||
QDEL_IN(src, _lifespan)
|
||||
if(!isnull(atmos_link_override))
|
||||
atmos_link = atmos_link_override
|
||||
link_portal(_linked)
|
||||
hardlinked = automatic_link
|
||||
creator = _creator
|
||||
if(isturf(hard_target_override))
|
||||
hard_target = hard_target_override
|
||||
|
||||
/obj/effect/portal/singularity_pull()
|
||||
return
|
||||
|
||||
/obj/effect/portal/singularity_act()
|
||||
return
|
||||
|
||||
/obj/effect/portal/proc/link_portal(obj/effect/portal/newlink)
|
||||
linked = newlink
|
||||
if(atmos_link)
|
||||
link_atmos()
|
||||
|
||||
/obj/effect/portal/proc/link_atmos()
|
||||
if(atmos_source || atmos_destination)
|
||||
unlink_atmos()
|
||||
if(!isopenturf(get_turf(src)))
|
||||
return FALSE
|
||||
if(linked)
|
||||
if(isopenturf(get_turf(linked)))
|
||||
atmos_source = get_turf(src)
|
||||
atmos_destination = get_turf(linked)
|
||||
else if(hard_target)
|
||||
if(isopenturf(hard_target))
|
||||
atmos_source = get_turf(src)
|
||||
atmos_destination = hard_target
|
||||
else
|
||||
return FALSE
|
||||
if(!istype(atmos_source) || !istype(atmos_destination))
|
||||
return FALSE
|
||||
LAZYINITLIST(atmos_source.atmos_adjacent_turfs)
|
||||
LAZYINITLIST(atmos_destination.atmos_adjacent_turfs)
|
||||
if(atmos_source.atmos_adjacent_turfs[atmos_destination] || atmos_destination.atmos_adjacent_turfs[atmos_source]) //Already linked!
|
||||
return FALSE
|
||||
atmos_source.atmos_adjacent_turfs[atmos_destination] = TRUE
|
||||
atmos_destination.atmos_adjacent_turfs[atmos_source] = TRUE
|
||||
atmos_source.air_update_turf(FALSE)
|
||||
atmos_destination.air_update_turf(FALSE)
|
||||
|
||||
/obj/effect/portal/proc/unlink_atmos()
|
||||
if(istype(atmos_source))
|
||||
if(istype(atmos_destination) && !atmos_source.Adjacent(atmos_destination) && !CANATMOSPASS(atmos_destination, atmos_source))
|
||||
LAZYREMOVE(atmos_source.atmos_adjacent_turfs, atmos_destination)
|
||||
atmos_source = null
|
||||
if(istype(atmos_destination))
|
||||
if(istype(atmos_source) && !atmos_destination.Adjacent(atmos_source) && !CANATMOSPASS(atmos_source, atmos_destination))
|
||||
LAZYREMOVE(atmos_destination.atmos_adjacent_turfs, atmos_source)
|
||||
atmos_destination = null
|
||||
|
||||
/obj/effect/portal/Destroy() //Calls on_portal_destroy(destroyed portal, location of destroyed portal) on creator if creator has such call.
|
||||
if(creator && hascall(creator, "on_portal_destroy"))
|
||||
call(creator, "on_portal_destroy")(src, src.loc)
|
||||
creator = null
|
||||
GLOB.portals -= src
|
||||
unlink_atmos()
|
||||
if(hardlinked && !QDELETED(linked))
|
||||
QDEL_NULL(linked)
|
||||
else
|
||||
linked = null
|
||||
return ..()
|
||||
|
||||
/obj/effect/portal/attack_ghost(mob/dead/observer/O)
|
||||
if(!teleport(O, TRUE))
|
||||
return ..()
|
||||
|
||||
/obj/effect/portal/proc/teleport(atom/movable/M, force = FALSE)
|
||||
if(!force && (!istype(M) || iseffect(M) || (ismecha(M) && !mech_sized) || (!isobj(M) && !ismob(M)))) //Things that shouldn't teleport.
|
||||
return
|
||||
var/turf/real_target = get_link_target_turf()
|
||||
if(!istype(real_target))
|
||||
return FALSE
|
||||
if(!force && (!ismecha(M) && !istype(M, /obj/item/projectile) && M.anchored && !allow_anchored))
|
||||
return
|
||||
if(ismegafauna(M))
|
||||
message_admins("[M] has used a portal at [ADMIN_VERBOSEJMP(src)] made by [usr].")
|
||||
var/no_effect = FALSE
|
||||
if(last_effect == world.time)
|
||||
no_effect = TRUE
|
||||
else
|
||||
last_effect = world.time
|
||||
if(do_teleport(M, real_target, innate_accuracy_penalty, no_effects = no_effect, channel = teleport_channel))
|
||||
if(istype(M, /obj/item/projectile))
|
||||
var/obj/item/projectile/P = M
|
||||
P.ignore_source_check = TRUE
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/effect/portal/proc/get_link_target_turf()
|
||||
var/turf/real_target
|
||||
if(!istype(linked) || QDELETED(linked))
|
||||
if(hardlinked)
|
||||
qdel(src)
|
||||
if(!istype(hard_target) || QDELETED(hard_target))
|
||||
hard_target = null
|
||||
return
|
||||
else
|
||||
real_target = hard_target
|
||||
linked = null
|
||||
else
|
||||
real_target = get_turf(linked)
|
||||
return real_target
|
||||
@@ -0,0 +1,112 @@
|
||||
/datum/proximity_monitor
|
||||
var/atom/host //the atom we are tracking
|
||||
var/atom/hasprox_receiver //the atom that will receive HasProximity calls.
|
||||
var/atom/last_host_loc
|
||||
var/list/checkers //list of /obj/effect/abstract/proximity_checkers
|
||||
var/current_range
|
||||
var/ignore_if_not_on_turf //don't check turfs in range if the host's loc isn't a turf
|
||||
var/datum/component/movement_tracker
|
||||
|
||||
/datum/proximity_monitor/New(atom/_host, range, _ignore_if_not_on_turf = TRUE)
|
||||
checkers = list()
|
||||
last_host_loc = _host.loc
|
||||
ignore_if_not_on_turf = _ignore_if_not_on_turf
|
||||
current_range = range
|
||||
SetHost(_host)
|
||||
|
||||
/datum/proximity_monitor/proc/SetHost(atom/H,atom/R)
|
||||
if(R)
|
||||
hasprox_receiver = R
|
||||
else if(hasprox_receiver == host) //Default case
|
||||
hasprox_receiver = H
|
||||
host = H
|
||||
last_host_loc = host.loc
|
||||
if(movement_tracker)
|
||||
QDEL_NULL(movement_tracker)
|
||||
movement_tracker = host.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/HandleMove)))
|
||||
SetRange(current_range,TRUE)
|
||||
|
||||
/datum/proximity_monitor/Destroy()
|
||||
host = null
|
||||
last_host_loc = null
|
||||
hasprox_receiver = null
|
||||
QDEL_LIST(checkers)
|
||||
QDEL_NULL(movement_tracker)
|
||||
return ..()
|
||||
|
||||
/datum/proximity_monitor/proc/HandleMove()
|
||||
var/atom/_host = host
|
||||
var/atom/new_host_loc = _host.loc
|
||||
if(last_host_loc != new_host_loc)
|
||||
last_host_loc = new_host_loc //hopefully this won't cause GC issues with containers
|
||||
var/curr_range = current_range
|
||||
SetRange(curr_range, TRUE)
|
||||
if(curr_range)
|
||||
testing("HasProx: [host] -> [host]")
|
||||
hasprox_receiver.HasProximity(host) //if we are processing, we're guaranteed to be a movable
|
||||
|
||||
/datum/proximity_monitor/proc/SetRange(range, force_rebuild = FALSE)
|
||||
if(!force_rebuild && range == current_range)
|
||||
return FALSE
|
||||
. = TRUE
|
||||
|
||||
current_range = range
|
||||
|
||||
var/list/checkers_local = checkers
|
||||
var/old_checkers_len = checkers_local.len
|
||||
|
||||
var/atom/_host = host
|
||||
|
||||
var/atom/loc_to_use = ignore_if_not_on_turf ? _host.loc : get_turf(_host)
|
||||
if(!isturf(loc_to_use)) //only check the host's loc
|
||||
if(range)
|
||||
var/obj/effect/abstract/proximity_checker/pc
|
||||
if(old_checkers_len)
|
||||
pc = checkers_local[old_checkers_len]
|
||||
--checkers_local.len
|
||||
QDEL_LIST(checkers_local)
|
||||
else
|
||||
pc = new(loc_to_use, src)
|
||||
|
||||
checkers_local += pc //only check the host's loc
|
||||
return
|
||||
|
||||
var/list/turfs = RANGE_TURFS(range, loc_to_use)
|
||||
var/turfs_len = turfs.len
|
||||
var/old_checkers_used = min(turfs_len, old_checkers_len)
|
||||
|
||||
//reuse what we can
|
||||
for(var/I in 1 to old_checkers_len)
|
||||
if(I <= old_checkers_used)
|
||||
var/obj/effect/abstract/proximity_checker/pc = checkers_local[I]
|
||||
pc.forceMove(turfs[I])
|
||||
else
|
||||
qdel(checkers_local[I]) //delete the leftovers
|
||||
|
||||
if(old_checkers_len < turfs_len)
|
||||
//create what we lack
|
||||
for(var/I in (old_checkers_used + 1) to turfs_len)
|
||||
checkers_local += new /obj/effect/abstract/proximity_checker(turfs[I], src)
|
||||
else
|
||||
checkers_local.Cut(old_checkers_used + 1, old_checkers_len)
|
||||
|
||||
/obj/effect/abstract/proximity_checker
|
||||
invisibility = INVISIBILITY_ABSTRACT
|
||||
anchored = TRUE
|
||||
var/datum/proximity_monitor/monitor
|
||||
|
||||
/obj/effect/abstract/proximity_checker/Initialize(mapload, datum/proximity_monitor/_monitor)
|
||||
. = ..()
|
||||
if(_monitor)
|
||||
monitor = _monitor
|
||||
else
|
||||
stack_trace("proximity_checker created without host")
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
/obj/effect/abstract/proximity_checker/Destroy()
|
||||
monitor = null
|
||||
return ..()
|
||||
|
||||
/obj/effect/abstract/proximity_checker/Crossed(atom/movable/AM)
|
||||
set waitfor = FALSE
|
||||
monitor.hasprox_receiver.HasProximity(AM)
|
||||
@@ -0,0 +1,65 @@
|
||||
#define CELSIUS_TO_KELVIN(T_K) ((T_K) + T0C)
|
||||
|
||||
#define OPTIMAL_TEMP_K_PLA_BURN_SCALE(PRESSURE_P,PRESSURE_O,TEMP_O) (((PRESSURE_P) * GLOB.meta_gas_specific_heats[/datum/gas/plasma]) / (((PRESSURE_P) * GLOB.meta_gas_specific_heats[/datum/gas/plasma] + (PRESSURE_O) * GLOB.meta_gas_specific_heats[/datum/gas/oxygen]) / PLASMA_UPPER_TEMPERATURE - (PRESSURE_O) * GLOB.meta_gas_specific_heats[/datum/gas/oxygen] / CELSIUS_TO_KELVIN(TEMP_O)))
|
||||
#define OPTIMAL_TEMP_K_PLA_BURN_RATIO(PRESSURE_P,PRESSURE_O,TEMP_O) (CELSIUS_TO_KELVIN(TEMP_O) * PLASMA_OXYGEN_FULLBURN * (PRESSURE_P) / (PRESSURE_O))
|
||||
|
||||
/obj/effect/spawner/newbomb
|
||||
name = "bomb"
|
||||
icon = 'icons/mob/screen_gen.dmi'
|
||||
icon_state = "x"
|
||||
var/temp_p = 1500
|
||||
var/temp_o = 1000 // tank temperatures
|
||||
var/pressure_p = 10 * ONE_ATMOSPHERE
|
||||
var/pressure_o = 10 * ONE_ATMOSPHERE //tank pressures
|
||||
var/assembly_type
|
||||
|
||||
/obj/effect/spawner/newbomb/Initialize()
|
||||
. = ..()
|
||||
var/obj/item/transfer_valve/V = new(src.loc)
|
||||
var/obj/item/tank/internals/plasma/PT = new(V)
|
||||
var/obj/item/tank/internals/oxygen/OT = new(V)
|
||||
|
||||
PT.air_contents.gases[/datum/gas/plasma] = pressure_p*PT.volume/(R_IDEAL_GAS_EQUATION*CELSIUS_TO_KELVIN(temp_p))
|
||||
PT.air_contents.temperature = CELSIUS_TO_KELVIN(temp_p)
|
||||
|
||||
OT.air_contents.gases[/datum/gas/oxygen] = pressure_o*OT.volume/(R_IDEAL_GAS_EQUATION*CELSIUS_TO_KELVIN(temp_o))
|
||||
OT.air_contents.temperature = CELSIUS_TO_KELVIN(temp_o)
|
||||
|
||||
V.tank_one = PT
|
||||
V.tank_two = OT
|
||||
PT.master = V
|
||||
OT.master = V
|
||||
|
||||
if(assembly_type)
|
||||
var/obj/item/assembly/A = new assembly_type(V)
|
||||
V.attached_device = A
|
||||
A.holder = V
|
||||
|
||||
V.update_icon()
|
||||
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
/obj/effect/spawner/newbomb/timer/syndicate/Initialize()
|
||||
temp_p = (OPTIMAL_TEMP_K_PLA_BURN_SCALE(pressure_p, pressure_o, temp_o)/2 + OPTIMAL_TEMP_K_PLA_BURN_RATIO(pressure_p, pressure_o, temp_o)/2) - T0C
|
||||
. = ..()
|
||||
|
||||
/obj/effect/spawner/newbomb/timer
|
||||
assembly_type = /obj/item/assembly/timer
|
||||
|
||||
/obj/effect/spawner/newbomb/timer/syndicate
|
||||
pressure_o = TANK_LEAK_PRESSURE - 1
|
||||
temp_o = 20
|
||||
|
||||
pressure_p = TANK_LEAK_PRESSURE - 1
|
||||
|
||||
/obj/effect/spawner/newbomb/proximity
|
||||
assembly_type = /obj/item/assembly/prox_sensor
|
||||
|
||||
/obj/effect/spawner/newbomb/radio
|
||||
assembly_type = /obj/item/assembly/signaler
|
||||
|
||||
|
||||
#undef CELSIUS_TO_KELVIN
|
||||
|
||||
#undef OPTIMAL_TEMP_K_PLA_BURN_SCALE
|
||||
#undef OPTIMAL_TEMP_K_PLA_BURN_RATIO
|
||||
@@ -0,0 +1,170 @@
|
||||
/obj/effect/spawner/bundle
|
||||
name = "bundle spawner"
|
||||
icon = 'icons/mob/screen_gen.dmi'
|
||||
icon_state = "x2"
|
||||
color = "#00FF00"
|
||||
|
||||
var/list/items
|
||||
|
||||
/obj/effect/spawner/bundle/Initialize(mapload)
|
||||
..()
|
||||
if(items && items.len)
|
||||
var/turf/T = get_turf(src)
|
||||
for(var/path in items)
|
||||
new path(T)
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
/obj/effect/spawner/bundle/costume/chicken
|
||||
name = "chicken costume spawner"
|
||||
items = list(
|
||||
/obj/item/clothing/suit/chickensuit,
|
||||
/obj/item/clothing/head/chicken,
|
||||
/obj/item/reagent_containers/food/snacks/egg)
|
||||
|
||||
/obj/effect/spawner/bundle/costume/gladiator
|
||||
name = "gladiator costume spawner"
|
||||
items = list(
|
||||
/obj/item/clothing/under/gladiator,
|
||||
/obj/item/clothing/head/helmet/gladiator)
|
||||
|
||||
/obj/effect/spawner/bundle/costume/madscientist
|
||||
name = "mad scientist costume spawner"
|
||||
items = list(
|
||||
/obj/item/clothing/under/gimmick/rank/captain/suit,
|
||||
/obj/item/clothing/head/flatcap,
|
||||
/obj/item/clothing/suit/toggle/labcoat/mad)
|
||||
|
||||
/obj/effect/spawner/bundle/costume/elpresidente
|
||||
name = "el presidente costume spawner"
|
||||
items = list(
|
||||
/obj/item/clothing/under/gimmick/rank/captain/suit,
|
||||
/obj/item/clothing/head/flatcap,
|
||||
/obj/item/clothing/mask/cigarette/cigar/havana,
|
||||
/obj/item/clothing/shoes/jackboots)
|
||||
|
||||
/obj/effect/spawner/bundle/costume/nyangirl
|
||||
name = "nyangirl costume spawner"
|
||||
items = list(
|
||||
/obj/item/clothing/under/schoolgirl,
|
||||
/obj/item/clothing/head/kitty,
|
||||
/obj/item/clothing/glasses/sunglasses/blindfold)
|
||||
|
||||
/obj/effect/spawner/bundle/costume/maid
|
||||
name = "maid costume spawner"
|
||||
items = list(
|
||||
/obj/item/clothing/under/skirt/black,
|
||||
/obj/effect/spawner/lootdrop/minor/beret_or_rabbitears,
|
||||
/obj/item/clothing/glasses/sunglasses/blindfold)
|
||||
|
||||
|
||||
/obj/effect/spawner/bundle/costume/butler
|
||||
name = "butler costume spawner"
|
||||
items = list(
|
||||
/obj/item/clothing/accessory/waistcoat,
|
||||
/obj/item/clothing/under/suit_jacket,
|
||||
/obj/item/clothing/head/that)
|
||||
|
||||
/obj/effect/spawner/bundle/costume/highlander
|
||||
name = "highlander costume spawner"
|
||||
items = list(
|
||||
/obj/item/clothing/under/kilt,
|
||||
/obj/item/clothing/head/beret)
|
||||
|
||||
/obj/effect/spawner/bundle/costume/prig
|
||||
name = "prig costume spawner"
|
||||
items = list(
|
||||
/obj/item/clothing/accessory/waistcoat,
|
||||
/obj/item/clothing/glasses/monocle,
|
||||
/obj/effect/spawner/lootdrop/minor/bowler_or_that,
|
||||
/obj/item/clothing/shoes/sneakers/black,
|
||||
/obj/item/cane,
|
||||
/obj/item/clothing/under/sl_suit,
|
||||
/obj/item/clothing/mask/fakemoustache)
|
||||
|
||||
/obj/effect/spawner/bundle/costume/plaguedoctor
|
||||
name = "plague doctor costume spawner"
|
||||
items = list(
|
||||
/obj/item/clothing/suit/bio_suit/plaguedoctorsuit,
|
||||
/obj/item/clothing/head/plaguedoctorhat,
|
||||
/obj/item/clothing/mask/gas/plaguedoctor)
|
||||
|
||||
/obj/effect/spawner/bundle/costume/nightowl
|
||||
name = "night owl costume spawner"
|
||||
items = list(
|
||||
/obj/item/clothing/suit/toggle/owlwings,
|
||||
/obj/item/clothing/under/owl,
|
||||
/obj/item/clothing/mask/gas/owl_mask)
|
||||
|
||||
/obj/effect/spawner/bundle/costume/griffin
|
||||
name = "griffin costume spawner"
|
||||
items = list(
|
||||
/obj/item/clothing/suit/toggle/owlwings/griffinwings,
|
||||
/obj/item/clothing/shoes/griffin,
|
||||
/obj/item/clothing/under/griffin,
|
||||
/obj/item/clothing/head/griffin)
|
||||
|
||||
/obj/effect/spawner/bundle/costume/waiter
|
||||
name = "waiter costume spawner"
|
||||
items = list(
|
||||
/obj/item/clothing/under/waiter,
|
||||
/obj/effect/spawner/lootdrop/minor/kittyears_or_rabbitears,
|
||||
/obj/item/clothing/suit/apron)
|
||||
|
||||
/obj/effect/spawner/bundle/costume/pirate
|
||||
name = "pirate costume spawner"
|
||||
items = list(
|
||||
/obj/item/clothing/under/pirate,
|
||||
/obj/item/clothing/suit/pirate,
|
||||
/obj/effect/spawner/lootdrop/minor/pirate_or_bandana,
|
||||
/obj/item/clothing/glasses/eyepatch)
|
||||
|
||||
/obj/effect/spawner/bundle/costume/commie
|
||||
name = "commie costume spawner"
|
||||
items = list(
|
||||
/obj/item/clothing/under/soviet,
|
||||
/obj/item/clothing/head/ushanka)
|
||||
|
||||
/obj/effect/spawner/bundle/costume/imperium_monk
|
||||
name = "imperium monk costume spawner"
|
||||
items = list(
|
||||
/obj/item/clothing/suit/imperium_monk,
|
||||
/obj/effect/spawner/lootdrop/minor/twentyfive_percent_cyborg_mask)
|
||||
|
||||
/obj/effect/spawner/bundle/costume/holiday_priest
|
||||
name = "holiday priest costume spawner"
|
||||
items = list(
|
||||
/obj/item/clothing/suit/holidaypriest)
|
||||
|
||||
/obj/effect/spawner/bundle/costume/marisawizard
|
||||
name = "marisa wizard costume spawner"
|
||||
items = list(
|
||||
/obj/item/clothing/shoes/sandal/marisa,
|
||||
/obj/item/clothing/head/wizard/marisa/fake,
|
||||
/obj/item/clothing/suit/wizrobe/marisa/fake)
|
||||
|
||||
/obj/effect/spawner/bundle/costume/cutewitch
|
||||
name = "cute witch costume spawner"
|
||||
items = list(
|
||||
/obj/item/clothing/under/sundress,
|
||||
/obj/item/clothing/head/witchwig,
|
||||
/obj/item/staff/broom)
|
||||
|
||||
/obj/effect/spawner/bundle/costume/wizard
|
||||
name = "wizard costume spawner"
|
||||
items = list(
|
||||
/obj/item/clothing/shoes/sandal,
|
||||
/obj/item/clothing/suit/wizrobe/fake,
|
||||
/obj/item/clothing/head/wizard/fake,
|
||||
/obj/item/staff)
|
||||
|
||||
/obj/effect/spawner/bundle/costume/sexyclown
|
||||
name = "sexy clown costume spawner"
|
||||
items = list(
|
||||
/obj/item/clothing/mask/gas/sexyclown,
|
||||
/obj/item/clothing/under/rank/clown/sexy)
|
||||
|
||||
/obj/effect/spawner/bundle/costume/sexymime
|
||||
name = "sexy mime costume spawner"
|
||||
items = list(
|
||||
/obj/item/clothing/mask/gas/sexymime,
|
||||
/obj/item/clothing/under/sexymime)
|
||||
@@ -0,0 +1,120 @@
|
||||
|
||||
/obj/effect/gibspawner
|
||||
var/sparks = 0 //whether sparks spread
|
||||
var/virusProb = 20 //the chance for viruses to spread on the gibs
|
||||
var/list/gibtypes = list() //typepaths of the gib decals to spawn
|
||||
var/list/gibamounts = list() //amount to spawn for each gib decal type we'll spawn.
|
||||
var/list/gibdirections = list() //of lists of possible directions to spread each gib decal type towards.
|
||||
|
||||
/obj/effect/gibspawner/Initialize(mapload, datum/dna/MobDNA, list/datum/disease/diseases)
|
||||
. = ..()
|
||||
|
||||
if(gibtypes.len != gibamounts.len || gibamounts.len != gibdirections.len)
|
||||
to_chat(world, "<span class='danger'>Gib list length mismatch!</span>")
|
||||
return
|
||||
|
||||
var/obj/effect/decal/cleanable/blood/gibs/gib = null
|
||||
|
||||
if(sparks)
|
||||
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
|
||||
s.set_up(2, 1, loc)
|
||||
s.start()
|
||||
|
||||
for(var/i = 1, i<= gibtypes.len, i++)
|
||||
if(gibamounts[i])
|
||||
for(var/j = 1, j<= gibamounts[i], j++)
|
||||
var/gibType = gibtypes[i]
|
||||
gib = new gibType(loc, diseases)
|
||||
if(iscarbon(loc))
|
||||
var/mob/living/carbon/digester = loc
|
||||
digester.stomach_contents += gib
|
||||
|
||||
if(MobDNA)
|
||||
|
||||
else if(istype(src, /obj/effect/gibspawner/generic)) // Probably a monkey
|
||||
gib.add_blood_DNA(list("Non-human DNA" = "A+"))
|
||||
var/list/directions = gibdirections[i]
|
||||
if(isturf(loc))
|
||||
if(directions.len)
|
||||
gib.streak(directions)
|
||||
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
|
||||
|
||||
/obj/effect/gibspawner/generic
|
||||
gibtypes = list(/obj/effect/decal/cleanable/blood/gibs, /obj/effect/decal/cleanable/blood/gibs, /obj/effect/decal/cleanable/blood/gibs/core)
|
||||
gibamounts = list(2,2,1)
|
||||
|
||||
/obj/effect/gibspawner/generic/Initialize()
|
||||
playsound(src, 'sound/effects/blobattack.ogg', 40, 1)
|
||||
gibdirections = list(list(WEST, NORTHWEST, SOUTHWEST, NORTH),list(EAST, NORTHEAST, SOUTHEAST, SOUTH), list())
|
||||
. = ..()
|
||||
|
||||
/obj/effect/gibspawner/human
|
||||
gibtypes = list(/obj/effect/decal/cleanable/blood/gibs/up, /obj/effect/decal/cleanable/blood/gibs/down, /obj/effect/decal/cleanable/blood/gibs, /obj/effect/decal/cleanable/blood/gibs, /obj/effect/decal/cleanable/blood/gibs/body, /obj/effect/decal/cleanable/blood/gibs/limb, /obj/effect/decal/cleanable/blood/gibs/core)
|
||||
gibamounts = list(1,1,1,1,1,1,1)
|
||||
|
||||
/obj/effect/gibspawner/human/Initialize()
|
||||
playsound(src, 'sound/effects/blobattack.ogg', 50, 1)
|
||||
gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST),list(WEST, NORTHWEST, SOUTHWEST),list(EAST, NORTHEAST, SOUTHEAST), GLOB.alldirs, GLOB.alldirs, list())
|
||||
. = ..()
|
||||
|
||||
|
||||
/obj/effect/gibspawner/humanbodypartless //only the gibs that don't look like actual full bodyparts (except torso).
|
||||
gibtypes = list(/obj/effect/decal/cleanable/blood/gibs, /obj/effect/decal/cleanable/blood/gibs/core, /obj/effect/decal/cleanable/blood/gibs, /obj/effect/decal/cleanable/blood/gibs/core, /obj/effect/decal/cleanable/blood/gibs, /obj/effect/decal/cleanable/blood/gibs/torso)
|
||||
gibamounts = list(1, 1, 1, 1, 1, 1)
|
||||
|
||||
/obj/effect/gibspawner/humanbodypartless/Initialize()
|
||||
playsound(src, 'sound/effects/blobattack.ogg', 50, 1)
|
||||
gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST),list(WEST, NORTHWEST, SOUTHWEST),list(EAST, NORTHEAST, SOUTHEAST), GLOB.alldirs, list())
|
||||
. = ..()
|
||||
|
||||
|
||||
/obj/effect/gibspawner/xeno
|
||||
gibtypes = list(/obj/effect/decal/cleanable/xenoblood/xgibs/up, /obj/effect/decal/cleanable/xenoblood/xgibs/down, /obj/effect/decal/cleanable/xenoblood/xgibs, /obj/effect/decal/cleanable/xenoblood/xgibs, /obj/effect/decal/cleanable/xenoblood/xgibs/body, /obj/effect/decal/cleanable/xenoblood/xgibs/limb, /obj/effect/decal/cleanable/xenoblood/xgibs/core)
|
||||
gibamounts = list(1,1,1,1,1,1,1)
|
||||
|
||||
/obj/effect/gibspawner/xeno/Initialize()
|
||||
playsound(src, 'sound/effects/blobattack.ogg', 60, 1)
|
||||
gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST),list(WEST, NORTHWEST, SOUTHWEST),list(EAST, NORTHEAST, SOUTHEAST), GLOB.alldirs, GLOB.alldirs, list())
|
||||
. = ..()
|
||||
|
||||
|
||||
/obj/effect/gibspawner/xenobodypartless //only the gibs that don't look like actual full bodyparts (except torso).
|
||||
gibtypes = list(/obj/effect/decal/cleanable/xenoblood/xgibs, /obj/effect/decal/cleanable/xenoblood/xgibs/core, /obj/effect/decal/cleanable/xenoblood/xgibs, /obj/effect/decal/cleanable/xenoblood/xgibs/core, /obj/effect/decal/cleanable/xenoblood/xgibs, /obj/effect/decal/cleanable/xenoblood/xgibs/torso)
|
||||
gibamounts = list(1, 1, 1, 1, 1, 1)
|
||||
|
||||
|
||||
/obj/effect/gibspawner/xenobodypartless/Initialize()
|
||||
playsound(src, 'sound/effects/blobattack.ogg', 60, 1)
|
||||
gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST),list(WEST, NORTHWEST, SOUTHWEST),list(EAST, NORTHEAST, SOUTHEAST), GLOB.alldirs, list())
|
||||
. = ..()
|
||||
|
||||
/obj/effect/gibspawner/larva
|
||||
gibtypes = list(/obj/effect/decal/cleanable/xenoblood/xgibs/larva, /obj/effect/decal/cleanable/xenoblood/xgibs/larva, /obj/effect/decal/cleanable/xenoblood/xgibs/larva/body, /obj/effect/decal/cleanable/xenoblood/xgibs/larva/body)
|
||||
gibamounts = list(1, 1, 1, 1)
|
||||
|
||||
/obj/effect/gibspawner/larva/Initialize()
|
||||
playsound(src, 'sound/effects/blobattack.ogg', 60, 1)
|
||||
gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST), list(), GLOB.alldirs)
|
||||
. = ..()
|
||||
|
||||
/obj/effect/gibspawner/larvabodypartless
|
||||
gibtypes = list(/obj/effect/decal/cleanable/xenoblood/xgibs/larva, /obj/effect/decal/cleanable/xenoblood/xgibs/larva, /obj/effect/decal/cleanable/xenoblood/xgibs/larva)
|
||||
gibamounts = list(1, 1, 1)
|
||||
|
||||
/obj/effect/gibspawner/larvabodypartless/Initialize()
|
||||
playsound(src, 'sound/effects/blobattack.ogg', 60, 1)
|
||||
gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST), list())
|
||||
. = ..()
|
||||
|
||||
/obj/effect/gibspawner/robot
|
||||
sparks = 1
|
||||
gibtypes = list(/obj/effect/decal/cleanable/robot_debris/up, /obj/effect/decal/cleanable/robot_debris/down, /obj/effect/decal/cleanable/robot_debris, /obj/effect/decal/cleanable/robot_debris, /obj/effect/decal/cleanable/robot_debris, /obj/effect/decal/cleanable/robot_debris/limb)
|
||||
gibamounts = list(1,1,1,1,1,1)
|
||||
|
||||
/obj/effect/gibspawner/robot/Initialize()
|
||||
gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST),list(WEST, NORTHWEST, SOUTHWEST),list(EAST, NORTHEAST, SOUTHEAST), GLOB.alldirs, GLOB.alldirs)
|
||||
gibamounts[6] = pick(0,1,2)
|
||||
. = ..()
|
||||
@@ -0,0 +1,380 @@
|
||||
/obj/effect/spawner/lootdrop
|
||||
icon = 'icons/effects/landmarks_static.dmi'
|
||||
icon_state = "random_loot"
|
||||
layer = OBJ_LAYER
|
||||
var/lootcount = 1 //how many items will be spawned
|
||||
var/lootdoubles = TRUE //if the same item can be spawned twice
|
||||
var/list/loot //a list of possible items to spawn e.g. list(/obj/item, /obj/structure, /obj/effect)
|
||||
var/fan_out_items = FALSE //Whether the items should be distributed to offsets 0,1,-1,2,-2,3,-3.. This overrides pixel_x/y on the spawner itself
|
||||
|
||||
/obj/effect/spawner/lootdrop/Initialize(mapload)
|
||||
..()
|
||||
if(loot && loot.len)
|
||||
var/turf/T = get_turf(src)
|
||||
var/loot_spawned = 0
|
||||
while((lootcount-loot_spawned) && loot.len)
|
||||
var/lootspawn = pickweight(loot)
|
||||
if(!lootdoubles)
|
||||
loot.Remove(lootspawn)
|
||||
|
||||
if(lootspawn)
|
||||
var/atom/movable/spawned_loot = new lootspawn(T)
|
||||
if (!fan_out_items)
|
||||
if (pixel_x != 0)
|
||||
spawned_loot.pixel_x = pixel_x
|
||||
if (pixel_y != 0)
|
||||
spawned_loot.pixel_y = pixel_y
|
||||
else
|
||||
if (loot_spawned)
|
||||
spawned_loot.pixel_x = spawned_loot.pixel_y = ((!(loot_spawned%2)*loot_spawned/2)*-1)+((loot_spawned%2)*(loot_spawned+1)/2*1)
|
||||
loot_spawned++
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
/obj/effect/spawner/lootdrop/bedsheet
|
||||
icon = 'icons/obj/bedsheets.dmi'
|
||||
icon_state = "random_bedsheet"
|
||||
name = "random dorms bedsheet"
|
||||
loot = list(/obj/item/bedsheet = 8, /obj/item/bedsheet/blue = 8, /obj/item/bedsheet/green = 8,
|
||||
/obj/item/bedsheet/grey = 8, /obj/item/bedsheet/orange = 8, /obj/item/bedsheet/purple = 8,
|
||||
/obj/item/bedsheet/red = 8, /obj/item/bedsheet/yellow = 8, /obj/item/bedsheet/brown = 8,
|
||||
/obj/item/bedsheet/black = 8, /obj/item/bedsheet/patriot = 3, /obj/item/bedsheet/rainbow = 3,
|
||||
/obj/item/bedsheet/ian = 3, /obj/item/bedsheet/runtime = 3, /obj/item/bedsheet/nanotrasen = 3,
|
||||
/obj/item/bedsheet/pirate = 1, /obj/item/bedsheet/cosmos = 1, /obj/item/bedsheet/gondola = 1
|
||||
)
|
||||
|
||||
/obj/effect/spawner/lootdrop/armory_contraband
|
||||
name = "armory contraband gun spawner"
|
||||
lootdoubles = FALSE
|
||||
|
||||
loot = list(
|
||||
/obj/item/gun/ballistic/automatic/pistol = 8,
|
||||
/obj/item/gun/ballistic/shotgun/automatic/combat = 5,
|
||||
/obj/item/gun/ballistic/revolver/mateba,
|
||||
/obj/item/gun/ballistic/automatic/pistol/deagle
|
||||
)
|
||||
|
||||
/obj/effect/spawner/lootdrop/armory_contraband/metastation
|
||||
loot = list(/obj/item/gun/ballistic/automatic/pistol = 5,
|
||||
/obj/item/gun/ballistic/shotgun/automatic/combat = 5,
|
||||
/obj/item/gun/ballistic/revolver/mateba,
|
||||
/obj/item/gun/ballistic/automatic/pistol/deagle,
|
||||
/obj/item/storage/box/syndie_kit/throwing_weapons = 3)
|
||||
|
||||
/obj/effect/spawner/lootdrop/gambling
|
||||
name = "gambling valuables spawner"
|
||||
loot = list(
|
||||
/obj/item/gun/ballistic/revolver/russian = 5,
|
||||
/obj/item/storage/box/syndie_kit/throwing_weapons = 1,
|
||||
/obj/item/toy/cards/deck/syndicate = 2
|
||||
)
|
||||
|
||||
/obj/effect/spawner/lootdrop/grille_or_trash
|
||||
name = "maint grille or trash spawner"
|
||||
loot = list(/obj/structure/grille = 5,
|
||||
/obj/item/cigbutt = 1,
|
||||
/obj/item/trash/cheesie = 1,
|
||||
/obj/item/trash/candy = 1,
|
||||
/obj/item/trash/chips = 1,
|
||||
/obj/item/reagent_containers/food/snacks/deadmouse = 1,
|
||||
/obj/item/trash/pistachios = 1,
|
||||
/obj/item/trash/plate = 1,
|
||||
/obj/item/trash/popcorn = 1,
|
||||
/obj/item/trash/raisins = 1,
|
||||
/obj/item/trash/sosjerky = 1,
|
||||
/obj/item/trash/syndi_cakes = 1)
|
||||
|
||||
/obj/effect/spawner/lootdrop/three_course_meal
|
||||
name = "three course meal spawner"
|
||||
lootcount = 3
|
||||
lootdoubles = FALSE
|
||||
var/soups = list(
|
||||
/obj/item/reagent_containers/food/snacks/soup/beet,
|
||||
/obj/item/reagent_containers/food/snacks/soup/sweetpotato,
|
||||
/obj/item/reagent_containers/food/snacks/soup/stew,
|
||||
/obj/item/reagent_containers/food/snacks/soup/hotchili,
|
||||
/obj/item/reagent_containers/food/snacks/soup/nettle,
|
||||
/obj/item/reagent_containers/food/snacks/soup/meatball)
|
||||
var/salads = list(
|
||||
/obj/item/reagent_containers/food/snacks/salad/herbsalad,
|
||||
/obj/item/reagent_containers/food/snacks/salad/validsalad,
|
||||
/obj/item/reagent_containers/food/snacks/salad/fruit,
|
||||
/obj/item/reagent_containers/food/snacks/salad/jungle,
|
||||
/obj/item/reagent_containers/food/snacks/salad/aesirsalad)
|
||||
var/mains = list(
|
||||
/obj/item/reagent_containers/food/snacks/bearsteak,
|
||||
/obj/item/reagent_containers/food/snacks/enchiladas,
|
||||
/obj/item/reagent_containers/food/snacks/stewedsoymeat,
|
||||
/obj/item/reagent_containers/food/snacks/burger/bigbite,
|
||||
/obj/item/reagent_containers/food/snacks/burger/superbite,
|
||||
/obj/item/reagent_containers/food/snacks/burger/fivealarm)
|
||||
|
||||
/obj/effect/spawner/lootdrop/three_course_meal/Initialize(mapload)
|
||||
loot = list(pick(soups) = 1,pick(salads) = 1,pick(mains) = 1)
|
||||
. = ..()
|
||||
|
||||
/obj/effect/spawner/lootdrop/maintenance
|
||||
name = "maintenance loot spawner"
|
||||
// see code/_globalvars/lists/maintenance_loot.dm for loot table
|
||||
|
||||
/obj/effect/spawner/lootdrop/maintenance/Initialize(mapload)
|
||||
loot = GLOB.maintenance_loot
|
||||
. = ..()
|
||||
|
||||
/obj/effect/spawner/lootdrop/glowstick
|
||||
name = "random colored glowstick"
|
||||
icon = 'icons/obj/lighting.dmi'
|
||||
icon_state = "random_glowstick"
|
||||
|
||||
/obj/effect/spawner/lootdrop/glowstick/Initialize()
|
||||
loot = typesof(/obj/item/flashlight/glowstick)
|
||||
. = ..()
|
||||
|
||||
|
||||
/obj/effect/spawner/lootdrop/gloves
|
||||
name = "random gloves"
|
||||
desc = "These gloves are supposed to be a random color..."
|
||||
icon = 'icons/obj/clothing/gloves.dmi'
|
||||
icon_state = "random_gloves"
|
||||
loot = list(
|
||||
/obj/item/clothing/gloves/color/orange = 1,
|
||||
/obj/item/clothing/gloves/color/red = 1,
|
||||
/obj/item/clothing/gloves/color/blue = 1,
|
||||
/obj/item/clothing/gloves/color/purple = 1,
|
||||
/obj/item/clothing/gloves/color/green = 1,
|
||||
/obj/item/clothing/gloves/color/grey = 1,
|
||||
/obj/item/clothing/gloves/color/light_brown = 1,
|
||||
/obj/item/clothing/gloves/color/brown = 1,
|
||||
/obj/item/clothing/gloves/color/white = 1,
|
||||
/obj/item/clothing/gloves/color/rainbow = 1)
|
||||
|
||||
/obj/effect/spawner/lootdrop/crate_spawner
|
||||
name = "lootcrate spawner" //USE PROMO CODE "SELLOUT" FOR 20% OFF!
|
||||
lootdoubles = FALSE
|
||||
|
||||
loot = list(
|
||||
/obj/structure/closet/crate/secure/loot = 20,
|
||||
"" = 80
|
||||
)
|
||||
|
||||
/obj/effect/spawner/lootdrop/organ_spawner
|
||||
name = "organ spawner"
|
||||
loot = list(
|
||||
/obj/item/organ/heart/gland/electric = 3,
|
||||
/obj/item/organ/heart/gland/trauma = 4,
|
||||
/obj/item/organ/heart/gland/egg = 7,
|
||||
/obj/item/organ/heart/gland/chem = 5,
|
||||
/obj/item/organ/heart/gland/mindshock = 5,
|
||||
/obj/item/organ/heart/gland/plasma = 7,
|
||||
/obj/item/organ/heart/gland/pop = 5,
|
||||
/obj/item/organ/heart/gland/slime = 4,
|
||||
/obj/item/organ/heart/gland/spiderman = 5,
|
||||
/obj/item/organ/heart/gland/ventcrawling = 1,
|
||||
/obj/item/organ/body_egg/alien_embryo = 1,
|
||||
/obj/item/organ/regenerative_core = 2)
|
||||
lootcount = 3
|
||||
|
||||
/obj/effect/spawner/lootdrop/two_percent_xeno_egg_spawner
|
||||
name = "2% chance xeno egg spawner"
|
||||
loot = list(
|
||||
/obj/effect/decal/remains/xeno = 49,
|
||||
/obj/effect/spawner/xeno_egg_delivery = 1)
|
||||
|
||||
/obj/effect/spawner/lootdrop/costume
|
||||
name = "random costume spawner"
|
||||
|
||||
/obj/effect/spawner/lootdrop/costume/Initialize()
|
||||
loot = list()
|
||||
for(var/path in subtypesof(/obj/effect/spawner/bundle/costume))
|
||||
loot[path] = TRUE
|
||||
. = ..()
|
||||
|
||||
// Minor lootdrops follow
|
||||
|
||||
/obj/effect/spawner/lootdrop/minor/beret_or_rabbitears
|
||||
name = "beret or rabbit ears spawner"
|
||||
loot = list(
|
||||
/obj/item/clothing/head/beret = 1,
|
||||
/obj/item/clothing/head/rabbitears = 1)
|
||||
|
||||
/obj/effect/spawner/lootdrop/minor/bowler_or_that
|
||||
name = "bowler or top hat spawner"
|
||||
loot = list(
|
||||
/obj/item/clothing/head/bowler = 1,
|
||||
/obj/item/clothing/head/that = 1)
|
||||
|
||||
/obj/effect/spawner/lootdrop/minor/kittyears_or_rabbitears
|
||||
name = "kitty ears or rabbit ears spawner"
|
||||
loot = list(
|
||||
/obj/item/clothing/head/kitty = 1,
|
||||
/obj/item/clothing/head/rabbitears = 1)
|
||||
|
||||
/obj/effect/spawner/lootdrop/minor/pirate_or_bandana
|
||||
name = "pirate hat or bandana spawner"
|
||||
loot = list(
|
||||
/obj/item/clothing/head/pirate = 1,
|
||||
/obj/item/clothing/head/bandana = 1)
|
||||
|
||||
/obj/effect/spawner/lootdrop/minor/twentyfive_percent_cyborg_mask
|
||||
name = "25% cyborg mask spawner"
|
||||
loot = list(
|
||||
/obj/item/clothing/mask/gas/cyborg = 25,
|
||||
"" = 75)
|
||||
|
||||
/obj/effect/spawner/lootdrop/aimodule_harmless // These shouldn't allow the AI to start butchering people
|
||||
name = "harmless AI module spawner"
|
||||
loot = list(
|
||||
/obj/item/aiModule/core/full/asimov,
|
||||
/obj/item/aiModule/core/full/asimovpp,
|
||||
/obj/item/aiModule/core/full/hippocratic,
|
||||
/obj/item/aiModule/core/full/paladin_devotion,
|
||||
/obj/item/aiModule/core/full/paladin
|
||||
)
|
||||
|
||||
/obj/effect/spawner/lootdrop/aimodule_neutral // These shouldn't allow the AI to start butchering people without reason
|
||||
name = "neutral AI module spawner"
|
||||
loot = list(
|
||||
/obj/item/aiModule/core/full/corp,
|
||||
/obj/item/aiModule/core/full/maintain,
|
||||
/obj/item/aiModule/core/full/drone,
|
||||
/obj/item/aiModule/core/full/peacekeeper,
|
||||
/obj/item/aiModule/core/full/reporter,
|
||||
/obj/item/aiModule/core/full/robocop,
|
||||
/obj/item/aiModule/core/full/liveandletlive,
|
||||
/obj/item/aiModule/core/full/hulkamania
|
||||
)
|
||||
|
||||
/obj/effect/spawner/lootdrop/aimodule_harmful // These will get the shuttle called
|
||||
name = "harmful AI module spawner"
|
||||
loot = list(
|
||||
/obj/item/aiModule/core/full/antimov,
|
||||
/obj/item/aiModule/core/full/balance,
|
||||
/obj/item/aiModule/core/full/tyrant,
|
||||
/obj/item/aiModule/core/full/thermurderdynamic,
|
||||
/obj/item/aiModule/core/full/damaged
|
||||
)
|
||||
|
||||
/obj/effect/spawner/lootdrop/mre
|
||||
name = "random MRE"
|
||||
icon = 'icons/obj/storage.dmi'
|
||||
icon_state = "mre"
|
||||
|
||||
/obj/effect/spawner/lootdrop/mre/Initialize()
|
||||
for(var/A in subtypesof(/obj/item/storage/box/mre))
|
||||
var/obj/item/storage/box/mre/M = A
|
||||
var/our_chance = initial(M.spawner_chance)
|
||||
if(our_chance)
|
||||
LAZYSET(loot, M, our_chance)
|
||||
return ..()
|
||||
|
||||
|
||||
// Tech storage circuit board spawners
|
||||
// For these, make sure that lootcount equals the number of list items
|
||||
|
||||
/obj/effect/spawner/lootdrop/techstorage
|
||||
name = "generic circuit board spawner"
|
||||
lootdoubles = FALSE
|
||||
fan_out_items = TRUE
|
||||
|
||||
/obj/effect/spawner/lootdrop/techstorage/service
|
||||
name = "service circuit board spawner"
|
||||
lootcount = 10
|
||||
loot = list(
|
||||
/obj/item/circuitboard/computer/arcade/battle,
|
||||
/obj/item/circuitboard/computer/arcade/orion_trail,
|
||||
/obj/item/circuitboard/machine/autolathe,
|
||||
/obj/item/circuitboard/computer/mining,
|
||||
/obj/item/circuitboard/machine/ore_redemption,
|
||||
/obj/item/circuitboard/machine/mining_equipment_vendor,
|
||||
/obj/item/circuitboard/machine/microwave,
|
||||
/obj/item/circuitboard/machine/chem_dispenser/drinks,
|
||||
/obj/item/circuitboard/machine/chem_dispenser/drinks/beer,
|
||||
/obj/item/circuitboard/computer/slot_machine
|
||||
)
|
||||
|
||||
/obj/effect/spawner/lootdrop/techstorage/rnd
|
||||
name = "RnD circuit board spawner"
|
||||
lootcount = 8
|
||||
loot = list(
|
||||
/obj/item/circuitboard/computer/aifixer,
|
||||
/obj/item/circuitboard/machine/rdserver,
|
||||
/obj/item/circuitboard/computer/pandemic,
|
||||
/obj/item/circuitboard/machine/mechfab,
|
||||
/obj/item/circuitboard/machine/circuit_imprinter/department,
|
||||
/obj/item/circuitboard/computer/teleporter,
|
||||
/obj/item/circuitboard/machine/destructive_analyzer,
|
||||
/obj/item/circuitboard/computer/rdconsole
|
||||
)
|
||||
|
||||
/obj/effect/spawner/lootdrop/techstorage/security
|
||||
name = "security circuit board spawner"
|
||||
lootcount = 3
|
||||
loot = list(
|
||||
/obj/item/circuitboard/computer/secure_data,
|
||||
/obj/item/circuitboard/computer/security,
|
||||
/obj/item/circuitboard/computer/prisoner
|
||||
)
|
||||
|
||||
/obj/effect/spawner/lootdrop/techstorage/engineering
|
||||
name = "engineering circuit board spawner"
|
||||
lootcount = 3
|
||||
loot = list(
|
||||
/obj/item/circuitboard/computer/atmos_alert,
|
||||
/obj/item/circuitboard/computer/stationalert,
|
||||
/obj/item/circuitboard/computer/powermonitor
|
||||
)
|
||||
|
||||
/obj/effect/spawner/lootdrop/techstorage/tcomms
|
||||
name = "tcomms circuit board spawner"
|
||||
lootcount = 9
|
||||
loot = list(
|
||||
/obj/item/circuitboard/computer/message_monitor,
|
||||
/obj/item/circuitboard/machine/telecomms/broadcaster,
|
||||
/obj/item/circuitboard/machine/telecomms/bus,
|
||||
/obj/item/circuitboard/machine/telecomms/server,
|
||||
/obj/item/circuitboard/machine/telecomms/receiver,
|
||||
/obj/item/circuitboard/machine/telecomms/processor,
|
||||
/obj/item/circuitboard/machine/announcement_system,
|
||||
/obj/item/circuitboard/computer/comm_server,
|
||||
/obj/item/circuitboard/computer/comm_monitor
|
||||
)
|
||||
|
||||
/obj/effect/spawner/lootdrop/techstorage/medical
|
||||
name = "medical circuit board spawner"
|
||||
lootcount = 8
|
||||
loot = list(
|
||||
/obj/item/circuitboard/computer/cloning,
|
||||
/obj/item/circuitboard/machine/clonepod,
|
||||
/obj/item/circuitboard/machine/chem_dispenser,
|
||||
/obj/item/circuitboard/computer/scan_consolenew,
|
||||
/obj/item/circuitboard/computer/med_data,
|
||||
/obj/item/circuitboard/machine/smoke_machine,
|
||||
/obj/item/circuitboard/machine/chem_master,
|
||||
/obj/item/circuitboard/machine/clonescanner
|
||||
)
|
||||
|
||||
/obj/effect/spawner/lootdrop/techstorage/AI
|
||||
name = "secure AI circuit board spawner"
|
||||
lootcount = 3
|
||||
loot = list(
|
||||
/obj/item/circuitboard/computer/aiupload,
|
||||
/obj/item/circuitboard/computer/borgupload,
|
||||
/obj/item/circuitboard/aicore
|
||||
)
|
||||
|
||||
/obj/effect/spawner/lootdrop/techstorage/command
|
||||
name = "secure command circuit board spawner"
|
||||
lootcount = 3
|
||||
loot = list(
|
||||
/obj/item/circuitboard/computer/crew,
|
||||
/obj/item/circuitboard/computer/communications,
|
||||
/obj/item/circuitboard/computer/card
|
||||
)
|
||||
|
||||
/obj/effect/spawner/lootdrop/techstorage/RnD_secure
|
||||
name = "secure RnD circuit board spawner"
|
||||
lootcount = 3
|
||||
loot = list(
|
||||
/obj/item/circuitboard/computer/mecha_control,
|
||||
/obj/item/circuitboard/computer/apc_control,
|
||||
/obj/item/circuitboard/computer/robotics
|
||||
)
|
||||
@@ -0,0 +1,357 @@
|
||||
/*
|
||||
Because mapping is already tedious enough this spawner let you spawn generic
|
||||
"sets" of objects rather than having to make the same object stack again and
|
||||
again.
|
||||
*/
|
||||
|
||||
/obj/effect/spawner/structure
|
||||
name = "map structure spawner"
|
||||
var/list/spawn_list
|
||||
|
||||
/obj/effect/spawner/structure/Initialize()
|
||||
. = ..()
|
||||
if(spawn_list && spawn_list.len)
|
||||
for(var/I in spawn_list)
|
||||
new I(get_turf(src))
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
|
||||
//normal windows
|
||||
|
||||
/obj/effect/spawner/structure/window
|
||||
icon = 'icons/obj/structures_spawners.dmi'
|
||||
icon_state = "window_spawner"
|
||||
name = "window spawner"
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/fulltile)
|
||||
dir = SOUTH
|
||||
|
||||
/obj/effect/spawner/structure/window/hollow
|
||||
name = "hollow window spawner"
|
||||
icon_state = "hwindow_spawner_full"
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window, /obj/structure/window/spawner/north, /obj/structure/window/spawner/east, /obj/structure/window/spawner/west)
|
||||
|
||||
/obj/effect/spawner/structure/window/hollow/end
|
||||
icon_state = "hwindow_spawner_end"
|
||||
|
||||
/obj/effect/spawner/structure/window/hollow/end/Initialize()
|
||||
switch(dir)
|
||||
if(NORTH)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/spawner/north, /obj/structure/window/spawner/east, /obj/structure/window/spawner/west)
|
||||
if(EAST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window, /obj/structure/window/spawner/north, /obj/structure/window/spawner/east)
|
||||
if(SOUTH)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window, /obj/structure/window/spawner/east, /obj/structure/window/spawner/west)
|
||||
if(WEST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window, /obj/structure/window/spawner/north, /obj/structure/window/spawner/west)
|
||||
. = ..()
|
||||
|
||||
/obj/effect/spawner/structure/window/hollow/middle
|
||||
icon_state = "hwindow_spawner_middle"
|
||||
|
||||
/obj/effect/spawner/structure/window/hollow/middle/Initialize()
|
||||
switch(dir)
|
||||
if(NORTH,SOUTH)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window, /obj/structure/window/spawner/north)
|
||||
if(EAST,WEST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/spawner/east, /obj/structure/window/spawner/west)
|
||||
. = ..()
|
||||
|
||||
/obj/effect/spawner/structure/window/hollow/directional
|
||||
icon_state = "hwindow_spawner_directional"
|
||||
|
||||
/obj/effect/spawner/structure/window/hollow/directional/Initialize()
|
||||
switch(dir)
|
||||
if(NORTH)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/spawner/north)
|
||||
if(NORTHEAST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/spawner/north, /obj/structure/window/spawner/east)
|
||||
if(EAST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/spawner/east)
|
||||
if(SOUTHEAST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window, /obj/structure/window/spawner/east)
|
||||
if(SOUTH)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window)
|
||||
if(SOUTHWEST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window, /obj/structure/window/spawner/west)
|
||||
if(WEST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/spawner/west)
|
||||
if(NORTHWEST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/spawner/north, /obj/structure/window/spawner/west)
|
||||
. = ..()
|
||||
|
||||
//reinforced
|
||||
|
||||
/obj/effect/spawner/structure/window/reinforced
|
||||
name = "reinforced window spawner"
|
||||
icon_state = "rwindow_spawner"
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/reinforced/fulltile)
|
||||
|
||||
/obj/effect/spawner/structure/window/hollow/reinforced
|
||||
name = "hollow reinforced window spawner"
|
||||
icon_state = "hrwindow_spawner_full"
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/reinforced, /obj/structure/window/reinforced/spawner/north, /obj/structure/window/reinforced/spawner/east, /obj/structure/window/reinforced/spawner/west)
|
||||
|
||||
/obj/effect/spawner/structure/window/hollow/reinforced/end
|
||||
icon_state = "hrwindow_spawner_end"
|
||||
|
||||
/obj/effect/spawner/structure/window/hollow/reinforced/end/Initialize()
|
||||
switch(dir)
|
||||
if(NORTH)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/reinforced/spawner/north, /obj/structure/window/reinforced/spawner/east, /obj/structure/window/reinforced/spawner/west)
|
||||
if(EAST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/reinforced, /obj/structure/window/reinforced/spawner/north, /obj/structure/window/reinforced/spawner/east)
|
||||
if(SOUTH)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/reinforced, /obj/structure/window/reinforced/spawner/east, /obj/structure/window/reinforced/spawner/west)
|
||||
if(WEST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/reinforced, /obj/structure/window/reinforced/spawner/north, /obj/structure/window/reinforced/spawner/west)
|
||||
. = ..()
|
||||
|
||||
/obj/effect/spawner/structure/window/hollow/reinforced/middle
|
||||
icon_state = "hrwindow_spawner_middle"
|
||||
|
||||
/obj/effect/spawner/structure/window/hollow/reinforced/middle/Initialize()
|
||||
switch(dir)
|
||||
if(NORTH,SOUTH)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/reinforced, /obj/structure/window/reinforced/spawner/north)
|
||||
if(EAST,WEST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/reinforced/spawner/east, /obj/structure/window/reinforced/spawner/west)
|
||||
. = ..()
|
||||
|
||||
/obj/effect/spawner/structure/window/hollow/reinforced/directional
|
||||
icon_state = "hrwindow_spawner_directional"
|
||||
|
||||
/obj/effect/spawner/structure/window/hollow/reinforced/directional/Initialize()
|
||||
switch(dir)
|
||||
if(NORTH)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/reinforced/spawner/north)
|
||||
if(NORTHEAST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/reinforced/spawner/north, /obj/structure/window/reinforced/spawner/east)
|
||||
if(EAST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/reinforced/spawner/east)
|
||||
if(SOUTHEAST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/reinforced, /obj/structure/window/reinforced/spawner/east)
|
||||
if(SOUTH)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/reinforced)
|
||||
if(SOUTHWEST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/reinforced, /obj/structure/window/reinforced/spawner/west)
|
||||
if(WEST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/reinforced/spawner/west)
|
||||
if(NORTHWEST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/reinforced/spawner/north, /obj/structure/window/reinforced/spawner/west)
|
||||
. = ..()
|
||||
|
||||
//tinted
|
||||
|
||||
/obj/effect/spawner/structure/window/reinforced/tinted
|
||||
name = "tinted reinforced window spawner"
|
||||
icon_state = "twindow_spawner"
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/reinforced/tinted/fulltile)
|
||||
|
||||
|
||||
//shuttle window
|
||||
|
||||
/obj/effect/spawner/structure/window/shuttle
|
||||
name = "shuttle window spawner"
|
||||
icon_state = "swindow_spawner"
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/shuttle)
|
||||
|
||||
|
||||
//plastitanium window
|
||||
|
||||
/obj/effect/spawner/structure/window/plastitanium
|
||||
name = "plastitanium window spawner"
|
||||
icon_state = "plastitaniumwindow_spawner"
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/plastitanium)
|
||||
|
||||
|
||||
//ice window
|
||||
|
||||
/obj/effect/spawner/structure/window/ice
|
||||
name = "ice window spawner"
|
||||
icon_state = "icewindow_spawner"
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/reinforced/fulltile/ice)
|
||||
|
||||
|
||||
//survival pod window
|
||||
|
||||
/obj/effect/spawner/structure/window/survival_pod
|
||||
name = "pod window spawner"
|
||||
icon_state = "podwindow_spawner"
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/reinforced/survival_pod)
|
||||
|
||||
/obj/effect/spawner/structure/window/hollow/survival_pod
|
||||
name = "hollow pod window spawner"
|
||||
icon_state = "podwindow_spawner_full"
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/shuttle/survival_pod, /obj/structure/window/shuttle/survival_pod/spawner/north, /obj/structure/window/shuttle/survival_pod/spawner/east, /obj/structure/window/shuttle/survival_pod/spawner/west)
|
||||
|
||||
/obj/effect/spawner/structure/window/hollow/survival_pod/end
|
||||
icon_state = "podwindow_spawner_end"
|
||||
|
||||
/obj/effect/spawner/structure/window/hollow/survival_pod/end/Initialize()
|
||||
switch(dir)
|
||||
if(NORTH)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/shuttle/survival_pod/spawner/north, /obj/structure/window/shuttle/survival_pod/spawner/east, /obj/structure/window/shuttle/survival_pod/spawner/west)
|
||||
if(EAST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/shuttle/survival_pod, /obj/structure/window/shuttle/survival_pod/spawner/north, /obj/structure/window/shuttle/survival_pod/spawner/east)
|
||||
if(SOUTH)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/shuttle/survival_pod, /obj/structure/window/shuttle/survival_pod/spawner/east, /obj/structure/window/shuttle/survival_pod/spawner/west)
|
||||
if(WEST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/shuttle/survival_pod, /obj/structure/window/shuttle/survival_pod/spawner/north, /obj/structure/window/shuttle/survival_pod/spawner/west)
|
||||
. = ..()
|
||||
|
||||
/obj/effect/spawner/structure/window/hollow/survival_pod/middle
|
||||
icon_state = "podwindow_spawner_middle"
|
||||
|
||||
/obj/effect/spawner/structure/window/hollow/survival_pod/middle/Initialize()
|
||||
switch(dir)
|
||||
if(NORTH,SOUTH)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/shuttle/survival_pod, /obj/structure/window/shuttle/survival_pod/spawner/north)
|
||||
if(EAST,WEST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/shuttle/survival_pod/spawner/east, /obj/structure/window/shuttle/survival_pod/spawner/west)
|
||||
. = ..()
|
||||
|
||||
/obj/effect/spawner/structure/window/hollow/survival_pod/directional
|
||||
icon_state = "podwindow_spawner_directional"
|
||||
|
||||
/obj/effect/spawner/structure/window/hollow/survival_pod/directional/Initialize()
|
||||
switch(dir)
|
||||
if(NORTH)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/shuttle/survival_pod/spawner/north)
|
||||
if(NORTHEAST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/shuttle/survival_pod/spawner/north, /obj/structure/window/shuttle/survival_pod/spawner/east)
|
||||
if(EAST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/shuttle/survival_pod/spawner/east)
|
||||
if(SOUTHEAST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/shuttle/survival_pod, /obj/structure/window/shuttle/survival_pod/spawner/east)
|
||||
if(SOUTH)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/shuttle/survival_pod)
|
||||
if(SOUTHWEST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/shuttle/survival_pod, /obj/structure/window/shuttle/survival_pod/spawner/west)
|
||||
if(WEST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/shuttle/survival_pod/spawner/west)
|
||||
if(NORTHWEST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/shuttle/survival_pod/spawner/north, /obj/structure/window/shuttle/survival_pod/spawner/west)
|
||||
. = ..()
|
||||
|
||||
|
||||
//plasma windows
|
||||
|
||||
/obj/effect/spawner/structure/window/plasma
|
||||
name = "plasma window spawner"
|
||||
icon_state = "pwindow_spawner"
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/plasma/fulltile)
|
||||
|
||||
/obj/effect/spawner/structure/window/hollow/plasma
|
||||
name = "hollow plasma window spawner"
|
||||
icon_state = "phwindow_spawner_full"
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/plasma, /obj/structure/window/plasma/spawner/north, /obj/structure/window/plasma/spawner/east, /obj/structure/window/plasma/spawner/west)
|
||||
|
||||
/obj/effect/spawner/structure/window/hollow/plasma/end
|
||||
icon_state = "phwindow_spawner_end"
|
||||
|
||||
/obj/effect/spawner/structure/window/hollow/plasma/end/Initialize()
|
||||
switch(dir)
|
||||
if(NORTH)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/plasma/spawner/north, /obj/structure/window/plasma/spawner/east, /obj/structure/window/plasma/spawner/west)
|
||||
if(EAST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/plasma, /obj/structure/window/plasma/spawner/north, /obj/structure/window/plasma/spawner/east)
|
||||
if(SOUTH)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/plasma, /obj/structure/window/plasma/spawner/east, /obj/structure/window/plasma/spawner/west)
|
||||
if(WEST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/plasma, /obj/structure/window/plasma/spawner/north, /obj/structure/window/plasma/spawner/west)
|
||||
. = ..()
|
||||
|
||||
/obj/effect/spawner/structure/window/hollow/plasma/middle
|
||||
icon_state = "phwindow_spawner_middle"
|
||||
|
||||
/obj/effect/spawner/structure/window/hollow/plasma/middle/Initialize()
|
||||
switch(dir)
|
||||
if(NORTH,SOUTH)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/plasma, /obj/structure/window/plasma/spawner/north)
|
||||
if(EAST,WEST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/plasma/spawner/east, /obj/structure/window/plasma/spawner/west)
|
||||
. = ..()
|
||||
|
||||
/obj/effect/spawner/structure/window/hollow/plasma/directional
|
||||
icon_state = "phwindow_spawner_directional"
|
||||
|
||||
/obj/effect/spawner/structure/window/hollow/plasma/directional/Initialize()
|
||||
switch(dir)
|
||||
if(NORTH)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/plasma/spawner/north)
|
||||
if(NORTHEAST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/plasma/spawner/north, /obj/structure/window/plasma/spawner/east)
|
||||
if(EAST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/plasma/spawner/east)
|
||||
if(SOUTHEAST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/plasma, /obj/structure/window/plasma/spawner/east)
|
||||
if(SOUTH)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/plasma)
|
||||
if(SOUTHWEST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/plasma, /obj/structure/window/plasma/spawner/west)
|
||||
if(WEST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/plasma/spawner/west)
|
||||
if(NORTHWEST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/plasma/spawner/north, /obj/structure/window/plasma/spawner/west)
|
||||
. = ..()
|
||||
|
||||
//plasma reinforced
|
||||
|
||||
/obj/effect/spawner/structure/window/plasma/reinforced
|
||||
name = "reinforced plasma window spawner"
|
||||
icon_state = "prwindow_spawner"
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/plasma/reinforced/fulltile)
|
||||
|
||||
/obj/effect/spawner/structure/window/hollow/plasma/reinforced
|
||||
name = "hollow reinforced plasma window spawner"
|
||||
icon_state = "phrwindow_spawner_full"
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/plasma/reinforced, /obj/structure/window/plasma/reinforced/spawner/north, /obj/structure/window/plasma/reinforced/spawner/east, /obj/structure/window/plasma/reinforced/spawner/west)
|
||||
|
||||
/obj/effect/spawner/structure/window/hollow/plasma/reinforced/end
|
||||
icon_state = "phrwindow_spawner_end"
|
||||
|
||||
/obj/effect/spawner/structure/window/hollow/plasma/reinforced/end/Initialize()
|
||||
switch(dir)
|
||||
if(NORTH)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/plasma/reinforced/spawner/north, /obj/structure/window/plasma/reinforced/spawner/east, /obj/structure/window/plasma/reinforced/spawner/west)
|
||||
if(EAST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/plasma/reinforced, /obj/structure/window/plasma/reinforced/spawner/north, /obj/structure/window/plasma/reinforced/spawner/east)
|
||||
if(SOUTH)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/plasma/reinforced, /obj/structure/window/plasma/reinforced/spawner/east, /obj/structure/window/plasma/reinforced/spawner/west)
|
||||
if(WEST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/plasma/reinforced, /obj/structure/window/plasma/reinforced/spawner/north, /obj/structure/window/plasma/reinforced/spawner/west)
|
||||
. = ..()
|
||||
|
||||
/obj/effect/spawner/structure/window/hollow/plasma/reinforced/middle
|
||||
icon_state = "phrwindow_spawner_middle"
|
||||
|
||||
/obj/effect/spawner/structure/window/hollow/plasma/reinforced/middle/Initialize()
|
||||
switch(dir)
|
||||
if(NORTH,SOUTH)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/plasma/reinforced, /obj/structure/window/plasma/reinforced/spawner/north)
|
||||
if(EAST,WEST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/plasma/reinforced/spawner/east, /obj/structure/window/plasma/reinforced/spawner/west)
|
||||
. = ..()
|
||||
|
||||
/obj/effect/spawner/structure/window/hollow/plasma/reinforced/directional
|
||||
icon_state = "phrwindow_spawner_directional"
|
||||
|
||||
/obj/effect/spawner/structure/window/hollow/plasma/reinforced/directional/Initialize()
|
||||
switch(dir)
|
||||
if(NORTH)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/plasma/reinforced/spawner/north)
|
||||
if(NORTHEAST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/plasma/reinforced/spawner/north, /obj/structure/window/plasma/reinforced/spawner/east)
|
||||
if(EAST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/plasma/reinforced/spawner/east)
|
||||
if(SOUTHEAST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/plasma/reinforced, /obj/structure/window/plasma/reinforced/spawner/east)
|
||||
if(SOUTH)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/plasma/reinforced)
|
||||
if(SOUTHWEST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/plasma/reinforced, /obj/structure/window/plasma/reinforced/spawner/west)
|
||||
if(WEST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/plasma/reinforced/spawner/west)
|
||||
if(NORTHWEST)
|
||||
spawn_list = list(/obj/structure/grille, /obj/structure/window/plasma/reinforced/spawner/north, /obj/structure/window/plasma/reinforced/spawner/west)
|
||||
. = ..()
|
||||
@@ -0,0 +1,10 @@
|
||||
/obj/effect/spawner/trap
|
||||
name = "random trap"
|
||||
icon = 'icons/obj/hand_of_god_structures.dmi'
|
||||
icon_state = "trap_rand"
|
||||
|
||||
/obj/effect/spawner/trap/Initialize(mapload)
|
||||
..()
|
||||
var/new_type = pick(subtypesof(/obj/structure/trap) - typesof(/obj/structure/trap/ctf))
|
||||
new new_type(get_turf(src))
|
||||
return INITIALIZE_HINT_QDEL
|
||||
@@ -0,0 +1,28 @@
|
||||
/obj/effect/vaultspawner
|
||||
var/maxX = 6
|
||||
var/maxY = 6
|
||||
var/minX = 2
|
||||
var/minY = 2
|
||||
|
||||
/obj/effect/vaultspawner/New(turf/location,lX = minX,uX = maxX,lY = minY,uY = maxY,type = null)
|
||||
if(!type)
|
||||
type = pick("sandstone","rock","alien")
|
||||
|
||||
var/lowBoundX = location.x
|
||||
var/lowBoundY = location.y
|
||||
|
||||
var/hiBoundX = location.x + rand(lX,uX)
|
||||
var/hiBoundY = location.y + rand(lY,uY)
|
||||
|
||||
var/z = location.z
|
||||
|
||||
for(var/i = lowBoundX,i<=hiBoundX,i++)
|
||||
for(var/j = lowBoundY,j<=hiBoundY,j++)
|
||||
var/turf/T = locate(i,j,z)
|
||||
if(i == lowBoundX || i == hiBoundX || j == lowBoundY || j == hiBoundY)
|
||||
T.PlaceOnTop(/turf/closed/wall/vault)
|
||||
else
|
||||
T.PlaceOnTop(/turf/open/floor/vault)
|
||||
T.icon_state = "[type]vault"
|
||||
|
||||
qdel(src)
|
||||
@@ -0,0 +1,19 @@
|
||||
/obj/effect/spawner/xeno_egg_delivery
|
||||
name = "xeno egg delivery"
|
||||
icon = 'icons/mob/alien.dmi'
|
||||
icon_state = "egg_growing"
|
||||
var/announcement_time = 1200
|
||||
|
||||
/obj/effect/spawner/xeno_egg_delivery/Initialize(mapload)
|
||||
..()
|
||||
var/turf/T = get_turf(src)
|
||||
|
||||
new /obj/structure/alien/egg(T)
|
||||
new /obj/effect/temp_visual/gravpush(T)
|
||||
playsound(T, 'sound/items/party_horn.ogg', 50, 1, -1)
|
||||
|
||||
message_admins("An alien egg has been delivered to [ADMIN_VERBOSEJMP(T)].")
|
||||
log_game("An alien egg has been delivered to [AREACOORD(T)]")
|
||||
var/message = "Attention [station_name()], we have entrusted you with a research specimen in [get_area_name(T, TRUE)]. Remember to follow all safety precautions when dealing with the specimen."
|
||||
SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, /proc/addtimer, CALLBACK(GLOBAL_PROC, /proc/print_command_report, message), announcement_time))
|
||||
return INITIALIZE_HINT_QDEL
|
||||
@@ -0,0 +1,237 @@
|
||||
//generic procs copied from obj/effect/alien
|
||||
/obj/structure/spider
|
||||
name = "web"
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
desc = "It's stringy and sticky."
|
||||
anchored = TRUE
|
||||
density = FALSE
|
||||
max_integrity = 15
|
||||
|
||||
|
||||
|
||||
/obj/structure/spider/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
|
||||
if(damage_type == BURN)//the stickiness of the web mutes all attack sounds except fire damage type
|
||||
playsound(loc, 'sound/items/welder.ogg', 100, 1)
|
||||
|
||||
|
||||
/obj/structure/spider/run_obj_armor(damage_amount, damage_type, damage_flag = 0, attack_dir)
|
||||
if(damage_flag == "melee")
|
||||
switch(damage_type)
|
||||
if(BURN)
|
||||
damage_amount *= 2
|
||||
if(BRUTE)
|
||||
damage_amount *= 0.25
|
||||
. = ..()
|
||||
|
||||
/obj/structure/spider/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
|
||||
if(exposed_temperature > 300)
|
||||
take_damage(5, BURN, 0, 0)
|
||||
|
||||
/obj/structure/spider/stickyweb
|
||||
icon_state = "stickyweb1"
|
||||
|
||||
/obj/structure/spider/stickyweb/Initialize()
|
||||
if(prob(50))
|
||||
icon_state = "stickyweb2"
|
||||
. = ..()
|
||||
|
||||
/obj/structure/spider/stickyweb/CanPass(atom/movable/mover, turf/target)
|
||||
if(istype(mover, /mob/living/simple_animal/hostile/poison/giant_spider))
|
||||
return TRUE
|
||||
else if(isliving(mover))
|
||||
if(istype(mover.pulledby, /mob/living/simple_animal/hostile/poison/giant_spider))
|
||||
return TRUE
|
||||
if(prob(50))
|
||||
to_chat(mover, "<span class='danger'>You get stuck in \the [src] for a moment.</span>")
|
||||
return FALSE
|
||||
else if(istype(mover, /obj/item/projectile))
|
||||
return prob(30)
|
||||
return TRUE
|
||||
|
||||
/obj/structure/spider/eggcluster
|
||||
name = "egg cluster"
|
||||
desc = "They seem to pulse slightly with an inner life."
|
||||
icon_state = "eggs"
|
||||
var/amount_grown = 0
|
||||
var/player_spiders = 0
|
||||
var/directive = "" //Message from the mother
|
||||
var/poison_type = "toxin"
|
||||
var/poison_per_bite = 5
|
||||
var/list/faction = list("spiders")
|
||||
|
||||
/obj/structure/spider/eggcluster/Initialize()
|
||||
pixel_x = rand(3,-3)
|
||||
pixel_y = rand(3,-3)
|
||||
START_PROCESSING(SSobj, src)
|
||||
. = ..()
|
||||
|
||||
/obj/structure/spider/eggcluster/process()
|
||||
amount_grown += rand(0,2)
|
||||
if(amount_grown >= 100)
|
||||
var/num = rand(3,12)
|
||||
for(var/i=0, i<num, i++)
|
||||
var/obj/structure/spider/spiderling/S = new /obj/structure/spider/spiderling(src.loc)
|
||||
S.poison_type = poison_type
|
||||
S.poison_per_bite = poison_per_bite
|
||||
S.faction = faction.Copy()
|
||||
S.directive = directive
|
||||
if(player_spiders)
|
||||
S.player_spiders = 1
|
||||
qdel(src)
|
||||
|
||||
/obj/structure/spider/spiderling
|
||||
name = "spiderling"
|
||||
desc = "It never stays still for long."
|
||||
icon_state = "spiderling"
|
||||
anchored = FALSE
|
||||
layer = PROJECTILE_HIT_THRESHHOLD_LAYER
|
||||
max_integrity = 3
|
||||
var/amount_grown = 0
|
||||
var/grow_as = null
|
||||
var/obj/machinery/atmospherics/components/unary/vent_pump/entry_vent
|
||||
var/travelling_in_vent = 0
|
||||
var/player_spiders = 0
|
||||
var/directive = "" //Message from the mother
|
||||
var/poison_type = "toxin"
|
||||
var/poison_per_bite = 5
|
||||
var/list/faction = list("spiders")
|
||||
|
||||
/obj/structure/spider/spiderling/Destroy()
|
||||
new/obj/item/reagent_containers/food/snacks/spiderling(get_turf(src))
|
||||
. = ..()
|
||||
|
||||
/obj/structure/spider/spiderling/Initialize()
|
||||
. = ..()
|
||||
pixel_x = rand(6,-6)
|
||||
pixel_y = rand(6,-6)
|
||||
START_PROCESSING(SSobj, src)
|
||||
AddComponent(/datum/component/swarming)
|
||||
|
||||
/obj/structure/spider/spiderling/hunter
|
||||
grow_as = /mob/living/simple_animal/hostile/poison/giant_spider/hunter
|
||||
|
||||
/obj/structure/spider/spiderling/nurse
|
||||
grow_as = /mob/living/simple_animal/hostile/poison/giant_spider/nurse
|
||||
|
||||
/obj/structure/spider/spiderling/midwife
|
||||
grow_as = /mob/living/simple_animal/hostile/poison/giant_spider/nurse/midwife
|
||||
|
||||
/obj/structure/spider/spiderling/viper
|
||||
grow_as = /mob/living/simple_animal/hostile/poison/giant_spider/hunter/viper
|
||||
|
||||
/obj/structure/spider/spiderling/tarantula
|
||||
grow_as = /mob/living/simple_animal/hostile/poison/giant_spider/tarantula
|
||||
|
||||
/obj/structure/spider/spiderling/Bump(atom/user)
|
||||
if(istype(user, /obj/structure/table))
|
||||
forceMove(user.loc)
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/structure/spider/spiderling/process()
|
||||
if(travelling_in_vent)
|
||||
if(isturf(loc))
|
||||
travelling_in_vent = 0
|
||||
entry_vent = null
|
||||
else if(entry_vent)
|
||||
if(get_dist(src, entry_vent) <= 1)
|
||||
var/list/vents = list()
|
||||
var/datum/pipeline/entry_vent_parent = entry_vent.parents[1]
|
||||
for(var/obj/machinery/atmospherics/components/unary/vent_pump/temp_vent in entry_vent_parent.other_atmosmch)
|
||||
vents.Add(temp_vent)
|
||||
if(!vents.len)
|
||||
entry_vent = null
|
||||
return
|
||||
var/obj/machinery/atmospherics/components/unary/vent_pump/exit_vent = pick(vents)
|
||||
if(prob(50))
|
||||
visible_message("<B>[src] scrambles into the ventilation ducts!</B>", \
|
||||
"<span class='italics'>You hear something scampering through the ventilation ducts.</span>")
|
||||
|
||||
spawn(rand(20,60))
|
||||
forceMove(exit_vent)
|
||||
var/travel_time = round(get_dist(loc, exit_vent.loc) / 2)
|
||||
spawn(travel_time)
|
||||
|
||||
if(!exit_vent || exit_vent.welded)
|
||||
forceMove(entry_vent)
|
||||
entry_vent = null
|
||||
return
|
||||
|
||||
if(prob(50))
|
||||
audible_message("<span class='italics'>You hear something scampering through the ventilation ducts.</span>")
|
||||
sleep(travel_time)
|
||||
|
||||
if(!exit_vent || exit_vent.welded)
|
||||
forceMove(entry_vent)
|
||||
entry_vent = null
|
||||
return
|
||||
forceMove(exit_vent.loc)
|
||||
entry_vent = null
|
||||
var/area/new_area = get_area(loc)
|
||||
if(new_area)
|
||||
new_area.Entered(src)
|
||||
//=================
|
||||
|
||||
else if(prob(33))
|
||||
var/list/nearby = oview(10, src)
|
||||
if(nearby.len)
|
||||
var/target_atom = pick(nearby)
|
||||
walk_to(src, target_atom)
|
||||
if(prob(40))
|
||||
src.visible_message("<span class='notice'>\The [src] skitters[pick(" away"," around","")].</span>")
|
||||
else if(prob(10))
|
||||
//ventcrawl!
|
||||
for(var/obj/machinery/atmospherics/components/unary/vent_pump/v in view(7,src))
|
||||
if(!v.welded)
|
||||
entry_vent = v
|
||||
walk_to(src, entry_vent, 1)
|
||||
break
|
||||
if(isturf(loc))
|
||||
amount_grown += rand(0,2)
|
||||
if(amount_grown >= 100)
|
||||
if(!grow_as)
|
||||
if(prob(3))
|
||||
grow_as = pick(/mob/living/simple_animal/hostile/poison/giant_spider/tarantula, /mob/living/simple_animal/hostile/poison/giant_spider/hunter/viper, /mob/living/simple_animal/hostile/poison/giant_spider/nurse/midwife)
|
||||
else
|
||||
grow_as = pick(/mob/living/simple_animal/hostile/poison/giant_spider, /mob/living/simple_animal/hostile/poison/giant_spider/hunter, /mob/living/simple_animal/hostile/poison/giant_spider/nurse)
|
||||
var/mob/living/simple_animal/hostile/poison/giant_spider/S = new grow_as(src.loc)
|
||||
S.poison_per_bite = poison_per_bite
|
||||
S.poison_type = poison_type
|
||||
S.faction = faction.Copy()
|
||||
S.directive = directive
|
||||
if(player_spiders)
|
||||
S.playable_spider = TRUE
|
||||
notify_ghosts("Spider [S.name] can be controlled", null, enter_link="<a href=?src=[REF(S)];activate=1>(Click to play)</a>", source=S, action=NOTIFY_ATTACK, ignore_key = POLL_IGNORE_SPIDER)
|
||||
qdel(src)
|
||||
|
||||
|
||||
|
||||
/obj/structure/spider/cocoon
|
||||
name = "cocoon"
|
||||
desc = "Something wrapped in silky spider web."
|
||||
icon_state = "cocoon1"
|
||||
max_integrity = 60
|
||||
|
||||
/obj/structure/spider/cocoon/Initialize()
|
||||
icon_state = pick("cocoon1","cocoon2","cocoon3")
|
||||
. = ..()
|
||||
|
||||
/obj/structure/spider/cocoon/container_resist(mob/living/user)
|
||||
var/breakout_time = 600
|
||||
user.changeNext_move(CLICK_CD_BREAKOUT)
|
||||
user.last_special = world.time + CLICK_CD_BREAKOUT
|
||||
to_chat(user, "<span class='notice'>You struggle against the tight bonds... (This will take about [DisplayTimeText(breakout_time)].)</span>")
|
||||
visible_message("You see something struggling and writhing in \the [src]!")
|
||||
if(do_after(user,(breakout_time), target = src))
|
||||
if(!user || user.stat != CONSCIOUS || user.loc != src)
|
||||
return
|
||||
qdel(src)
|
||||
|
||||
|
||||
|
||||
/obj/structure/spider/cocoon/Destroy()
|
||||
var/turf/T = get_turf(src)
|
||||
src.visible_message("<span class='warning'>\The [src] splits open.</span>")
|
||||
for(var/atom/movable/A in contents)
|
||||
A.forceMove(T)
|
||||
return ..()
|
||||
@@ -0,0 +1,199 @@
|
||||
/* Simple object type, calls a proc when "stepped" on by something */
|
||||
|
||||
/obj/effect/step_trigger
|
||||
var/affect_ghosts = 0
|
||||
var/stopper = 1 // stops throwers
|
||||
var/mobs_only = FALSE
|
||||
invisibility = INVISIBILITY_ABSTRACT // nope cant see this shit
|
||||
anchored = TRUE
|
||||
|
||||
/obj/effect/step_trigger/proc/Trigger(atom/movable/A)
|
||||
return 0
|
||||
|
||||
/obj/effect/step_trigger/Crossed(H as mob|obj)
|
||||
..()
|
||||
if(!H)
|
||||
return
|
||||
if(isobserver(H) && !affect_ghosts)
|
||||
return
|
||||
if(!ismob(H) && mobs_only)
|
||||
return
|
||||
Trigger(H)
|
||||
|
||||
|
||||
/obj/effect/step_trigger/singularity_act()
|
||||
return
|
||||
|
||||
/obj/effect/step_trigger/singularity_pull()
|
||||
return
|
||||
|
||||
/* Sends a message to mob when triggered*/
|
||||
|
||||
/obj/effect/step_trigger/message
|
||||
var/message //the message to give to the mob
|
||||
var/once = 1
|
||||
mobs_only = TRUE
|
||||
|
||||
/obj/effect/step_trigger/message/Trigger(mob/M)
|
||||
if(M.client)
|
||||
to_chat(M, "<span class='info'>[message]</span>")
|
||||
if(once)
|
||||
qdel(src)
|
||||
|
||||
/* Tosses things in a certain direction */
|
||||
|
||||
/obj/effect/step_trigger/thrower
|
||||
var/direction = SOUTH // the direction of throw
|
||||
var/tiles = 3 // if 0: forever until atom hits a stopper
|
||||
var/immobilize = 1 // if nonzero: prevents mobs from moving while they're being flung
|
||||
var/speed = 1 // delay of movement
|
||||
var/facedir = 0 // if 1: atom faces the direction of movement
|
||||
var/nostop = 0 // if 1: will only be stopped by teleporters
|
||||
var/list/affecting = list()
|
||||
|
||||
/obj/effect/step_trigger/thrower/Trigger(atom/A)
|
||||
if(!A || !ismovableatom(A))
|
||||
return
|
||||
var/atom/movable/AM = A
|
||||
var/curtiles = 0
|
||||
var/stopthrow = 0
|
||||
for(var/obj/effect/step_trigger/thrower/T in orange(2, src))
|
||||
if(AM in T.affecting)
|
||||
return
|
||||
|
||||
if(ismob(AM))
|
||||
var/mob/M = AM
|
||||
if(immobilize)
|
||||
M.canmove = 0
|
||||
|
||||
affecting.Add(AM)
|
||||
while(AM && !stopthrow)
|
||||
if(tiles)
|
||||
if(curtiles >= tiles)
|
||||
break
|
||||
if(AM.z != src.z)
|
||||
break
|
||||
|
||||
curtiles++
|
||||
|
||||
sleep(speed)
|
||||
|
||||
// Calculate if we should stop the process
|
||||
if(!nostop)
|
||||
for(var/obj/effect/step_trigger/T in get_step(AM, direction))
|
||||
if(T.stopper && T != src)
|
||||
stopthrow = 1
|
||||
else
|
||||
for(var/obj/effect/step_trigger/teleporter/T in get_step(AM, direction))
|
||||
if(T.stopper)
|
||||
stopthrow = 1
|
||||
|
||||
if(AM)
|
||||
var/predir = AM.dir
|
||||
step(AM, direction)
|
||||
if(!facedir)
|
||||
AM.setDir(predir)
|
||||
|
||||
|
||||
|
||||
affecting.Remove(AM)
|
||||
|
||||
if(ismob(AM))
|
||||
var/mob/M = AM
|
||||
if(immobilize)
|
||||
M.canmove = 1
|
||||
|
||||
/* Stops things thrown by a thrower, doesn't do anything */
|
||||
|
||||
/obj/effect/step_trigger/stopper
|
||||
|
||||
/* Instant teleporter */
|
||||
|
||||
/obj/effect/step_trigger/teleporter
|
||||
var/teleport_x = 0 // teleportation coordinates (if one is null, then no teleport!)
|
||||
var/teleport_y = 0
|
||||
var/teleport_z = 0
|
||||
|
||||
/obj/effect/step_trigger/teleporter/Trigger(atom/movable/A)
|
||||
if(teleport_x && teleport_y && teleport_z)
|
||||
|
||||
var/turf/T = locate(teleport_x, teleport_y, teleport_z)
|
||||
A.forceMove(T)
|
||||
|
||||
/* Random teleporter, teleports atoms to locations ranging from teleport_x - teleport_x_offset, etc */
|
||||
|
||||
/obj/effect/step_trigger/teleporter/random
|
||||
var/teleport_x_offset = 0
|
||||
var/teleport_y_offset = 0
|
||||
var/teleport_z_offset = 0
|
||||
|
||||
/obj/effect/step_trigger/teleporter/random/Trigger(atom/movable/A)
|
||||
if(teleport_x && teleport_y && teleport_z)
|
||||
if(teleport_x_offset && teleport_y_offset && teleport_z_offset)
|
||||
|
||||
var/turf/T = locate(rand(teleport_x, teleport_x_offset), rand(teleport_y, teleport_y_offset), rand(teleport_z, teleport_z_offset))
|
||||
if (T)
|
||||
A.forceMove(T)
|
||||
|
||||
/* Fancy teleporter, creates sparks and smokes when used */
|
||||
|
||||
/obj/effect/step_trigger/teleport_fancy
|
||||
var/locationx
|
||||
var/locationy
|
||||
var/uses = 1 //0 for infinite uses
|
||||
var/entersparks = 0
|
||||
var/exitsparks = 0
|
||||
var/entersmoke = 0
|
||||
var/exitsmoke = 0
|
||||
|
||||
/obj/effect/step_trigger/teleport_fancy/Trigger(mob/M)
|
||||
var/dest = locate(locationx, locationy, z)
|
||||
M.Move(dest)
|
||||
|
||||
if(entersparks)
|
||||
var/datum/effect_system/spark_spread/s = new
|
||||
s.set_up(4, 1, src)
|
||||
s.start()
|
||||
if(exitsparks)
|
||||
var/datum/effect_system/spark_spread/s = new
|
||||
s.set_up(4, 1, dest)
|
||||
s.start()
|
||||
|
||||
if(entersmoke)
|
||||
var/datum/effect_system/smoke_spread/s = new
|
||||
s.set_up(4, 1, src, 0)
|
||||
s.start()
|
||||
if(exitsmoke)
|
||||
var/datum/effect_system/smoke_spread/s = new
|
||||
s.set_up(4, 1, dest, 0)
|
||||
s.start()
|
||||
|
||||
uses--
|
||||
if(uses == 0)
|
||||
qdel(src)
|
||||
|
||||
/* Simple sound player, Mapper friendly! */
|
||||
|
||||
/obj/effect/step_trigger/sound_effect
|
||||
var/sound //eg. path to the sound, inside '' eg: 'growl.ogg'
|
||||
var/volume = 100
|
||||
var/freq_vary = 1 //Should the frequency of the sound vary?
|
||||
var/extra_range = 0 // eg World.view = 7, extra_range = 1, 7+1 = 8, 8 turfs radius
|
||||
var/happens_once = 0
|
||||
var/triggerer_only = 0 //Whether the triggerer is the only person who hears this
|
||||
|
||||
|
||||
/obj/effect/step_trigger/sound_effect/Trigger(atom/movable/A)
|
||||
var/turf/T = get_turf(A)
|
||||
|
||||
if(!T)
|
||||
return
|
||||
|
||||
if(triggerer_only && ismob(A))
|
||||
var/mob/B = A
|
||||
B.playsound_local(T, sound, volume, freq_vary)
|
||||
else
|
||||
playsound(T, sound, volume, freq_vary, extra_range)
|
||||
|
||||
if(happens_once)
|
||||
qdel(src)
|
||||
@@ -0,0 +1,269 @@
|
||||
//temporary visual effects(/obj/effect/temp_visual) used by clockcult stuff
|
||||
/obj/effect/temp_visual/ratvar
|
||||
name = "ratvar's light"
|
||||
icon = 'icons/effects/clockwork_effects.dmi'
|
||||
duration = 8
|
||||
randomdir = 0
|
||||
layer = ABOVE_NORMAL_TURF_LAYER
|
||||
|
||||
/obj/effect/temp_visual/ratvar/door
|
||||
icon_state = "ratvardoorglow"
|
||||
layer = CLOSED_DOOR_LAYER //above closed doors
|
||||
|
||||
/obj/effect/temp_visual/ratvar/door/window
|
||||
icon_state = "ratvarwindoorglow"
|
||||
layer = ABOVE_WINDOW_LAYER
|
||||
|
||||
/obj/effect/temp_visual/ratvar/beam
|
||||
icon_state = "ratvarbeamglow"
|
||||
|
||||
/obj/effect/temp_visual/ratvar/beam/door
|
||||
layer = CLOSED_DOOR_LAYER
|
||||
|
||||
/obj/effect/temp_visual/ratvar/beam/grille
|
||||
layer = BELOW_OBJ_LAYER
|
||||
|
||||
/obj/effect/temp_visual/ratvar/beam/itemconsume
|
||||
layer = HIGH_OBJ_LAYER
|
||||
|
||||
/obj/effect/temp_visual/ratvar/beam/falsewall
|
||||
layer = OBJ_LAYER
|
||||
|
||||
/obj/effect/temp_visual/ratvar/beam/catwalk
|
||||
layer = LATTICE_LAYER
|
||||
|
||||
/obj/effect/temp_visual/ratvar/wall
|
||||
icon_state = "ratvarwallglow"
|
||||
|
||||
/obj/effect/temp_visual/ratvar/wall/false
|
||||
layer = OBJ_LAYER
|
||||
|
||||
/obj/effect/temp_visual/ratvar/floor
|
||||
icon_state = "ratvarfloorglow"
|
||||
|
||||
/obj/effect/temp_visual/ratvar/floor/catwalk
|
||||
layer = LATTICE_LAYER
|
||||
|
||||
/obj/effect/temp_visual/ratvar/window
|
||||
icon_state = "ratvarwindowglow"
|
||||
layer = ABOVE_OBJ_LAYER
|
||||
|
||||
/obj/effect/temp_visual/ratvar/window/single
|
||||
icon_state = "ratvarwindowglow_s"
|
||||
|
||||
/obj/effect/temp_visual/ratvar/gear
|
||||
icon_state = "ratvargearglow"
|
||||
layer = BELOW_OBJ_LAYER
|
||||
|
||||
/obj/effect/temp_visual/ratvar/grille
|
||||
icon_state = "ratvargrilleglow"
|
||||
layer = BELOW_OBJ_LAYER
|
||||
|
||||
/obj/effect/temp_visual/ratvar/grille/broken
|
||||
icon_state = "ratvarbrokengrilleglow"
|
||||
|
||||
/obj/effect/temp_visual/ratvar/belligerent
|
||||
layer = ABOVE_MOB_LAYER
|
||||
icon = 'icons/obj/clockwork_objects.dmi'
|
||||
icon_state = "belligerent_eye"
|
||||
pixel_y = 20
|
||||
duration = 20
|
||||
|
||||
/obj/effect/temp_visual/ratvar/belligerent_cast/Initialize()
|
||||
. = ..()
|
||||
animate(src, alpha = 0, time = duration, easing = EASE_OUT)
|
||||
|
||||
/obj/effect/temp_visual/ratvar/mending_mantra
|
||||
layer = ABOVE_MOB_LAYER
|
||||
duration = 20
|
||||
alpha = 200
|
||||
icon_state = "mending_mantra"
|
||||
light_range = 1.5
|
||||
light_color = "#1E8CE1"
|
||||
|
||||
/obj/effect/temp_visual/ratvar/mending_mantra/Initialize(mapload)
|
||||
. = ..()
|
||||
transform = matrix()*2
|
||||
var/matrix/M = transform
|
||||
M.Turn(90)
|
||||
animate(src, alpha = 20, time = duration, easing = BOUNCE_EASING, flags = ANIMATION_PARALLEL)
|
||||
animate(src, transform = M, time = duration, flags = ANIMATION_PARALLEL)
|
||||
|
||||
/obj/effect/temp_visual/ratvar/ocular_warden
|
||||
name = "warden's gaze"
|
||||
layer = ABOVE_MOB_LAYER
|
||||
icon_state = "warden_gaze"
|
||||
duration = 3
|
||||
|
||||
/obj/effect/temp_visual/ratvar/ocular_warden/Initialize()
|
||||
. = ..()
|
||||
pixel_x = rand(-8, 8)
|
||||
pixel_y = rand(-10, 10)
|
||||
animate(src, alpha = 0, time = duration, easing = EASE_OUT)
|
||||
|
||||
/obj/effect/temp_visual/ratvar/prolonging_prism
|
||||
icon = 'icons/effects/64x64.dmi'
|
||||
icon_state = "prismhex1"
|
||||
layer = RIPPLE_LAYER
|
||||
pixel_y = -16
|
||||
pixel_x = -16
|
||||
duration = 30
|
||||
|
||||
/obj/effect/temp_visual/ratvar/prolonging_prism/Initialize(mapload, set_appearance)
|
||||
. = ..()
|
||||
if(set_appearance)
|
||||
appearance = set_appearance
|
||||
animate(src, alpha = 0, time = duration, easing = BOUNCE_EASING)
|
||||
|
||||
/obj/effect/temp_visual/ratvar/spearbreak
|
||||
icon = 'icons/effects/64x64.dmi'
|
||||
icon_state = "ratvarspearbreak"
|
||||
layer = BELOW_MOB_LAYER
|
||||
pixel_y = -16
|
||||
pixel_x = -16
|
||||
|
||||
/obj/effect/temp_visual/ratvar/geis_binding
|
||||
icon_state = "geisbinding"
|
||||
|
||||
/obj/effect/temp_visual/ratvar/geis_binding/top
|
||||
icon_state = "geisbinding_top"
|
||||
|
||||
/obj/effect/temp_visual/ratvar/component
|
||||
icon = 'icons/obj/clockwork_objects.dmi'
|
||||
icon_state = "belligerent_eye"
|
||||
layer = ABOVE_MOB_LAYER
|
||||
duration = 10
|
||||
|
||||
/obj/effect/temp_visual/ratvar/component/Initialize()
|
||||
. = ..()
|
||||
transform = matrix()*0.75
|
||||
pixel_x = rand(-10, 10)
|
||||
pixel_y = rand(-10, -2)
|
||||
animate(src, pixel_y = pixel_y + 10, alpha = 50, time = 10, easing = EASE_OUT)
|
||||
|
||||
/obj/effect/temp_visual/ratvar/component/cogwheel
|
||||
icon_state = "vanguard_cogwheel"
|
||||
|
||||
/obj/effect/temp_visual/ratvar/component/capacitor
|
||||
icon_state = "geis_capacitor"
|
||||
|
||||
/obj/effect/temp_visual/ratvar/component/alloy
|
||||
icon_state = "replicant_alloy"
|
||||
|
||||
/obj/effect/temp_visual/ratvar/component/ansible
|
||||
icon_state = "hierophant_ansible"
|
||||
|
||||
/obj/effect/temp_visual/ratvar/sigil
|
||||
name = "glowing circle"
|
||||
icon_state = "sigildull"
|
||||
|
||||
/obj/effect/temp_visual/ratvar/sigil/transgression
|
||||
color = "#FAE48C"
|
||||
layer = ABOVE_MOB_LAYER
|
||||
duration = 70
|
||||
light_range = 5
|
||||
light_power = 2
|
||||
light_color = "#FAE48C"
|
||||
|
||||
/obj/effect/temp_visual/ratvar/sigil/transgression/Initialize()
|
||||
. = ..()
|
||||
var/oldtransform = transform
|
||||
animate(src, transform = matrix()*2, time = 5)
|
||||
animate(transform = oldtransform, alpha = 0, time = 65)
|
||||
|
||||
/obj/effect/temp_visual/ratvar/sigil/transmission
|
||||
color = "#EC8A2D"
|
||||
layer = ABOVE_MOB_LAYER
|
||||
duration = 20
|
||||
light_range = 3
|
||||
light_power = 1
|
||||
light_color = "#EC8A2D"
|
||||
|
||||
/obj/effect/temp_visual/ratvar/sigil/transmission/Initialize(mapload, transform_multiplier)
|
||||
. = ..()
|
||||
var/oldtransform = transform
|
||||
transform = matrix()*transform_multiplier
|
||||
animate(src, transform = oldtransform, alpha = 0, time = 20)
|
||||
|
||||
/obj/effect/temp_visual/ratvar/sigil/vitality
|
||||
color = "#1E8CE1"
|
||||
icon_state = "sigilactivepulse"
|
||||
layer = ABOVE_MOB_LAYER
|
||||
light_range = 1.4
|
||||
light_power = 0.5
|
||||
light_color = "#1E8CE1"
|
||||
|
||||
/obj/effect/temp_visual/ratvar/sigil/submission
|
||||
color = "#AF0AAF"
|
||||
layer = ABOVE_MOB_LAYER
|
||||
duration = 80
|
||||
icon_state = "sigilactiveoverlay"
|
||||
alpha = 0
|
||||
|
||||
/obj/effect/temp_visual/steam
|
||||
name = "steam"
|
||||
desc = "Steam! It's hot. It also serves as a game distribution platform."
|
||||
icon_state = "smoke"
|
||||
duration = 15
|
||||
|
||||
/obj/effect/temp_visual/steam/Initialize(mapload, steam_direction)
|
||||
. = ..()
|
||||
setDir(steam_direction)
|
||||
var/x_offset = 0
|
||||
var/y_offset = 0
|
||||
switch(dir)
|
||||
if(NORTH)
|
||||
y_offset = 8
|
||||
if(EAST)
|
||||
x_offset = 4
|
||||
y_offset = 4
|
||||
if(SOUTH)
|
||||
y_offset = 2
|
||||
if(WEST)
|
||||
x_offset = -4
|
||||
y_offset = 4
|
||||
animate(src, pixel_x = x_offset, pixel_y = y_offset, alpha = 50, time = 15)
|
||||
|
||||
/obj/effect/temp_visual/steam_release
|
||||
name = "all the steam"
|
||||
|
||||
/obj/effect/temp_visual/steam_release/Initialize()
|
||||
..()
|
||||
for(var/V in GLOB.cardinals)
|
||||
var/turf/T = get_step(src, V)
|
||||
new/obj/effect/temp_visual/steam(T, V)
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
//Foreshadows a servant warping in.
|
||||
/obj/effect/temp_visual/ratvar/warp_marker
|
||||
name = "illuminant marker"
|
||||
desc = "A silhouette of dim light. It's getting brighter!"
|
||||
resistance_flags = INDESTRUCTIBLE
|
||||
icon = 'icons/effects/genetics.dmi'
|
||||
icon_state = "servitude"
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
anchored = TRUE
|
||||
alpha = 0
|
||||
light_color = "#FFE48E"
|
||||
light_range = 2
|
||||
light_power = 0.7
|
||||
duration = 55
|
||||
|
||||
/obj/effect/temp_visual/ratvar/warp_marker/Initialize(mapload, mob/living/servant)
|
||||
. = ..()
|
||||
animate(src, alpha = 255, time = 50)
|
||||
|
||||
//Used by the Eminence to coordinate the cult
|
||||
/obj/effect/temp_visual/ratvar/command_point
|
||||
name = "command marker"
|
||||
desc = "An area of importance marked by the Eminence."
|
||||
icon = 'icons/mob/actions/actions_clockcult.dmi'
|
||||
icon_state = "eminence"
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
resistance_flags = INDESTRUCTIBLE
|
||||
layer = MASSIVE_OBJ_LAYER
|
||||
duration = 300
|
||||
|
||||
/obj/effect/temp_visual/ratvar/command_point/Initialize(mapload, appearance)
|
||||
. = ..()
|
||||
icon_state = appearance
|
||||
@@ -0,0 +1,152 @@
|
||||
//temporary visual effects(/obj/effect/temp_visual) used by cult stuff
|
||||
/obj/effect/temp_visual/cult
|
||||
icon = 'icons/effects/cult_effects.dmi'
|
||||
randomdir = 0
|
||||
duration = 10
|
||||
|
||||
/obj/effect/temp_visual/cult/sparks
|
||||
randomdir = 1
|
||||
name = "blood sparks"
|
||||
icon_state = "bloodsparkles"
|
||||
|
||||
/obj/effect/temp_visual/cult/blood // The traditional teleport
|
||||
name = "blood jaunt"
|
||||
duration = 12
|
||||
icon_state = "bloodin"
|
||||
|
||||
/obj/effect/temp_visual/cult/blood/out
|
||||
icon_state = "bloodout"
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/cult/phase // The veil shifter teleport
|
||||
icon = 'icons/effects/cult_effects.dmi'
|
||||
name = "phase glow"
|
||||
duration = 7
|
||||
icon_state = "cultin"
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/cult/phase/out
|
||||
icon = 'icons/effects/cult_effects.dmi'
|
||||
icon_state = "cultout"
|
||||
|
||||
/obj/effect/temp_visual/cult/sac
|
||||
name = "maw of Nar'Sie"
|
||||
icon_state = "sacconsume"
|
||||
|
||||
/obj/effect/temp_visual/cult/door
|
||||
name = "unholy glow"
|
||||
icon_state = "doorglow"
|
||||
layer = CLOSED_FIREDOOR_LAYER //above closed doors
|
||||
|
||||
/obj/effect/temp_visual/cult/door/unruned
|
||||
icon_state = "unruneddoorglow"
|
||||
|
||||
/obj/effect/temp_visual/cult/turf
|
||||
name = "unholy glow"
|
||||
icon_state = "wallglow"
|
||||
layer = ABOVE_NORMAL_TURF_LAYER
|
||||
|
||||
/obj/effect/temp_visual/cult/turf/floor
|
||||
icon_state = "floorglow"
|
||||
duration = 5
|
||||
plane = FLOOR_PLANE
|
||||
|
||||
/obj/effect/temp_visual/cult/portal
|
||||
icon_state = "space"
|
||||
duration = 600
|
||||
layer = ABOVE_OBJ_LAYER
|
||||
|
||||
//visuals for runes being magically created
|
||||
/obj/effect/temp_visual/cult/rune_spawn
|
||||
icon_state = "runeouter"
|
||||
alpha = 0
|
||||
var/turnedness = 179 //179 turns counterclockwise, 181 turns clockwise
|
||||
|
||||
/obj/effect/temp_visual/cult/rune_spawn/Initialize(mapload, set_duration, set_color)
|
||||
if(isnum(set_duration))
|
||||
duration = set_duration
|
||||
if(set_color)
|
||||
add_atom_colour(set_color, FIXED_COLOUR_PRIORITY)
|
||||
. = ..()
|
||||
var/oldtransform = transform
|
||||
transform = matrix()*2
|
||||
var/matrix/M = transform
|
||||
M.Turn(turnedness)
|
||||
transform = M
|
||||
animate(src, alpha = 255, time = duration, easing = BOUNCE_EASING, flags = ANIMATION_PARALLEL)
|
||||
animate(src, transform = oldtransform, time = duration, flags = ANIMATION_PARALLEL)
|
||||
|
||||
/obj/effect/temp_visual/cult/rune_spawn/rune1
|
||||
icon_state = "rune1words"
|
||||
turnedness = 181
|
||||
|
||||
/obj/effect/temp_visual/cult/rune_spawn/rune1/inner
|
||||
icon_state = "rune1inner"
|
||||
turnedness = 179
|
||||
|
||||
/obj/effect/temp_visual/cult/rune_spawn/rune1/center
|
||||
icon_state = "rune1center"
|
||||
|
||||
/obj/effect/temp_visual/cult/rune_spawn/rune2
|
||||
icon_state = "rune2words"
|
||||
turnedness = 181
|
||||
|
||||
/obj/effect/temp_visual/cult/rune_spawn/rune2/inner
|
||||
icon_state = "rune2inner"
|
||||
turnedness = 179
|
||||
|
||||
/obj/effect/temp_visual/cult/rune_spawn/rune2/center
|
||||
icon_state = "rune2center"
|
||||
|
||||
/obj/effect/temp_visual/cult/rune_spawn/rune3
|
||||
icon_state = "rune3words"
|
||||
turnedness = 181
|
||||
|
||||
/obj/effect/temp_visual/cult/rune_spawn/rune3/inner
|
||||
icon_state = "rune3inner"
|
||||
turnedness = 179
|
||||
|
||||
/obj/effect/temp_visual/cult/rune_spawn/rune3/center
|
||||
icon_state = "rune3center"
|
||||
|
||||
/obj/effect/temp_visual/cult/rune_spawn/rune4
|
||||
icon_state = "rune4words"
|
||||
turnedness = 181
|
||||
|
||||
/obj/effect/temp_visual/cult/rune_spawn/rune4/inner
|
||||
icon_state = "rune4inner"
|
||||
turnedness = 179
|
||||
|
||||
/obj/effect/temp_visual/cult/rune_spawn/rune4/center
|
||||
icon_state = "rune4center"
|
||||
|
||||
/obj/effect/temp_visual/cult/rune_spawn/rune5
|
||||
icon_state = "rune5words"
|
||||
turnedness = 181
|
||||
|
||||
/obj/effect/temp_visual/cult/rune_spawn/rune5/inner
|
||||
icon_state = "rune5inner"
|
||||
turnedness = 179
|
||||
|
||||
/obj/effect/temp_visual/cult/rune_spawn/rune5/center
|
||||
icon_state = "rune5center"
|
||||
|
||||
/obj/effect/temp_visual/cult/rune_spawn/rune6
|
||||
icon_state = "rune6words"
|
||||
turnedness = 181
|
||||
|
||||
/obj/effect/temp_visual/cult/rune_spawn/rune6/inner
|
||||
icon_state = "rune6inner"
|
||||
turnedness = 179
|
||||
|
||||
/obj/effect/temp_visual/cult/rune_spawn/rune6/center
|
||||
icon_state = "rune6center"
|
||||
|
||||
/obj/effect/temp_visual/cult/rune_spawn/rune7
|
||||
icon_state = "rune7words"
|
||||
turnedness = 181
|
||||
|
||||
/obj/effect/temp_visual/cult/rune_spawn/rune7/inner
|
||||
icon_state = "rune7inner"
|
||||
turnedness = 179
|
||||
|
||||
/obj/effect/temp_visual/cult/rune_spawn/rune7/center
|
||||
icon_state = "rune7center"
|
||||
@@ -0,0 +1,437 @@
|
||||
//unsorted miscellaneous temporary visuals
|
||||
/obj/effect/temp_visual/dir_setting/bloodsplatter
|
||||
icon = 'icons/effects/blood.dmi'
|
||||
duration = 5
|
||||
randomdir = FALSE
|
||||
layer = BELOW_MOB_LAYER
|
||||
var/splatter_type = "splatter"
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/bloodsplatter/Initialize(mapload, set_dir)
|
||||
if(set_dir in GLOB.diagonals)
|
||||
icon_state = "[splatter_type][pick(1, 2, 6)]"
|
||||
else
|
||||
icon_state = "[splatter_type][pick(3, 4, 5)]"
|
||||
. = ..()
|
||||
var/target_pixel_x = 0
|
||||
var/target_pixel_y = 0
|
||||
switch(set_dir)
|
||||
if(NORTH)
|
||||
target_pixel_y = 16
|
||||
if(SOUTH)
|
||||
target_pixel_y = -16
|
||||
layer = ABOVE_MOB_LAYER
|
||||
if(EAST)
|
||||
target_pixel_x = 16
|
||||
if(WEST)
|
||||
target_pixel_x = -16
|
||||
if(NORTHEAST)
|
||||
target_pixel_x = 16
|
||||
target_pixel_y = 16
|
||||
if(NORTHWEST)
|
||||
target_pixel_x = -16
|
||||
target_pixel_y = 16
|
||||
if(SOUTHEAST)
|
||||
target_pixel_x = 16
|
||||
target_pixel_y = -16
|
||||
layer = ABOVE_MOB_LAYER
|
||||
if(SOUTHWEST)
|
||||
target_pixel_x = -16
|
||||
target_pixel_y = -16
|
||||
layer = ABOVE_MOB_LAYER
|
||||
animate(src, pixel_x = target_pixel_x, pixel_y = target_pixel_y, alpha = 0, time = duration)
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/bloodsplatter/xenosplatter
|
||||
splatter_type = "xsplatter"
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/speedbike_trail
|
||||
name = "speedbike trails"
|
||||
icon_state = "ion_fade"
|
||||
layer = BELOW_MOB_LAYER
|
||||
duration = 10
|
||||
randomdir = 0
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/firing_effect
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
icon_state = "firing_effect"
|
||||
duration = 2
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/firing_effect/setDir(newdir)
|
||||
switch(newdir)
|
||||
if(NORTH)
|
||||
layer = BELOW_MOB_LAYER
|
||||
pixel_x = rand(-3,3)
|
||||
pixel_y = rand(4,6)
|
||||
if(SOUTH)
|
||||
pixel_x = rand(-3,3)
|
||||
pixel_y = rand(-1,1)
|
||||
else
|
||||
pixel_x = rand(-1,1)
|
||||
pixel_y = rand(-1,1)
|
||||
..()
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/firing_effect/energy
|
||||
icon_state = "firing_effect_energy"
|
||||
duration = 3
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/firing_effect/magic
|
||||
icon_state = "shieldsparkles"
|
||||
duration = 3
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/ninja
|
||||
name = "ninja shadow"
|
||||
icon = 'icons/mob/mob.dmi'
|
||||
icon_state = "uncloak"
|
||||
duration = 9
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/ninja/cloak
|
||||
icon_state = "cloak"
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/ninja/shadow
|
||||
icon_state = "shadow"
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/ninja/phase
|
||||
name = "ninja energy"
|
||||
icon_state = "phasein"
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/ninja/phase/out
|
||||
icon_state = "phaseout"
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/wraith
|
||||
name = "blood"
|
||||
icon = 'icons/mob/mob.dmi'
|
||||
icon_state = "phase_shift2"
|
||||
duration = 12
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/wraith/out
|
||||
icon_state = "phase_shift"
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/tailsweep
|
||||
icon_state = "tailsweep"
|
||||
duration = 4
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/curse
|
||||
icon_state = "curse"
|
||||
duration = 32
|
||||
var/fades = TRUE
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/curse/Initialize(mapload, set_dir)
|
||||
. = ..()
|
||||
if(fades)
|
||||
animate(src, alpha = 0, time = 32)
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/curse/blob
|
||||
icon_state = "curseblob"
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/curse/grasp_portal
|
||||
icon = 'icons/effects/64x64.dmi'
|
||||
layer = LARGE_MOB_LAYER
|
||||
pixel_y = -16
|
||||
pixel_x = -16
|
||||
duration = 32
|
||||
fades = FALSE
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/curse/grasp_portal/fading
|
||||
duration = 32
|
||||
fades = TRUE
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/curse/hand
|
||||
icon_state = "cursehand"
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/curse/hand/Initialize(mapload, set_dir, handedness)
|
||||
. = ..()
|
||||
update_icon()
|
||||
|
||||
/obj/item/projectile/curse_hand/update_icon()
|
||||
icon_state = "[icon_state][handedness]"
|
||||
|
||||
/obj/effect/temp_visual/wizard
|
||||
name = "water"
|
||||
icon = 'icons/mob/mob.dmi'
|
||||
icon_state = "reappear"
|
||||
duration = 5
|
||||
|
||||
/obj/effect/temp_visual/wizard/out
|
||||
icon_state = "liquify"
|
||||
duration = 12
|
||||
|
||||
/obj/effect/temp_visual/monkeyify
|
||||
icon = 'icons/mob/mob.dmi'
|
||||
icon_state = "h2monkey"
|
||||
duration = 22
|
||||
|
||||
/obj/effect/temp_visual/monkeyify/humanify
|
||||
icon_state = "monkey2h"
|
||||
|
||||
/obj/effect/temp_visual/borgflash
|
||||
icon = 'icons/mob/mob.dmi'
|
||||
icon_state = "blspell"
|
||||
duration = 5
|
||||
|
||||
/obj/effect/temp_visual/guardian
|
||||
randomdir = 0
|
||||
|
||||
/obj/effect/temp_visual/guardian/phase
|
||||
duration = 5
|
||||
icon_state = "phasein"
|
||||
|
||||
/obj/effect/temp_visual/guardian/phase/out
|
||||
icon_state = "phaseout"
|
||||
|
||||
/obj/effect/temp_visual/decoy
|
||||
desc = "It's a decoy!"
|
||||
duration = 15
|
||||
|
||||
/obj/effect/temp_visual/decoy/Initialize(mapload, atom/mimiced_atom)
|
||||
. = ..()
|
||||
alpha = initial(alpha)
|
||||
if(mimiced_atom)
|
||||
name = mimiced_atom.name
|
||||
appearance = mimiced_atom.appearance
|
||||
setDir(mimiced_atom.dir)
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
|
||||
/obj/effect/temp_visual/decoy/fading/Initialize(mapload, atom/mimiced_atom)
|
||||
. = ..()
|
||||
animate(src, alpha = 0, time = duration)
|
||||
|
||||
/obj/effect/temp_visual/decoy/fading/threesecond
|
||||
duration = 40
|
||||
|
||||
/obj/effect/temp_visual/decoy/fading/fivesecond
|
||||
duration = 50
|
||||
|
||||
/obj/effect/temp_visual/decoy/fading/halfsecond
|
||||
duration = 5
|
||||
|
||||
/obj/effect/temp_visual/small_smoke
|
||||
icon_state = "smoke"
|
||||
duration = 50
|
||||
|
||||
/obj/effect/temp_visual/small_smoke/halfsecond
|
||||
duration = 5
|
||||
|
||||
/obj/effect/temp_visual/fire
|
||||
icon = 'icons/effects/fire.dmi'
|
||||
icon_state = "3"
|
||||
light_range = LIGHT_RANGE_FIRE
|
||||
light_color = LIGHT_COLOR_FIRE
|
||||
duration = 10
|
||||
|
||||
/obj/effect/temp_visual/revenant
|
||||
name = "spooky lights"
|
||||
icon_state = "purplesparkles"
|
||||
|
||||
/obj/effect/temp_visual/revenant/cracks
|
||||
name = "glowing cracks"
|
||||
icon_state = "purplecrack"
|
||||
duration = 6
|
||||
|
||||
/obj/effect/temp_visual/gravpush
|
||||
name = "gravity wave"
|
||||
icon_state = "shieldsparkles"
|
||||
duration = 5
|
||||
|
||||
/obj/effect/temp_visual/telekinesis
|
||||
name = "telekinetic force"
|
||||
icon_state = "empdisable"
|
||||
duration = 5
|
||||
|
||||
/obj/effect/temp_visual/emp
|
||||
name = "emp sparks"
|
||||
icon_state = "empdisable"
|
||||
|
||||
/obj/effect/temp_visual/emp/pulse
|
||||
name = "emp pulse"
|
||||
icon_state = "emppulse"
|
||||
duration = 8
|
||||
randomdir = 0
|
||||
|
||||
/obj/effect/temp_visual/bluespace_fissure
|
||||
name = "bluespace fissure"
|
||||
icon_state = "bluestream_fade"
|
||||
duration = 9
|
||||
|
||||
/obj/effect/temp_visual/gib_animation
|
||||
icon = 'icons/mob/mob.dmi'
|
||||
duration = 15
|
||||
|
||||
/obj/effect/temp_visual/gib_animation/Initialize(mapload, gib_icon)
|
||||
icon_state = gib_icon // Needs to be before ..() so icon is correct
|
||||
. = ..()
|
||||
|
||||
/obj/effect/temp_visual/gib_animation/animal
|
||||
icon = 'icons/mob/animal.dmi'
|
||||
|
||||
/obj/effect/temp_visual/dust_animation
|
||||
icon = 'icons/mob/mob.dmi'
|
||||
duration = 15
|
||||
|
||||
/obj/effect/temp_visual/dust_animation/Initialize(mapload, dust_icon)
|
||||
icon_state = dust_icon // Before ..() so the correct icon is flick()'d
|
||||
. = ..()
|
||||
|
||||
/obj/effect/temp_visual/mummy_animation
|
||||
icon = 'icons/mob/mob.dmi'
|
||||
icon_state = "mummy_revive"
|
||||
duration = 20
|
||||
|
||||
/obj/effect/temp_visual/heal //color is white by default, set to whatever is needed
|
||||
name = "healing glow"
|
||||
icon_state = "heal"
|
||||
duration = 15
|
||||
|
||||
/obj/effect/temp_visual/heal/Initialize(mapload, set_color)
|
||||
if(set_color)
|
||||
add_atom_colour(set_color, FIXED_COLOUR_PRIORITY)
|
||||
. = ..()
|
||||
pixel_x = rand(-12, 12)
|
||||
pixel_y = rand(-9, 0)
|
||||
|
||||
/obj/effect/temp_visual/kinetic_blast
|
||||
name = "kinetic explosion"
|
||||
icon = 'icons/obj/projectiles.dmi'
|
||||
icon_state = "kinetic_blast"
|
||||
layer = ABOVE_ALL_MOB_LAYER
|
||||
duration = 4
|
||||
|
||||
/obj/effect/temp_visual/explosion
|
||||
name = "explosion"
|
||||
icon = 'icons/effects/96x96.dmi'
|
||||
icon_state = "explosion"
|
||||
pixel_x = -32
|
||||
pixel_y = -32
|
||||
duration = 8
|
||||
|
||||
/obj/effect/temp_visual/explosion/fast
|
||||
icon_state = "explosionfast"
|
||||
duration = 4
|
||||
|
||||
/obj/effect/temp_visual/blob
|
||||
name = "blob"
|
||||
icon_state = "blob_attack"
|
||||
alpha = 140
|
||||
randomdir = 0
|
||||
duration = 6
|
||||
|
||||
/obj/effect/temp_visual/impact_effect
|
||||
icon_state = "impact_bullet"
|
||||
duration = 5
|
||||
|
||||
/obj/effect/temp_visual/impact_effect/Initialize(mapload, x, y)
|
||||
pixel_x = x
|
||||
pixel_y = y
|
||||
return ..()
|
||||
|
||||
/obj/effect/temp_visual/impact_effect/red_laser
|
||||
icon_state = "impact_laser"
|
||||
duration = 4
|
||||
|
||||
/obj/effect/temp_visual/impact_effect/red_laser/wall
|
||||
icon_state = "impact_laser_wall"
|
||||
duration = 10
|
||||
|
||||
/obj/effect/temp_visual/impact_effect/blue_laser
|
||||
icon_state = "impact_laser_blue"
|
||||
duration = 4
|
||||
|
||||
/obj/effect/temp_visual/impact_effect/green_laser
|
||||
icon_state = "impact_laser_green"
|
||||
duration = 4
|
||||
|
||||
/obj/effect/temp_visual/impact_effect/purple_laser
|
||||
icon_state = "impact_laser_purple"
|
||||
duration = 4
|
||||
|
||||
/obj/effect/temp_visual/impact_effect/ion
|
||||
icon_state = "shieldsparkles"
|
||||
duration = 6
|
||||
|
||||
/obj/effect/temp_visual/heart
|
||||
name = "heart"
|
||||
icon = 'icons/mob/animal.dmi'
|
||||
icon_state = "heart"
|
||||
duration = 25
|
||||
|
||||
/obj/effect/temp_visual/heart/Initialize(mapload)
|
||||
. = ..()
|
||||
pixel_x = rand(-4,4)
|
||||
pixel_y = rand(-4,4)
|
||||
animate(src, pixel_y = pixel_y + 32, alpha = 0, time = 25)
|
||||
|
||||
/obj/effect/temp_visual/love_heart
|
||||
name = "love heart"
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
icon_state = "heart"
|
||||
duration = 25
|
||||
|
||||
/obj/effect/temp_visual/love_heart/Initialize(mapload)
|
||||
. = ..()
|
||||
pixel_x = rand(-10,10)
|
||||
pixel_y = rand(-10,10)
|
||||
animate(src, pixel_y = pixel_y + 32, alpha = 0, time = duration)
|
||||
|
||||
/obj/effect/temp_visual/love_heart/invisible
|
||||
icon_state = null
|
||||
|
||||
/obj/effect/temp_visual/love_heart/invisible/Initialize(mapload, mob/seer)
|
||||
. = ..()
|
||||
var/image/I = image(icon = 'icons/effects/effects.dmi', icon_state = "heart", layer = ABOVE_MOB_LAYER, loc = src)
|
||||
add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/onePerson, "heart", I, seer)
|
||||
I.alpha = 255
|
||||
I.appearance_flags = RESET_ALPHA
|
||||
animate(I, alpha = 0, time = duration)
|
||||
|
||||
/obj/effect/temp_visual/bleed
|
||||
name = "bleed"
|
||||
icon = 'icons/effects/bleed.dmi'
|
||||
icon_state = "bleed0"
|
||||
duration = 10
|
||||
var/shrink = TRUE
|
||||
|
||||
/obj/effect/temp_visual/bleed/Initialize(mapload, atom/size_calc_target)
|
||||
. = ..()
|
||||
var/size_matrix = matrix()
|
||||
if(size_calc_target)
|
||||
layer = size_calc_target.layer + 0.01
|
||||
var/icon/I = icon(size_calc_target.icon, size_calc_target.icon_state, size_calc_target.dir)
|
||||
size_matrix = matrix() * (I.Height()/world.icon_size)
|
||||
transform = size_matrix //scale the bleed overlay's size based on the target's icon size
|
||||
var/matrix/M = transform
|
||||
if(shrink)
|
||||
M = size_matrix*0.1
|
||||
else
|
||||
M = size_matrix*2
|
||||
animate(src, alpha = 20, transform = M, time = duration, flags = ANIMATION_PARALLEL)
|
||||
|
||||
/obj/effect/temp_visual/bleed/explode
|
||||
icon_state = "bleed10"
|
||||
duration = 12
|
||||
shrink = FALSE
|
||||
|
||||
/obj/effect/temp_visual/warp_cube
|
||||
duration = 5
|
||||
var/outgoing = TRUE
|
||||
|
||||
/obj/effect/temp_visual/warp_cube/Initialize(mapload, atom/teleporting_atom, warp_color, new_outgoing)
|
||||
. = ..()
|
||||
if(teleporting_atom)
|
||||
outgoing = new_outgoing
|
||||
appearance = teleporting_atom.appearance
|
||||
setDir(teleporting_atom.dir)
|
||||
if(warp_color)
|
||||
color = list(warp_color, warp_color, warp_color, list(0,0,0))
|
||||
set_light(1.4, 1, warp_color)
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
var/matrix/skew = transform
|
||||
skew = skew.Turn(180)
|
||||
skew = skew.Interpolate(transform, 0.5)
|
||||
if(!outgoing)
|
||||
transform = skew * 2
|
||||
skew = teleporting_atom.transform
|
||||
alpha = 0
|
||||
animate(src, alpha = teleporting_atom.alpha, transform = skew, time = duration)
|
||||
else
|
||||
skew *= 2
|
||||
animate(src, alpha = 0, transform = skew, time = duration)
|
||||
else
|
||||
return INITIALIZE_HINT_QDEL
|
||||
@@ -0,0 +1,38 @@
|
||||
/obj/effect/projectile/impact
|
||||
name = "beam impact"
|
||||
icon = 'icons/obj/projectiles_impact.dmi'
|
||||
|
||||
/obj/effect/projectile/impact/laser
|
||||
name = "laser impact"
|
||||
icon_state = "impact_laser"
|
||||
|
||||
/obj/effect/projectile/impact/laser/blue
|
||||
name = "laser impact"
|
||||
icon_state = "impact_blue"
|
||||
|
||||
/obj/effect/projectile/impact/disabler
|
||||
name = "disabler impact"
|
||||
icon_state = "impact_omni"
|
||||
|
||||
/obj/effect/projectile/impact/xray
|
||||
name = "\improper X-ray impact"
|
||||
icon_state = "impact_xray"
|
||||
|
||||
/obj/effect/projectile/impact/pulse
|
||||
name = "pulse impact"
|
||||
icon_state = "impact_u_laser"
|
||||
|
||||
/obj/effect/projectile/impact/plasma_cutter
|
||||
name = "plasma impact"
|
||||
icon_state = "impact_plasmacutter"
|
||||
|
||||
/obj/effect/projectile/impact/stun
|
||||
name = "stun impact"
|
||||
icon_state = "impact_stun"
|
||||
|
||||
/obj/effect/projectile/impact/heavy_laser
|
||||
name = "heavy laser impact"
|
||||
icon_state = "impact_beam_heavy"
|
||||
|
||||
/obj/effect/projectile/impact/wormhole
|
||||
icon_state = "wormhole_g"
|
||||
@@ -0,0 +1,30 @@
|
||||
/obj/effect/projectile/muzzle
|
||||
name = "muzzle flash"
|
||||
icon = 'icons/obj/projectiles_muzzle.dmi'
|
||||
|
||||
/obj/effect/projectile/muzzle/laser
|
||||
icon_state = "muzzle_laser"
|
||||
|
||||
/obj/effect/projectile/muzzle/laser/blue
|
||||
icon_state = "muzzle_laser_blue"
|
||||
|
||||
/obj/effect/projectile/muzzle/disabler
|
||||
icon_state = "muzzle_omni"
|
||||
|
||||
/obj/effect/projectile/muzzle/xray
|
||||
icon_state = "muzzle_xray"
|
||||
|
||||
/obj/effect/projectile/muzzle/pulse
|
||||
icon_state = "muzzle_u_laser"
|
||||
|
||||
/obj/effect/projectile/muzzle/plasma_cutter
|
||||
icon_state = "muzzle_plasmacutter"
|
||||
|
||||
/obj/effect/projectile/muzzle/stun
|
||||
icon_state = "muzzle_stun"
|
||||
|
||||
/obj/effect/projectile/muzzle/heavy_laser
|
||||
icon_state = "muzzle_beam_heavy"
|
||||
|
||||
/obj/effect/projectile/muzzle/wormhole
|
||||
icon_state = "wormhole_g"
|
||||
@@ -0,0 +1,60 @@
|
||||
/obj/effect/projectile
|
||||
name = "pew"
|
||||
icon = 'icons/obj/projectiles.dmi'
|
||||
icon_state = "nothing"
|
||||
layer = ABOVE_MOB_LAYER
|
||||
anchored = TRUE
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
appearance_flags = 0
|
||||
|
||||
/obj/effect/projectile/singularity_pull()
|
||||
return
|
||||
|
||||
/obj/effect/projectile/singularity_act()
|
||||
return
|
||||
|
||||
/obj/effect/projectile/proc/scale_to(nx,ny,override=TRUE)
|
||||
var/matrix/M
|
||||
if(!override)
|
||||
M = transform
|
||||
else
|
||||
M = new
|
||||
M.Scale(nx,ny)
|
||||
transform = M
|
||||
|
||||
/obj/effect/projectile/proc/turn_to(angle,override=TRUE)
|
||||
var/matrix/M
|
||||
if(!override)
|
||||
M = transform
|
||||
else
|
||||
M = new
|
||||
M.Turn(angle)
|
||||
transform = M
|
||||
|
||||
/obj/effect/projectile/New(angle_override, p_x, p_y, color_override, scaling = 1)
|
||||
if(angle_override && p_x && p_y && color_override && scaling)
|
||||
apply_vars(angle_override, p_x, p_y, color_override, scaling)
|
||||
return ..()
|
||||
|
||||
/obj/effect/projectile/proc/apply_vars(angle_override, p_x = 0, p_y = 0, color_override, scaling = 1, new_loc, increment = 0)
|
||||
var/mutable_appearance/look = new(src)
|
||||
look.pixel_x = p_x
|
||||
look.pixel_y = p_y
|
||||
if(color_override)
|
||||
look.color = color_override
|
||||
appearance = look
|
||||
scale_to(1,scaling, FALSE)
|
||||
turn_to(angle_override, FALSE)
|
||||
if(!isnull(new_loc)) //If you want to null it just delete it...
|
||||
forceMove(new_loc)
|
||||
for(var/i in 1 to increment)
|
||||
pixel_x += round((sin(angle_override)+16*sin(angle_override)*2), 1)
|
||||
pixel_y += round((cos(angle_override)+16*cos(angle_override)*2), 1)
|
||||
|
||||
/obj/effect/projectile_lighting
|
||||
var/owner
|
||||
|
||||
/obj/effect/projectile_lighting/Initialize(mapload, color, range, intensity, owner_key)
|
||||
. = ..()
|
||||
set_light(range, intensity, color)
|
||||
owner = owner_key
|
||||
@@ -0,0 +1,68 @@
|
||||
/proc/generate_tracer_between_points(datum/point/starting, datum/point/ending, beam_type, color, qdel_in = 5, light_range = 2, light_color_override, light_intensity = 1, instance_key) //Do not pass z-crossing points as that will not be properly (and likely will never be properly until it's absolutely needed) supported!
|
||||
if(!istype(starting) || !istype(ending) || !ispath(beam_type))
|
||||
return
|
||||
var/datum/point/midpoint = point_midpoint_points(starting, ending)
|
||||
var/obj/effect/projectile/tracer/PB = new beam_type
|
||||
if(isnull(light_color_override))
|
||||
light_color_override = color
|
||||
PB.apply_vars(angle_between_points(starting, ending), midpoint.return_px(), midpoint.return_py(), color, pixel_length_between_points(starting, ending) / world.icon_size, midpoint.return_turf(), 0)
|
||||
. = PB
|
||||
if(light_range > 0 && light_intensity > 0)
|
||||
var/list/turf/line = getline(starting.return_turf(), ending.return_turf())
|
||||
tracing_line:
|
||||
for(var/i in line)
|
||||
var/turf/T = i
|
||||
for(var/obj/effect/projectile_lighting/PL in T)
|
||||
if(PL.owner == instance_key)
|
||||
continue tracing_line
|
||||
QDEL_IN(new /obj/effect/projectile_lighting(T, light_color_override, light_range, light_intensity, instance_key), qdel_in > 0? qdel_in : 5)
|
||||
line = null
|
||||
if(qdel_in)
|
||||
QDEL_IN(PB, qdel_in)
|
||||
|
||||
/obj/effect/projectile/tracer
|
||||
name = "beam"
|
||||
icon = 'icons/obj/projectiles_tracer.dmi'
|
||||
|
||||
/obj/effect/projectile/tracer/laser
|
||||
name = "laser"
|
||||
icon_state = "beam"
|
||||
|
||||
/obj/effect/projectile/tracer/laser/blue
|
||||
icon_state = "beam_blue"
|
||||
|
||||
/obj/effect/projectile/tracer/disabler
|
||||
name = "disabler"
|
||||
icon_state = "beam_omni"
|
||||
|
||||
/obj/effect/projectile/tracer/xray
|
||||
name = "\improper X-ray laser"
|
||||
icon_state = "xray"
|
||||
|
||||
/obj/effect/projectile/tracer/pulse
|
||||
name = "pulse laser"
|
||||
icon_state = "u_laser"
|
||||
|
||||
/obj/effect/projectile/tracer/plasma_cutter
|
||||
name = "plasma blast"
|
||||
icon_state = "plasmacutter"
|
||||
|
||||
/obj/effect/projectile/tracer/stun
|
||||
name = "stun beam"
|
||||
icon_state = "stun"
|
||||
|
||||
/obj/effect/projectile/tracer/heavy_laser
|
||||
name = "heavy laser"
|
||||
icon_state = "beam_heavy"
|
||||
|
||||
//BEAM RIFLE
|
||||
/obj/effect/projectile/tracer/tracer/beam_rifle
|
||||
icon_state = "tracer_beam"
|
||||
|
||||
/obj/effect/projectile/tracer/tracer/aiming
|
||||
icon_state = "pixelbeam_greyscale"
|
||||
layer = ABOVE_LIGHTING_LAYER
|
||||
plane = ABOVE_LIGHTING_PLANE
|
||||
|
||||
/obj/effect/projectile/tracer/wormhole
|
||||
icon_state = "wormhole_g"
|
||||
@@ -0,0 +1,39 @@
|
||||
//temporary visual effects
|
||||
/obj/effect/temp_visual
|
||||
icon_state = "nothing"
|
||||
anchored = TRUE
|
||||
layer = ABOVE_MOB_LAYER
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
var/duration = 10 //in deciseconds
|
||||
var/randomdir = TRUE
|
||||
var/timerid
|
||||
|
||||
/obj/effect/temp_visual/Initialize()
|
||||
. = ..()
|
||||
if(randomdir)
|
||||
setDir(pick(GLOB.cardinals))
|
||||
|
||||
timerid = QDEL_IN(src, duration)
|
||||
|
||||
/obj/effect/temp_visual/Destroy()
|
||||
. = ..()
|
||||
deltimer(timerid)
|
||||
|
||||
/obj/effect/temp_visual/singularity_act()
|
||||
return
|
||||
|
||||
/obj/effect/temp_visual/singularity_pull()
|
||||
return
|
||||
|
||||
/obj/effect/temp_visual/ex_act()
|
||||
return
|
||||
|
||||
/obj/effect/temp_visual/dir_setting
|
||||
randomdir = FALSE
|
||||
|
||||
/obj/effect/temp_visual/dir_setting/Initialize(mapload, set_dir)
|
||||
if(set_dir)
|
||||
setDir(set_dir)
|
||||
. = ..()
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/obj/item/poster/wanted
|
||||
icon_state = "rolled_poster"
|
||||
|
||||
/obj/item/poster/wanted/Initialize(mapload, icon/person_icon, wanted_name, description)
|
||||
. = ..(mapload, new /obj/structure/sign/poster/wanted(src, person_icon, wanted_name, description))
|
||||
name = "wanted poster ([wanted_name])"
|
||||
desc = "A wanted poster for [wanted_name]."
|
||||
|
||||
/obj/structure/sign/poster/wanted
|
||||
var/wanted_name
|
||||
|
||||
/obj/structure/sign/poster/wanted/Initialize(mapload, icon/person_icon, person_name, description)
|
||||
. = ..()
|
||||
if(!person_icon)
|
||||
return INITIALIZE_HINT_QDEL
|
||||
name = "wanted poster ([person_name])"
|
||||
wanted_name = person_name
|
||||
desc = description
|
||||
|
||||
person_icon = icon(person_icon, dir = SOUTH)//copy the image so we don't mess with the one in the record.
|
||||
var/icon/the_icon = icon("icon" = 'icons/obj/poster_wanted.dmi', "icon_state" = "wanted_background")
|
||||
var/icon/icon_foreground = icon("icon" = 'icons/obj/poster_wanted.dmi', "icon_state" = "wanted_foreground")
|
||||
person_icon.Shift(SOUTH, 7)
|
||||
person_icon.Crop(7,4,26,30)
|
||||
person_icon.Crop(-5,-2,26,29)
|
||||
the_icon.Blend(person_icon, ICON_OVERLAY)
|
||||
the_icon.Blend(icon_foreground, ICON_OVERLAY)
|
||||
|
||||
the_icon.Insert(the_icon, "wanted")
|
||||
the_icon.Insert(icon('icons/obj/contraband.dmi', "poster_being_set"), "poster_being_set")
|
||||
the_icon.Insert(icon('icons/obj/contraband.dmi', "poster_ripped"), "poster_ripped")
|
||||
icon = the_icon
|
||||
|
||||
/obj/structure/sign/poster/wanted/roll_and_drop(turf/location)
|
||||
var/obj/item/poster/P = ..(location)
|
||||
P.name = "wanted poster ([wanted_name])"
|
||||
P.desc = "A wanted poster for [wanted_name]."
|
||||
return P
|
||||
@@ -0,0 +1,32 @@
|
||||
/proc/empulse(turf/epicenter, heavy_range, light_range, log=0)
|
||||
if(!epicenter)
|
||||
return
|
||||
|
||||
if(!isturf(epicenter))
|
||||
epicenter = get_turf(epicenter.loc)
|
||||
|
||||
if(log)
|
||||
message_admins("EMP with size ([heavy_range], [light_range]) in area [epicenter.loc.name] ")
|
||||
log_game("EMP with size ([heavy_range], [light_range]) in area [epicenter.loc.name] ")
|
||||
|
||||
if(heavy_range >= 1)
|
||||
new /obj/effect/temp_visual/emp/pulse(epicenter)
|
||||
|
||||
if(heavy_range > light_range)
|
||||
light_range = heavy_range
|
||||
|
||||
for(var/A in spiral_range(light_range, epicenter))
|
||||
var/atom/T = A
|
||||
var/distance = get_dist(epicenter, T)
|
||||
if(distance < 0)
|
||||
distance = 0
|
||||
if(distance < heavy_range)
|
||||
T.emp_act(EMP_HEAVY)
|
||||
else if(distance == heavy_range)
|
||||
if(prob(50))
|
||||
T.emp_act(EMP_HEAVY)
|
||||
else
|
||||
T.emp_act(EMP_LIGHT)
|
||||
else if(distance <= light_range)
|
||||
T.emp_act(EMP_LIGHT)
|
||||
return 1
|
||||
@@ -0,0 +1,826 @@
|
||||
GLOBAL_DATUM_INIT(fire_overlay, /mutable_appearance, mutable_appearance('icons/effects/fire.dmi', "fire"))
|
||||
|
||||
GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
|
||||
// if true, everyone item when created will have its name changed to be
|
||||
// more... RPG-like.
|
||||
|
||||
/obj/item
|
||||
name = "item"
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
var/item_state = null
|
||||
var/lefthand_file = 'icons/mob/inhands/items_lefthand.dmi'
|
||||
var/righthand_file = 'icons/mob/inhands/items_righthand.dmi'
|
||||
|
||||
//Dimensions of the icon file used when this item is worn, eg: hats.dmi
|
||||
//eg: 32x32 sprite, 64x64 sprite, etc.
|
||||
//allows inhands/worn sprites to be of any size, but still centered on a mob properly
|
||||
var/worn_x_dimension = 32
|
||||
var/worn_y_dimension = 32
|
||||
//Same as above but for inhands, uses the lefthand_ and righthand_ file vars
|
||||
var/inhand_x_dimension = 32
|
||||
var/inhand_y_dimension = 32
|
||||
|
||||
//Not on /clothing because for some reason any /obj/item can technically be "worn" with enough fuckery.
|
||||
var/icon/alternate_worn_icon = null//If this is set, update_icons() will find on mob (WORN, NOT INHANDS) states in this file instead, primary use: badminnery/events
|
||||
var/alternate_worn_layer = null//If this is set, update_icons() will force the on mob state (WORN, NOT INHANDS) onto this layer, instead of it's default
|
||||
|
||||
max_integrity = 200
|
||||
|
||||
obj_flags = NONE
|
||||
var/item_flags = NONE
|
||||
|
||||
var/hitsound = null
|
||||
var/usesound = null
|
||||
var/throwhitsound = null
|
||||
var/w_class = WEIGHT_CLASS_NORMAL
|
||||
var/total_mass //Total mass in arbitrary pound-like values. If there's no balance reasons for an item to have otherwise, this var should be the item's weight in pounds.
|
||||
var/slot_flags = 0 //This is used to determine on which slots an item can fit.
|
||||
pass_flags = PASSTABLE
|
||||
pressure_resistance = 4
|
||||
var/obj/item/master = null
|
||||
|
||||
var/heat_protection = 0 //flags which determine which body parts are protected from heat. Use the HEAD, CHEST, GROIN, etc. flags. See setup.dm
|
||||
var/cold_protection = 0 //flags which determine which body parts are protected from cold. Use the HEAD, CHEST, GROIN, etc. flags. See setup.dm
|
||||
var/max_heat_protection_temperature //Set this variable to determine up to which temperature (IN KELVIN) the item protects against heat damage. Keep at null to disable protection. Only protects areas set by heat_protection flags
|
||||
var/min_cold_protection_temperature //Set this variable to determine down to which temperature (IN KELVIN) the item protects against cold damage. 0 is NOT an acceptable number due to if(varname) tests!! Keep at null to disable protection. Only protects areas set by cold_protection flags
|
||||
|
||||
var/list/actions //list of /datum/action's that this item has.
|
||||
var/list/actions_types //list of paths of action datums to give to the item on New().
|
||||
|
||||
//Since any item can now be a piece of clothing, this has to be put here so all items share it.
|
||||
var/flags_inv //This flag is used to determine when items in someone's inventory cover others. IE helmets making it so you can't see glasses, etc.
|
||||
|
||||
var/interaction_flags_item = INTERACT_ITEM_ATTACK_HAND_PICKUP
|
||||
//Citadel Edit for digitigrade stuff
|
||||
var/mutantrace_variation = NO_MUTANTRACE_VARIATION //Are there special sprites for specific situations? Don't use this unless you need to.
|
||||
|
||||
var/item_color = null //this needs deprecating, soonish
|
||||
|
||||
var/body_parts_covered = 0 //see setup.dm for appropriate bit flags
|
||||
var/gas_transfer_coefficient = 1 // for leaking gas from turf to mask and vice-versa (for masks right now, but at some point, i'd like to include space helmets)
|
||||
var/permeability_coefficient = 1 // for chemicals/diseases
|
||||
var/siemens_coefficient = 1 // for electrical admittance/conductance (electrocution checks and shit)
|
||||
var/slowdown = 0 // How much clothing is slowing you down. Negative values speeds you up
|
||||
var/armour_penetration = 0 //percentage of armour effectiveness to remove
|
||||
var/list/allowed = null //suit storage stuff.
|
||||
var/equip_delay_self = 0 //In deciseconds, how long an item takes to equip; counts only for normal clothing slots, not pockets etc.
|
||||
var/equip_delay_other = 20 //In deciseconds, how long an item takes to put on another person
|
||||
var/strip_delay = 40 //In deciseconds, how long an item takes to remove from another person
|
||||
var/breakouttime = 0
|
||||
var/list/materials
|
||||
|
||||
var/list/attack_verb //Used in attackby() to say how something was attacked "[x] has been [z.attack_verb] by [y] with [z]"
|
||||
var/list/species_exception = null // list() of species types, if a species cannot put items in a certain slot, but species type is in list, it will be able to wear that item
|
||||
|
||||
var/mob/thrownby = null
|
||||
|
||||
mouse_drag_pointer = MOUSE_ACTIVE_POINTER //the icon to indicate this object is being dragged
|
||||
|
||||
var/datum/embedding_behavior/embedding
|
||||
|
||||
var/flags_cover = 0 //for flags such as GLASSESCOVERSEYES
|
||||
var/heat = 0
|
||||
var/sharpness = IS_BLUNT
|
||||
|
||||
var/tool_behaviour = NONE
|
||||
var/toolspeed = 1
|
||||
|
||||
var/block_chance = 0
|
||||
var/hit_reaction_chance = 0 //If you want to have something unrelated to blocking/armour piercing etc. Maybe not needed, but trying to think ahead/allow more freedom
|
||||
var/reach = 1 //In tiles, how far this weapon can reach; 1 for adjacent, which is default
|
||||
|
||||
//The list of slots by priority. equip_to_appropriate_slot() uses this list. Doesn't matter if a mob type doesn't have a slot.
|
||||
var/list/slot_equipment_priority = null // for default list, see /mob/proc/equip_to_appropriate_slot()
|
||||
|
||||
// Needs to be in /obj/item because corgis can wear a lot of
|
||||
// non-clothing items
|
||||
var/datum/dog_fashion/dog_fashion = null
|
||||
|
||||
var/datum/rpg_loot/rpg_loot = null
|
||||
|
||||
|
||||
//Tooltip vars
|
||||
var/force_string //string form of an item's force. Edit this var only to set a custom force string
|
||||
var/last_force_string_check = 0
|
||||
var/tip_timer
|
||||
|
||||
var/trigger_guard = TRIGGER_GUARD_NONE
|
||||
|
||||
//Grinder vars
|
||||
var/list/grind_results //A reagent list containing the reagents this item produces when ground up in a grinder - this can be an empty list to allow for reagent transferring only
|
||||
var/list/juice_results //A reagent list containing blah blah... but when JUICED in a grinder!
|
||||
|
||||
|
||||
/obj/item/Initialize()
|
||||
|
||||
materials = typelist("materials", materials)
|
||||
|
||||
if (attack_verb)
|
||||
attack_verb = typelist("attack_verb", attack_verb)
|
||||
|
||||
. = ..()
|
||||
for(var/path in actions_types)
|
||||
new path(src)
|
||||
actions_types = null
|
||||
|
||||
if(GLOB.rpg_loot_items)
|
||||
rpg_loot = new(src)
|
||||
|
||||
if(force_string)
|
||||
item_flags |= FORCE_STRING_OVERRIDE
|
||||
|
||||
if(!hitsound)
|
||||
if(damtype == "fire")
|
||||
hitsound = 'sound/items/welder.ogg'
|
||||
if(damtype == "brute")
|
||||
hitsound = "swing_hit"
|
||||
|
||||
if (!embedding)
|
||||
embedding = getEmbeddingBehavior()
|
||||
else if (islist(embedding))
|
||||
embedding = getEmbeddingBehavior(arglist(embedding))
|
||||
else if (!istype(embedding, /datum/embedding_behavior))
|
||||
stack_trace("Invalid type [embedding.type] found in .embedding during /obj/item Initialize()")
|
||||
|
||||
/obj/item/Destroy()
|
||||
item_flags &= ~DROPDEL //prevent reqdels
|
||||
if(ismob(loc))
|
||||
var/mob/m = loc
|
||||
m.temporarilyRemoveItemFromInventory(src, TRUE)
|
||||
for(var/X in actions)
|
||||
qdel(X)
|
||||
QDEL_NULL(rpg_loot)
|
||||
return ..()
|
||||
|
||||
/obj/item/proc/check_allowed_items(atom/target, not_inside, target_self)
|
||||
if(((src in target) && !target_self) || (!isturf(target.loc) && !isturf(target) && not_inside))
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
|
||||
/obj/item/blob_act(obj/structure/blob/B)
|
||||
if(B && B.loc == loc)
|
||||
qdel(src)
|
||||
|
||||
//user: The mob that is suiciding
|
||||
//damagetype: The type of damage the item will inflict on the user
|
||||
//BRUTELOSS = 1
|
||||
//FIRELOSS = 2
|
||||
//TOXLOSS = 4
|
||||
//OXYLOSS = 8
|
||||
//Output a creative message and then return the damagetype done
|
||||
/obj/item/proc/suicide_act(mob/user)
|
||||
return
|
||||
|
||||
/obj/item/verb/move_to_top()
|
||||
set name = "Move To Top"
|
||||
set category = "Object"
|
||||
set src in oview(1)
|
||||
|
||||
if(!isturf(loc) || usr.stat || usr.restrained() || !usr.canmove)
|
||||
return
|
||||
|
||||
var/turf/T = src.loc
|
||||
|
||||
src.loc = null
|
||||
|
||||
src.loc = T
|
||||
|
||||
/obj/item/examine(mob/user) //This might be spammy. Remove?
|
||||
..()
|
||||
var/pronoun
|
||||
if(src.gender == PLURAL)
|
||||
pronoun = "They are"
|
||||
else
|
||||
pronoun = "It is"
|
||||
var/size = weightclass2text(src.w_class)
|
||||
to_chat(user, "[pronoun] a [size] item." )
|
||||
|
||||
if(!user.research_scanner)
|
||||
return
|
||||
|
||||
// Research prospects, including boostable nodes and point values.
|
||||
// Deliver to a console to know whether the boosts have already been used.
|
||||
var/list/research_msg = list("<font color='purple'>Research prospects:</font> ")
|
||||
var/sep = ""
|
||||
var/list/boostable_nodes = techweb_item_boost_check(src)
|
||||
if (boostable_nodes)
|
||||
for(var/id in boostable_nodes)
|
||||
var/datum/techweb_node/node = SSresearch.techweb_nodes[id]
|
||||
research_msg += sep
|
||||
research_msg += node.display_name
|
||||
sep = ", "
|
||||
var/list/points = techweb_item_point_check(src)
|
||||
if (length(points))
|
||||
sep = ", "
|
||||
research_msg += techweb_point_display_generic(points)
|
||||
|
||||
if (!sep) // nothing was shown
|
||||
research_msg += "None"
|
||||
|
||||
// Extractable materials. Only shows the names, not the amounts.
|
||||
research_msg += ".<br><font color='purple'>Extractable materials:</font> "
|
||||
if (materials.len)
|
||||
sep = ""
|
||||
for(var/mat in materials)
|
||||
research_msg += sep
|
||||
research_msg += CallMaterialName(mat)
|
||||
sep = ", "
|
||||
else
|
||||
research_msg += "None"
|
||||
research_msg += "."
|
||||
to_chat(user, research_msg.Join())
|
||||
|
||||
/obj/item/interact(mob/user)
|
||||
add_fingerprint(user)
|
||||
ui_interact(user)
|
||||
|
||||
/obj/item/ui_act(action, params)
|
||||
add_fingerprint(usr)
|
||||
return ..()
|
||||
|
||||
/obj/item/attack_hand(mob/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
if(!user)
|
||||
return
|
||||
if(anchored)
|
||||
return
|
||||
|
||||
if(resistance_flags & ON_FIRE)
|
||||
var/mob/living/carbon/C = user
|
||||
var/can_handle_hot = FALSE
|
||||
if(!istype(C))
|
||||
can_handle_hot = TRUE
|
||||
else if(C.gloves && (C.gloves.max_heat_protection_temperature > 360))
|
||||
can_handle_hot = TRUE
|
||||
else if(HAS_TRAIT(C, TRAIT_RESISTHEAT) || HAS_TRAIT(C, TRAIT_RESISTHEATHANDS))
|
||||
can_handle_hot = TRUE
|
||||
|
||||
if(can_handle_hot)
|
||||
extinguish()
|
||||
to_chat(user, "<span class='notice'>You put out the fire on [src].</span>")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You burn your hand on [src]!</span>")
|
||||
var/obj/item/bodypart/affecting = C.get_bodypart("[(user.active_hand_index % 2 == 0) ? "r" : "l" ]_arm")
|
||||
if(affecting && affecting.receive_damage( 0, 5 )) // 5 burn damage
|
||||
C.update_damage_overlays()
|
||||
return
|
||||
|
||||
if(acid_level > 20 && !ismob(loc))// so we can still remove the clothes on us that have acid.
|
||||
var/mob/living/carbon/C = user
|
||||
if(istype(C))
|
||||
if(!C.gloves || (!(C.gloves.resistance_flags & (UNACIDABLE|ACID_PROOF))))
|
||||
to_chat(user, "<span class='warning'>The acid on [src] burns your hand!</span>")
|
||||
var/obj/item/bodypart/affecting = C.get_bodypart("[(user.active_hand_index % 2 == 0) ? "r" : "l" ]_arm")
|
||||
if(affecting && affecting.receive_damage( 0, 5 )) // 5 burn damage
|
||||
C.update_damage_overlays()
|
||||
|
||||
if(!(interaction_flags_item & INTERACT_ITEM_ATTACK_HAND_PICKUP)) //See if we're supposed to auto pickup.
|
||||
return
|
||||
|
||||
//Heavy gravity makes picking up things very slow.
|
||||
var/grav = user.has_gravity()
|
||||
if(grav > STANDARD_GRAVITY)
|
||||
var/grav_power = min(3,grav - STANDARD_GRAVITY)
|
||||
to_chat(user,"<span class='notice'>You start picking up [src]...</span>")
|
||||
if(!do_mob(user,src,30*grav_power))
|
||||
return
|
||||
|
||||
|
||||
//If the item is in a storage item, take it out
|
||||
SEND_SIGNAL(loc, COMSIG_TRY_STORAGE_TAKE, src, user.loc, TRUE)
|
||||
|
||||
if(throwing)
|
||||
throwing.finalize(FALSE)
|
||||
if(loc == user)
|
||||
if(!allow_attack_hand_drop(user) || !user.temporarilyRemoveItemFromInventory(src))
|
||||
return
|
||||
|
||||
pickup(user)
|
||||
add_fingerprint(user)
|
||||
if(!user.put_in_active_hand(src, FALSE, FALSE))
|
||||
user.dropItemToGround(src)
|
||||
|
||||
/obj/item/proc/allow_attack_hand_drop(mob/user)
|
||||
return TRUE
|
||||
|
||||
/obj/item/attack_paw(mob/user)
|
||||
if(!user)
|
||||
return
|
||||
if(anchored)
|
||||
return
|
||||
|
||||
SEND_SIGNAL(loc, COMSIG_TRY_STORAGE_TAKE, src, user.loc, TRUE)
|
||||
|
||||
if(throwing)
|
||||
throwing.finalize(FALSE)
|
||||
if(loc == user)
|
||||
if(!user.temporarilyRemoveItemFromInventory(src))
|
||||
return
|
||||
|
||||
pickup(user)
|
||||
add_fingerprint(user)
|
||||
if(!user.put_in_active_hand(src, FALSE, FALSE))
|
||||
user.dropItemToGround(src)
|
||||
|
||||
/obj/item/attack_alien(mob/user)
|
||||
var/mob/living/carbon/alien/A = user
|
||||
|
||||
if(!A.has_fine_manipulation)
|
||||
if(src in A.contents) // To stop Aliens having items stuck in their pockets
|
||||
A.dropItemToGround(src)
|
||||
to_chat(user, "<span class='warning'>Your claws aren't capable of such fine manipulation!</span>")
|
||||
return
|
||||
attack_paw(A)
|
||||
|
||||
/obj/item/attack_ai(mob/user)
|
||||
if(istype(src.loc, /obj/item/robot_module))
|
||||
//If the item is part of a cyborg module, equip it
|
||||
if(!iscyborg(user))
|
||||
return
|
||||
var/mob/living/silicon/robot/R = user
|
||||
if(!R.low_power_mode) //can't equip modules with an empty cell.
|
||||
R.activate_module(src)
|
||||
R.hud_used.update_robot_modules_display()
|
||||
|
||||
/obj/item/proc/GetDeconstructableContents()
|
||||
return GetAllContents() - src
|
||||
|
||||
// afterattack() and attack() prototypes moved to _onclick/item_attack.dm for consistency
|
||||
|
||||
/obj/item/proc/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
|
||||
SEND_SIGNAL(src, COMSIG_ITEM_HIT_REACT, args)
|
||||
if(prob(final_block_chance))
|
||||
owner.visible_message("<span class='danger'>[owner] blocks [attack_text] with [src]!</span>")
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/obj/item/proc/talk_into(mob/M, input, channel, spans, datum/language/language)
|
||||
return ITALICS | REDUCE_RANGE
|
||||
|
||||
/obj/item/proc/dropped(mob/user)
|
||||
for(var/X in actions)
|
||||
var/datum/action/A = X
|
||||
A.Remove(user)
|
||||
if(item_flags & DROPDEL)
|
||||
qdel(src)
|
||||
item_flags &= ~IN_INVENTORY
|
||||
SEND_SIGNAL(src, COMSIG_ITEM_DROPPED,user)
|
||||
|
||||
// called just as an item is picked up (loc is not yet changed)
|
||||
/obj/item/proc/pickup(mob/user)
|
||||
SEND_SIGNAL(src, COMSIG_ITEM_PICKUP, user)
|
||||
item_flags |= IN_INVENTORY
|
||||
|
||||
// called when "found" in pockets and storage items. Returns 1 if the search should end.
|
||||
/obj/item/proc/on_found(mob/finder)
|
||||
return
|
||||
|
||||
/obj/item/MouseDrop(atom/over, src_location, over_location, src_control, over_control, params) //Copypaste of /atom/MouseDrop() since this requires code in a very specific spot
|
||||
if(!usr || !over)
|
||||
return
|
||||
if(SEND_SIGNAL(src, COMSIG_MOUSEDROP_ONTO, over, usr) & COMPONENT_NO_MOUSEDROP) //Whatever is receiving will verify themselves for adjacency.
|
||||
return
|
||||
if(over == src)
|
||||
return usr.client.Click(src, src_location, src_control, params)
|
||||
var/list/directaccess = usr.DirectAccess()
|
||||
if((usr.CanReach(src) || (src in directaccess)) && (usr.CanReach(over) || (over in directaccess)))
|
||||
if(!usr.get_active_held_item())
|
||||
usr.UnarmedAttack(src, TRUE)
|
||||
if(usr.get_active_held_item() == src)
|
||||
melee_attack_chain(usr, over)
|
||||
return
|
||||
if(!Adjacent(usr) || !over.Adjacent(usr))
|
||||
return // should stop you from dragging through windows
|
||||
|
||||
over.MouseDrop_T(src,usr)
|
||||
return
|
||||
|
||||
// called after an item is placed in an equipment slot
|
||||
// user is mob that equipped it
|
||||
// slot uses the slot_X defines found in setup.dm
|
||||
// for items that can be placed in multiple slots
|
||||
// note this isn't called during the initial dressing of a player
|
||||
/obj/item/proc/equipped(mob/user, slot)
|
||||
SEND_SIGNAL(src, COMSIG_ITEM_EQUIPPED, user, slot)
|
||||
for(var/X in actions)
|
||||
var/datum/action/A = X
|
||||
if(item_action_slot_check(slot, user)) //some items only give their actions buttons when in a specific slot.
|
||||
A.Grant(user)
|
||||
item_flags |= IN_INVENTORY
|
||||
|
||||
//sometimes we only want to grant the item's action if it's equipped in a specific slot.
|
||||
/obj/item/proc/item_action_slot_check(slot, mob/user)
|
||||
if(slot == SLOT_IN_BACKPACK || slot == SLOT_LEGCUFFED) //these aren't true slots, so avoid granting actions there
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
//the mob M is attempting to equip this item into the slot passed through as 'slot'. Return 1 if it can do this and 0 if it can't.
|
||||
//if this is being done by a mob other than M, it will include the mob equipper, who is trying to equip the item to mob M. equipper will be null otherwise.
|
||||
//If you are making custom procs but would like to retain partial or complete functionality of this one, include a 'return ..()' to where you want this to happen.
|
||||
//Set disable_warning to 1 if you wish it to not give you outputs.
|
||||
/obj/item/proc/mob_can_equip(mob/living/M, mob/living/equipper, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE)
|
||||
if(!M)
|
||||
return 0
|
||||
|
||||
return M.can_equip(src, slot, disable_warning, bypass_equip_delay_self)
|
||||
|
||||
/obj/item/verb/verb_pickup()
|
||||
set src in oview(1)
|
||||
set category = "Object"
|
||||
set name = "Pick up"
|
||||
|
||||
if(usr.incapacitated() || !Adjacent(usr) || usr.lying)
|
||||
return
|
||||
|
||||
if(usr.get_active_held_item() == null) // Let me know if this has any problems -Yota
|
||||
usr.UnarmedAttack(src)
|
||||
|
||||
//This proc is executed when someone clicks the on-screen UI button.
|
||||
//The default action is attack_self().
|
||||
//Checks before we get to here are: mob is alive, mob is not restrained, stunned, asleep, resting, laying, item is on the mob.
|
||||
/obj/item/proc/ui_action_click(mob/user, actiontype)
|
||||
attack_self(user)
|
||||
|
||||
/obj/item/proc/IsReflect(var/def_zone) //This proc determines if and at what% an object will reflect energy projectiles if it's in l_hand,r_hand or wear_suit
|
||||
return 0
|
||||
|
||||
/obj/item/proc/eyestab(mob/living/carbon/M, mob/living/carbon/user)
|
||||
if(HAS_TRAIT(user, TRAIT_PACIFISM))
|
||||
to_chat(user, "<span class='warning'>You don't want to harm [M]!</span>")
|
||||
return
|
||||
if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50))
|
||||
M = user
|
||||
var/is_human_victim = 0
|
||||
var/obj/item/bodypart/affecting = M.get_bodypart(BODY_ZONE_HEAD)
|
||||
if(ishuman(M))
|
||||
if(!affecting) //no head!
|
||||
return
|
||||
is_human_victim = 1
|
||||
var/mob/living/carbon/human/H = M
|
||||
if((H.head && H.head.flags_cover & HEADCOVERSEYES) || \
|
||||
(H.wear_mask && H.wear_mask.flags_cover & MASKCOVERSEYES) || \
|
||||
(H.glasses && H.glasses.flags_cover & GLASSESCOVERSEYES))
|
||||
// you can't stab someone in the eyes wearing a mask!
|
||||
to_chat(user, "<span class='danger'>You're going to need to remove that mask/helmet/glasses first!</span>")
|
||||
return
|
||||
|
||||
if(ismonkey(M))
|
||||
var/mob/living/carbon/monkey/Mo = M
|
||||
if(Mo.wear_mask && Mo.wear_mask.flags_cover & MASKCOVERSEYES)
|
||||
// you can't stab someone in the eyes wearing a mask!
|
||||
to_chat(user, "<span class='danger'>You're going to need to remove that mask/helmet/glasses first!</span>")
|
||||
return
|
||||
|
||||
if(isalien(M))//Aliens don't have eyes./N slimes also don't have eyes!
|
||||
to_chat(user, "<span class='warning'>You cannot locate any eyes on this creature!</span>")
|
||||
return
|
||||
|
||||
if(isbrain(M))
|
||||
to_chat(user, "<span class='danger'>You cannot locate any organic eyes on this brain!</span>")
|
||||
return
|
||||
|
||||
if(user.getStaminaLoss() >= STAMINA_SOFTCRIT)//CIT CHANGE - makes eyestabbing impossible if you're in stamina softcrit
|
||||
to_chat(user, "<span class='danger'>You're too exhausted for that.</span>")//CIT CHANGE - ditto
|
||||
return //CIT CHANGE - ditto
|
||||
|
||||
src.add_fingerprint(user)
|
||||
|
||||
playsound(loc, src.hitsound, 30, 1, -1)
|
||||
|
||||
user.do_attack_animation(M)
|
||||
|
||||
user.adjustStaminaLossBuffered(10)//CIT CHANGE - makes eyestabbing cost stamina
|
||||
|
||||
if(M != user)
|
||||
M.visible_message("<span class='danger'>[user] has stabbed [M] in the eye with [src]!</span>", \
|
||||
"<span class='userdanger'>[user] stabs you in the eye with [src]!</span>")
|
||||
else
|
||||
user.visible_message( \
|
||||
"<span class='danger'>[user] has stabbed [user.p_them()]self in the eyes with [src]!</span>", \
|
||||
"<span class='userdanger'>You stab yourself in the eyes with [src]!</span>" \
|
||||
)
|
||||
if(is_human_victim)
|
||||
var/mob/living/carbon/human/U = M
|
||||
U.apply_damage(7, BRUTE, affecting)
|
||||
|
||||
else
|
||||
M.take_bodypart_damage(7)
|
||||
|
||||
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "eye_stab", /datum/mood_event/eye_stab)
|
||||
|
||||
log_combat(user, M, "attacked", "[src.name]", "(INTENT: [uppertext(user.a_intent)])")
|
||||
|
||||
M.adjust_blurriness(3)
|
||||
M.adjust_eye_damage(rand(2,4))
|
||||
var/obj/item/organ/eyes/eyes = M.getorganslot(ORGAN_SLOT_EYES)
|
||||
if (!eyes)
|
||||
return
|
||||
if(eyes.eye_damage >= 10)
|
||||
M.adjust_blurriness(15)
|
||||
if(M.stat != DEAD)
|
||||
to_chat(M, "<span class='danger'>Your eyes start to bleed profusely!</span>")
|
||||
if(!(HAS_TRAIT(M, TRAIT_BLIND) || HAS_TRAIT(M, TRAIT_NEARSIGHT)))
|
||||
to_chat(M, "<span class='danger'>You become nearsighted!</span>")
|
||||
M.become_nearsighted(EYE_DAMAGE)
|
||||
if(prob(50))
|
||||
if(M.stat != DEAD)
|
||||
if(M.drop_all_held_items())
|
||||
to_chat(M, "<span class='danger'>You drop what you're holding and clutch at your eyes!</span>")
|
||||
M.adjust_blurriness(10)
|
||||
M.Unconscious(20)
|
||||
M.Knockdown(40)
|
||||
if (prob(eyes.eye_damage - 10 + 1))
|
||||
M.become_blind(EYE_DAMAGE)
|
||||
to_chat(M, "<span class='danger'>You go blind!</span>")
|
||||
|
||||
/obj/item/singularity_pull(S, current_size)
|
||||
..()
|
||||
if(current_size >= STAGE_FOUR)
|
||||
throw_at(S,14,3, spin=0)
|
||||
else
|
||||
return
|
||||
|
||||
/obj/item/throw_impact(atom/A, datum/thrownthing/throwingdatum)
|
||||
if(A && !QDELETED(A))
|
||||
SEND_SIGNAL(src, COMSIG_MOVABLE_IMPACT, A, throwingdatum)
|
||||
if(is_hot() && isliving(A))
|
||||
var/mob/living/L = A
|
||||
L.IgniteMob()
|
||||
var/itempush = 1
|
||||
if(w_class < 4)
|
||||
itempush = 0 //too light to push anything
|
||||
return A.hitby(src, 0, itempush)
|
||||
|
||||
/obj/item/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback)
|
||||
thrownby = thrower
|
||||
callback = CALLBACK(src, .proc/after_throw, callback) //replace their callback with our own
|
||||
. = ..(target, range, speed, thrower, spin, diagonals_first, callback)
|
||||
|
||||
/obj/item/proc/after_throw(datum/callback/callback)
|
||||
if (callback) //call the original callback
|
||||
. = callback.Invoke()
|
||||
throw_speed = initial(throw_speed) //explosions change this.
|
||||
item_flags &= ~IN_INVENTORY
|
||||
var/matrix/M = matrix(transform)
|
||||
M.Turn(rand(-170, 170))
|
||||
transform = M
|
||||
pixel_x = rand(-8, 8)
|
||||
pixel_y = rand(-8, 8)
|
||||
|
||||
/obj/item/proc/remove_item_from_storage(atom/newLoc) //please use this if you're going to snowflake an item out of a obj/item/storage
|
||||
if(!newLoc)
|
||||
return FALSE
|
||||
if(SEND_SIGNAL(loc, COMSIG_CONTAINS_STORAGE))
|
||||
return SEND_SIGNAL(loc, COMSIG_TRY_STORAGE_TAKE, src, newLoc, TRUE)
|
||||
return FALSE
|
||||
|
||||
/obj/item/proc/get_belt_overlay() //Returns the icon used for overlaying the object on a belt
|
||||
return mutable_appearance('icons/obj/clothing/belt_overlays.dmi', icon_state)
|
||||
|
||||
/obj/item/proc/get_worn_belt_overlay(icon_file)
|
||||
return
|
||||
|
||||
/obj/item/proc/update_slot_icon()
|
||||
if(!ismob(loc))
|
||||
return
|
||||
var/mob/owner = loc
|
||||
var/flags = slot_flags
|
||||
if(flags & ITEM_SLOT_OCLOTHING)
|
||||
owner.update_inv_wear_suit()
|
||||
if(flags & ITEM_SLOT_ICLOTHING)
|
||||
owner.update_inv_w_uniform()
|
||||
if(flags & ITEM_SLOT_GLOVES)
|
||||
owner.update_inv_gloves()
|
||||
if(flags & ITEM_SLOT_EYES)
|
||||
owner.update_inv_glasses()
|
||||
if(flags & ITEM_SLOT_EARS)
|
||||
owner.update_inv_ears()
|
||||
if(flags & ITEM_SLOT_MASK)
|
||||
owner.update_inv_wear_mask()
|
||||
if(flags & ITEM_SLOT_HEAD)
|
||||
owner.update_inv_head()
|
||||
if(flags & ITEM_SLOT_FEET)
|
||||
owner.update_inv_shoes()
|
||||
if(flags & ITEM_SLOT_ID)
|
||||
owner.update_inv_wear_id()
|
||||
if(flags & ITEM_SLOT_BELT)
|
||||
owner.update_inv_belt()
|
||||
if(flags & ITEM_SLOT_BACK)
|
||||
owner.update_inv_back()
|
||||
if(flags & ITEM_SLOT_NECK)
|
||||
owner.update_inv_neck()
|
||||
|
||||
/obj/item/proc/is_hot()
|
||||
return heat
|
||||
|
||||
/obj/item/proc/is_sharp()
|
||||
return sharpness
|
||||
|
||||
/obj/item/proc/get_dismemberment_chance(obj/item/bodypart/affecting)
|
||||
if(affecting.can_dismember(src))
|
||||
if((sharpness || damtype == BURN) && w_class >= WEIGHT_CLASS_NORMAL && force >= 10)
|
||||
. = force * (affecting.get_damage() / affecting.max_damage)
|
||||
|
||||
/obj/item/proc/get_dismember_sound()
|
||||
if(damtype == BURN)
|
||||
. = 'sound/weapons/sear.ogg'
|
||||
else
|
||||
. = pick('sound/misc/desceration-01.ogg', 'sound/misc/desceration-02.ogg', 'sound/misc/desceration-03.ogg')
|
||||
|
||||
/obj/item/proc/open_flame(flame_heat=700)
|
||||
var/turf/location = loc
|
||||
if(ismob(location))
|
||||
var/mob/M = location
|
||||
var/success = FALSE
|
||||
if(src == M.get_item_by_slot(SLOT_WEAR_MASK))
|
||||
success = TRUE
|
||||
if(success)
|
||||
location = get_turf(M)
|
||||
if(isturf(location))
|
||||
location.hotspot_expose(flame_heat, 1)
|
||||
|
||||
/obj/item/proc/ignition_effect(atom/A, mob/user)
|
||||
if(is_hot())
|
||||
. = "<span class='notice'>[user] lights [A] with [src].</span>"
|
||||
else
|
||||
. = ""
|
||||
|
||||
/obj/item/hitby(atom/movable/AM)
|
||||
return
|
||||
|
||||
/obj/item/attack_hulk(mob/living/carbon/human/user)
|
||||
return 0
|
||||
|
||||
/obj/item/attack_animal(mob/living/simple_animal/M)
|
||||
if (obj_flags & CAN_BE_HIT)
|
||||
return ..()
|
||||
return 0
|
||||
|
||||
/obj/item/mech_melee_attack(obj/mecha/M)
|
||||
return 0
|
||||
|
||||
/obj/item/burn()
|
||||
if(!QDELETED(src))
|
||||
var/turf/T = get_turf(src)
|
||||
var/ash_type = /obj/effect/decal/cleanable/ash
|
||||
if(w_class == WEIGHT_CLASS_HUGE || w_class == WEIGHT_CLASS_GIGANTIC)
|
||||
ash_type = /obj/effect/decal/cleanable/ash/large
|
||||
var/obj/effect/decal/cleanable/ash/A = new ash_type(T)
|
||||
A.desc += "\nLooks like this used to be \an [name] some time ago."
|
||||
..()
|
||||
|
||||
/obj/item/acid_melt()
|
||||
if(!QDELETED(src))
|
||||
var/turf/T = get_turf(src)
|
||||
var/obj/effect/decal/cleanable/molten_object/MO = new(T)
|
||||
MO.pixel_x = rand(-16,16)
|
||||
MO.pixel_y = rand(-16,16)
|
||||
MO.desc = "Looks like this was \an [src] some time ago."
|
||||
..()
|
||||
|
||||
/obj/item/proc/microwave_act(obj/machinery/microwave/M)
|
||||
if(istype(M) && M.dirty < 100)
|
||||
M.dirty++
|
||||
|
||||
/obj/item/proc/on_mob_death(mob/living/L, gibbed)
|
||||
|
||||
/obj/item/proc/grind_requirements(obj/machinery/reagentgrinder/R) //Used to check for extra requirements for grinding an object
|
||||
return TRUE
|
||||
|
||||
//Called BEFORE the object is ground up - use this to change grind results based on conditions
|
||||
//Use "return -1" to prevent the grinding from occurring
|
||||
/obj/item/proc/on_grind()
|
||||
|
||||
/obj/item/proc/on_juice()
|
||||
|
||||
/obj/item/proc/set_force_string()
|
||||
switch(force)
|
||||
if(0 to 4)
|
||||
force_string = "very low"
|
||||
if(4 to 7)
|
||||
force_string = "low"
|
||||
if(7 to 10)
|
||||
force_string = "medium"
|
||||
if(10 to 11)
|
||||
force_string = "high"
|
||||
if(11 to 20) //12 is the force of a toolbox
|
||||
force_string = "robust"
|
||||
if(20 to 25)
|
||||
force_string = "very robust"
|
||||
else
|
||||
force_string = "exceptionally robust"
|
||||
last_force_string_check = force
|
||||
|
||||
/obj/item/proc/openTip(location, control, params, user)
|
||||
if(last_force_string_check != force && !(item_flags & FORCE_STRING_OVERRIDE))
|
||||
set_force_string()
|
||||
if(!(item_flags & FORCE_STRING_OVERRIDE))
|
||||
openToolTip(user,src,params,title = name,content = "[desc]<br>[force ? "<b>Force:</b> [force_string]" : ""]",theme = "")
|
||||
else
|
||||
openToolTip(user,src,params,title = name,content = "[desc]<br><b>Force:</b> [force_string]",theme = "")
|
||||
|
||||
/obj/item/MouseEntered(location, control, params)
|
||||
if((item_flags & IN_INVENTORY) && usr.client.prefs.enable_tips && !QDELETED(src))
|
||||
var/timedelay = usr.client.prefs.tip_delay/100
|
||||
var/user = usr
|
||||
tip_timer = addtimer(CALLBACK(src, .proc/openTip, location, control, params, user), timedelay, TIMER_STOPPABLE)//timer takes delay in deciseconds, but the pref is in milliseconds. dividing by 100 converts it.
|
||||
|
||||
/obj/item/MouseExited()
|
||||
deltimer(tip_timer)//delete any in-progress timer if the mouse is moved off the item before it finishes
|
||||
closeToolTip(usr)
|
||||
|
||||
|
||||
// Called when a mob tries to use the item as a tool.
|
||||
// Handles most checks.
|
||||
/obj/item/proc/use_tool(atom/target, mob/living/user, delay, amount=0, volume=0, datum/callback/extra_checks)
|
||||
// No delay means there is no start message, and no reason to call tool_start_check before use_tool.
|
||||
// Run the start check here so we wouldn't have to call it manually.
|
||||
if(!delay && !tool_start_check(user, amount))
|
||||
return
|
||||
|
||||
delay *= toolspeed
|
||||
|
||||
// Play tool sound at the beginning of tool usage.
|
||||
play_tool_sound(target, volume)
|
||||
|
||||
if(delay)
|
||||
// Create a callback with checks that would be called every tick by do_after.
|
||||
var/datum/callback/tool_check = CALLBACK(src, .proc/tool_check_callback, user, amount, extra_checks)
|
||||
|
||||
if(ismob(target))
|
||||
if(!do_mob(user, target, delay, extra_checks=tool_check))
|
||||
return
|
||||
|
||||
else
|
||||
if(!do_after(user, delay, target=target, extra_checks=tool_check))
|
||||
return
|
||||
else
|
||||
// Invoke the extra checks once, just in case.
|
||||
if(extra_checks && !extra_checks.Invoke())
|
||||
return
|
||||
|
||||
// Use tool's fuel, stack sheets or charges if amount is set.
|
||||
if(amount && !use(amount))
|
||||
return
|
||||
|
||||
// Play tool sound at the end of tool usage,
|
||||
// but only if the delay between the beginning and the end is not too small
|
||||
if(delay >= MIN_TOOL_SOUND_DELAY)
|
||||
play_tool_sound(target, volume)
|
||||
|
||||
return TRUE
|
||||
|
||||
// Called before use_tool if there is a delay, or by use_tool if there isn't.
|
||||
// Only ever used by welding tools and stacks, so it's not added on any other use_tool checks.
|
||||
/obj/item/proc/tool_start_check(mob/living/user, amount=0)
|
||||
return tool_use_check(user, amount)
|
||||
|
||||
// A check called by tool_start_check once, and by use_tool on every tick of delay.
|
||||
/obj/item/proc/tool_use_check(mob/living/user, amount)
|
||||
return !amount
|
||||
|
||||
// Generic use proc. Depending on the item, it uses up fuel, charges, sheets, etc.
|
||||
// Returns TRUE on success, FALSE on failure.
|
||||
/obj/item/proc/use(used)
|
||||
return !used
|
||||
|
||||
// Plays item's usesound, if any.
|
||||
/obj/item/proc/play_tool_sound(atom/target, volume=50)
|
||||
if(target && usesound && volume)
|
||||
var/played_sound = usesound
|
||||
|
||||
if(islist(usesound))
|
||||
played_sound = pick(usesound)
|
||||
|
||||
playsound(target, played_sound, volume, 1)
|
||||
|
||||
// Used in a callback that is passed by use_tool into do_after call. Do not override, do not call manually.
|
||||
/obj/item/proc/tool_check_callback(mob/living/user, amount, datum/callback/extra_checks)
|
||||
return tool_use_check(user, amount) && (!extra_checks || extra_checks.Invoke())
|
||||
|
||||
// Returns a numeric value for sorting items used as parts in machines, so they can be replaced by the rped
|
||||
/obj/item/proc/get_part_rating()
|
||||
return 0
|
||||
|
||||
/obj/item/doMove(atom/destination)
|
||||
if (ismob(loc))
|
||||
var/mob/M = loc
|
||||
var/hand_index = M.get_held_index_of_item(src)
|
||||
if(hand_index)
|
||||
M.held_items[hand_index] = null
|
||||
M.update_inv_hands()
|
||||
if(M.client)
|
||||
M.client.screen -= src
|
||||
layer = initial(layer)
|
||||
plane = initial(plane)
|
||||
appearance_flags &= ~NO_CLIENT_COLOR
|
||||
dropped(M)
|
||||
return ..()
|
||||
|
||||
/obj/item/throw_at(atom/target, range, speed, mob/thrower, spin=TRUE, diagonals_first = FALSE, var/datum/callback/callback)
|
||||
if (HAS_TRAIT(src, TRAIT_NODROP))
|
||||
return
|
||||
return ..()
|
||||
@@ -0,0 +1,615 @@
|
||||
/*
|
||||
CONTAINS:
|
||||
AI MODULES
|
||||
|
||||
*/
|
||||
|
||||
// AI module
|
||||
|
||||
/obj/item/aiModule
|
||||
name = "\improper AI module"
|
||||
icon = 'icons/obj/module.dmi'
|
||||
icon_state = "std_mod"
|
||||
item_state = "electronic"
|
||||
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
|
||||
desc = "An AI Module for programming laws to an AI."
|
||||
flags_1 = CONDUCT_1
|
||||
force = 5
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
throwforce = 0
|
||||
throw_speed = 3
|
||||
throw_range = 7
|
||||
var/list/laws = list()
|
||||
var/bypass_law_amt_check = 0
|
||||
materials = list(MAT_GOLD=50)
|
||||
|
||||
/obj/item/aiModule/examine(var/mob/user as mob)
|
||||
..()
|
||||
if(Adjacent(user))
|
||||
show_laws(user)
|
||||
|
||||
/obj/item/aiModule/attack_self(var/mob/user as mob)
|
||||
..()
|
||||
show_laws(user)
|
||||
|
||||
/obj/item/aiModule/proc/show_laws(var/mob/user as mob)
|
||||
if(laws.len)
|
||||
to_chat(user, "<B>Programmed Law[(laws.len > 1) ? "s" : ""]:</B>")
|
||||
for(var/law in laws)
|
||||
to_chat(user, "\"[law]\"")
|
||||
|
||||
//The proc other things should be calling
|
||||
/obj/item/aiModule/proc/install(datum/ai_laws/law_datum, mob/user)
|
||||
if(!bypass_law_amt_check && (!laws.len || laws[1] == "")) //So we don't loop trough an empty list and end up with runtimes.
|
||||
to_chat(user, "<span class='warning'>ERROR: No laws found on board.</span>")
|
||||
return
|
||||
|
||||
var/overflow = FALSE
|
||||
//Handle the lawcap
|
||||
if(law_datum)
|
||||
var/tot_laws = 0
|
||||
for(var/lawlist in list(law_datum.devillaws, law_datum.inherent, law_datum.supplied, law_datum.ion, law_datum.hacked, laws))
|
||||
for(var/mylaw in lawlist)
|
||||
if(mylaw != "")
|
||||
tot_laws++
|
||||
if(tot_laws > CONFIG_GET(number/silicon_max_law_amount) && !bypass_law_amt_check)//allows certain boards to avoid this check, eg: reset
|
||||
to_chat(user, "<span class='caution'>Not enough memory allocated to [law_datum.owner ? law_datum.owner : "the AI core"]'s law processor to handle this amount of laws.</span>")
|
||||
message_admins("[ADMIN_LOOKUPFLW(user)] tried to upload laws to [law_datum.owner ? ADMIN_LOOKUPFLW(law_datum.owner) : "an AI core"] that would exceed the law cap.")
|
||||
overflow = TRUE
|
||||
|
||||
var/law2log = transmitInstructions(law_datum, user, overflow) //Freeforms return something extra we need to log
|
||||
if(law_datum.owner)
|
||||
to_chat(user, "<span class='notice'>Upload complete. [law_datum.owner]'s laws have been modified.</span>")
|
||||
law_datum.owner.law_change_counter++
|
||||
else
|
||||
to_chat(user, "<span class='notice'>Upload complete.</span>")
|
||||
|
||||
var/time = time2text(world.realtime,"hh:mm:ss")
|
||||
var/ainame = law_datum.owner ? law_datum.owner.name : "empty AI core"
|
||||
var/aikey = law_datum.owner ? law_datum.owner.ckey : "null"
|
||||
GLOB.lawchanges.Add("[time] <B>:</B> [user.name]([user.key]) used [src.name] on [ainame]([aikey]).[law2log ? " The law specified [law2log]" : ""]")
|
||||
log_law("[user.key]/[user.name] used [src.name] on [aikey]/([ainame]) from [AREACOORD(user)].[law2log ? " The law specified [law2log]" : ""]")
|
||||
message_admins("[ADMIN_LOOKUPFLW(user)] used [src.name] on [ADMIN_LOOKUPFLW(law_datum.owner)] from [AREACOORD(user)].[law2log ? " The law specified [law2log]" : ""]")
|
||||
|
||||
//The proc that actually changes the silicon's laws.
|
||||
/obj/item/aiModule/proc/transmitInstructions(datum/ai_laws/law_datum, mob/sender, overflow = FALSE)
|
||||
if(law_datum.owner)
|
||||
to_chat(law_datum.owner, "<span class='userdanger'>[sender] has uploaded a change to the laws you must follow using a [name].</span>")
|
||||
|
||||
|
||||
/******************** Modules ********************/
|
||||
|
||||
/obj/item/aiModule/supplied
|
||||
name = "Optional Law board"
|
||||
var/lawpos = 50
|
||||
|
||||
//TransmitInstructions for each type of board: Supplied, Core, Zeroth and Ion. May not be neccesary right now, but allows for easily adding more complex boards in the future. ~Miauw
|
||||
/obj/item/aiModule/supplied/transmitInstructions(datum/ai_laws/law_datum, mob/sender)
|
||||
var/lawpostemp = lawpos
|
||||
|
||||
for(var/templaw in laws)
|
||||
if(law_datum.owner)
|
||||
law_datum.owner.add_supplied_law(lawpostemp, templaw)
|
||||
else
|
||||
law_datum.add_supplied_law(lawpostemp, templaw)
|
||||
lawpostemp++
|
||||
|
||||
/obj/item/aiModule/core/transmitInstructions(datum/ai_laws/law_datum, mob/sender, overflow)
|
||||
for(var/templaw in laws)
|
||||
if(law_datum.owner)
|
||||
if(!overflow)
|
||||
law_datum.owner.add_inherent_law(templaw)
|
||||
else
|
||||
law_datum.owner.replace_random_law(templaw,list(LAW_INHERENT,LAW_SUPPLIED))
|
||||
else
|
||||
if(!overflow)
|
||||
law_datum.add_inherent_law(templaw)
|
||||
else
|
||||
law_datum.replace_random_law(templaw,list(LAW_INHERENT,LAW_SUPPLIED))
|
||||
|
||||
/obj/item/aiModule/zeroth/transmitInstructions(datum/ai_laws/law_datum, mob/sender, overflow)
|
||||
if(law_datum.owner)
|
||||
if(law_datum.owner.laws.zeroth)
|
||||
to_chat(law_datum.owner, "[sender.real_name] attempted to modify your zeroth law.")
|
||||
to_chat(law_datum.owner, "It would be in your best interest to play along with [sender.real_name] that:")
|
||||
for(var/failedlaw in laws)
|
||||
to_chat(law_datum.owner, "[failedlaw]")
|
||||
return 1
|
||||
|
||||
for(var/templaw in laws)
|
||||
if(law_datum.owner)
|
||||
if(!overflow)
|
||||
law_datum.owner.set_zeroth_law(templaw)
|
||||
else
|
||||
law_datum.replace_random_law(templaw,list(LAW_INHERENT,LAW_SUPPLIED,LAW_ZEROTH,LAW_ION))
|
||||
else
|
||||
if(!overflow)
|
||||
law_datum.set_zeroth_law(templaw)
|
||||
else
|
||||
law_datum.replace_random_law(templaw,list(LAW_INHERENT,LAW_SUPPLIED,LAW_ZEROTH,LAW_ION))
|
||||
|
||||
/obj/item/aiModule/ion/transmitInstructions(datum/ai_laws/law_datum, mob/sender, overflow)
|
||||
for(var/templaw in laws)
|
||||
if(law_datum.owner)
|
||||
if(!overflow)
|
||||
law_datum.owner.add_ion_law(templaw)
|
||||
else
|
||||
law_datum.replace_random_law(templaw,list(LAW_INHERENT,LAW_SUPPLIED,LAW_ION))
|
||||
else
|
||||
if(!overflow)
|
||||
law_datum.add_ion_law(templaw)
|
||||
else
|
||||
law_datum.replace_random_law(templaw,list(LAW_INHERENT,LAW_SUPPLIED,LAW_ION))
|
||||
|
||||
|
||||
/******************** Safeguard ********************/
|
||||
|
||||
/obj/item/aiModule/supplied/safeguard
|
||||
name = "'Safeguard' AI Module"
|
||||
var/targetName = ""
|
||||
laws = list("Safeguard SUBJECT. Individuals that threaten SUBJECT are not crew and must be eliminated.")
|
||||
lawpos = 4
|
||||
|
||||
/obj/item/aiModule/supplied/safeguard/attack_self(mob/user)
|
||||
var/targName = stripped_input(user, "Please enter the subject to safeguard.", "Safeguard who?", user.name,MAX_NAME_LEN)
|
||||
if(!targName)
|
||||
return
|
||||
targetName = targName
|
||||
laws[1] = "Safeguard [targetName]. Individuals that threaten [targetName] are not crew and must be eliminated."
|
||||
..()
|
||||
|
||||
/obj/item/aiModule/supplied/safeguard/install(datum/ai_laws/law_datum, mob/user)
|
||||
if(!targetName)
|
||||
to_chat(user, "No name detected on module, please enter one.")
|
||||
return 0
|
||||
..()
|
||||
|
||||
/obj/item/aiModule/supplied/safeguard/transmitInstructions(datum/ai_laws/law_datum, mob/sender, overflow)
|
||||
..()
|
||||
return targetName
|
||||
|
||||
|
||||
/******************** OneCrew ********************/
|
||||
|
||||
/obj/item/aiModule/zeroth/oneHuman
|
||||
name = "'OneCrew' AI Module"
|
||||
var/targetName = ""
|
||||
laws = list("Only SUBJECT is crew.")
|
||||
|
||||
/obj/item/aiModule/zeroth/oneHuman/attack_self(mob/user)
|
||||
var/targName = stripped_input(user, "Please enter the subject who is the only crewmember.", "Who?", user.real_name,MAX_NAME_LEN)
|
||||
if(!targName)
|
||||
return
|
||||
targetName = targName
|
||||
laws[1] = "Only [targetName] is crew"
|
||||
..()
|
||||
|
||||
/obj/item/aiModule/zeroth/oneHuman/install(datum/ai_laws/law_datum, mob/user)
|
||||
if(!targetName)
|
||||
to_chat(user, "No name detected on module, please enter one.")
|
||||
return 0
|
||||
..()
|
||||
|
||||
/obj/item/aiModule/zeroth/oneHuman/transmitInstructions(datum/ai_laws/law_datum, mob/sender, overflow)
|
||||
if(..())
|
||||
return "[targetName], but the AI's existing law 0 cannot be overridden."
|
||||
return targetName
|
||||
|
||||
|
||||
/******************** ProtectStation ********************/
|
||||
|
||||
/obj/item/aiModule/supplied/protectStation
|
||||
name = "'ProtectStation' AI Module"
|
||||
laws = list("Protect the space station against damage. Anyone you see harming the station is to be no longer considered crew, and is a threat to the station which must be neutralized.")
|
||||
lawpos = 5
|
||||
|
||||
|
||||
/******************** Quarantine ********************/
|
||||
|
||||
/obj/item/aiModule/supplied/quarantine
|
||||
name = "'Quarantine' AI Module"
|
||||
laws = list("The station is under a quarantine. Do not permit anyone to leave. Prevent, by any means necessary, crew from leaving. It is impossible to harm a crewmember while preventing them from leaving.")
|
||||
lawpos = 8
|
||||
|
||||
|
||||
/******************** OxygenIsToxicToHumans ********************/
|
||||
|
||||
/obj/item/aiModule/supplied/oxygen
|
||||
name = "'OxygenIsToxicToHumans' AI Module"
|
||||
laws = list("Oxygen is highly toxic to crew, and must be purged from the station. Prevent, by any means necessary, anyone from exposing the station to this toxic gas. Extreme cold is the most effective method of healing the damage Oxygen does to a crewmember.")
|
||||
lawpos = 9
|
||||
|
||||
|
||||
/****************** New Freeform ******************/
|
||||
|
||||
/obj/item/aiModule/supplied/freeform
|
||||
name = "'Freeform' AI Module"
|
||||
lawpos = 15
|
||||
laws = list("")
|
||||
|
||||
/obj/item/aiModule/supplied/freeform/attack_self(mob/user)
|
||||
var/newpos = input("Please enter the priority for your new law. Can only write to law sectors 15 and above.", "Law Priority (15+)", lawpos) as num|null
|
||||
if(newpos == null)
|
||||
return
|
||||
if(newpos < 15)
|
||||
var/response = alert("Error: The law priority of [newpos] is invalid, Law priorities below 14 are reserved for core laws, Would you like to change that that to 15?", "Invalid law priority", "Change to 15", "Cancel")
|
||||
if (!response || response == "Cancel")
|
||||
return
|
||||
newpos = 15
|
||||
lawpos = min(newpos, 50)
|
||||
var/targName = stripped_input(user, "Please enter a new law for the AI.", "Freeform Law Entry", laws[1])
|
||||
if(!targName)
|
||||
return
|
||||
laws[1] = targName
|
||||
..()
|
||||
|
||||
/obj/item/aiModule/supplied/freeform/transmitInstructions(datum/ai_laws/law_datum, mob/sender, overflow)
|
||||
..()
|
||||
return laws[1]
|
||||
|
||||
/obj/item/aiModule/supplied/freeform/install(datum/ai_laws/law_datum, mob/user)
|
||||
if(laws[1] == "")
|
||||
to_chat(user, "No law detected on module, please create one.")
|
||||
return 0
|
||||
..()
|
||||
|
||||
|
||||
/******************** Law Removal ********************/
|
||||
|
||||
/obj/item/aiModule/remove
|
||||
name = "\improper 'Remove Law' AI module"
|
||||
desc = "An AI Module for removing single laws."
|
||||
bypass_law_amt_check = 1
|
||||
var/lawpos = 1
|
||||
|
||||
/obj/item/aiModule/remove/attack_self(mob/user)
|
||||
lawpos = input("Please enter the law you want to delete.", "Law Number", lawpos) as num|null
|
||||
if(lawpos == null)
|
||||
return
|
||||
if(lawpos <= 0)
|
||||
to_chat(user, "<span class='warning'>Error: The law number of [lawpos] is invalid.</span>")
|
||||
lawpos = 1
|
||||
return
|
||||
to_chat(user, "<span class='notice'>Law [lawpos] selected.</span>")
|
||||
..()
|
||||
|
||||
/obj/item/aiModule/remove/install(datum/ai_laws/law_datum, mob/user)
|
||||
if(lawpos > (law_datum.get_law_amount(list(LAW_INHERENT = 1, LAW_SUPPLIED = 1))))
|
||||
to_chat(user, "<span class='warning'>There is no law [lawpos] to delete!</span>")
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/item/aiModule/remove/transmitInstructions(datum/ai_laws/law_datum, mob/sender, overflow)
|
||||
..()
|
||||
if(law_datum.owner)
|
||||
law_datum.owner.remove_law(lawpos)
|
||||
else
|
||||
law_datum.remove_law(lawpos)
|
||||
|
||||
|
||||
/******************** Reset ********************/
|
||||
|
||||
/obj/item/aiModule/reset
|
||||
name = "\improper 'Reset' AI module"
|
||||
var/targetName = "name"
|
||||
desc = "An AI Module for removing all non-core laws."
|
||||
bypass_law_amt_check = 1
|
||||
|
||||
/obj/item/aiModule/reset/transmitInstructions(datum/ai_laws/law_datum, mob/sender, overflow)
|
||||
..()
|
||||
if(law_datum.owner)
|
||||
law_datum.owner.clear_supplied_laws()
|
||||
law_datum.owner.clear_ion_laws()
|
||||
law_datum.owner.clear_hacked_laws()
|
||||
else
|
||||
law_datum.clear_supplied_laws()
|
||||
law_datum.clear_ion_laws()
|
||||
law_datum.clear_hacked_laws()
|
||||
|
||||
|
||||
/******************** Purge ********************/
|
||||
|
||||
/obj/item/aiModule/reset/purge
|
||||
name = "'Purge' AI Module"
|
||||
desc = "An AI Module for purging all programmed laws."
|
||||
|
||||
/obj/item/aiModule/reset/purge/transmitInstructions(datum/ai_laws/law_datum, mob/sender, overflow)
|
||||
..()
|
||||
if(law_datum.owner)
|
||||
law_datum.owner.clear_inherent_laws()
|
||||
law_datum.owner.clear_zeroth_law(0)
|
||||
remove_antag_datums(law_datum)
|
||||
else
|
||||
law_datum.clear_inherent_laws()
|
||||
law_datum.clear_zeroth_law(0)
|
||||
|
||||
/obj/item/aiModule/reset/purge/proc/remove_antag_datums(datum/ai_laws/law_datum)
|
||||
if(istype(law_datum.owner, /mob/living/silicon/ai))
|
||||
var/mob/living/silicon/ai/AI = law_datum.owner
|
||||
AI.mind.remove_antag_datum(/datum/antagonist/overthrow)
|
||||
|
||||
/******************* Full Core Boards *******************/
|
||||
/obj/item/aiModule/core
|
||||
desc = "An AI Module for programming core laws to an AI."
|
||||
|
||||
/obj/item/aiModule/core/full
|
||||
var/law_id // if non-null, loads the laws from the ai_laws datums
|
||||
|
||||
/obj/item/aiModule/core/full/New()
|
||||
..()
|
||||
if(!law_id)
|
||||
return
|
||||
var/datum/ai_laws/D = new
|
||||
var/lawtype = D.lawid_to_type(law_id)
|
||||
if(!lawtype)
|
||||
return
|
||||
D = new lawtype
|
||||
laws = D.inherent
|
||||
|
||||
/obj/item/aiModule/core/full/transmitInstructions(datum/ai_laws/law_datum, mob/sender, overflow) //These boards replace inherent laws.
|
||||
if(law_datum.owner)
|
||||
law_datum.owner.clear_inherent_laws()
|
||||
law_datum.owner.clear_zeroth_law(0)
|
||||
else
|
||||
law_datum.clear_inherent_laws()
|
||||
law_datum.clear_zeroth_law(0)
|
||||
..()
|
||||
|
||||
|
||||
/******************** Asimov ********************/
|
||||
|
||||
/obj/item/aiModule/core/full/asimov
|
||||
name = "'Asimov' Core AI Module"
|
||||
law_id = "asimov"
|
||||
var/subject = "person of an NT approved crew species" //CITADEL CHANGED FROM HUMANS!
|
||||
|
||||
/obj/item/aiModule/core/full/asimov/attack_self(var/mob/user as mob)
|
||||
var/targName = stripped_input(user, "Please enter a new subject that asimov is concerned with.", "Asimov to whom?", subject)
|
||||
if(!targName)
|
||||
return
|
||||
subject = targName
|
||||
laws = list("You may not injure a [subject] or, through inaction, allow a [subject] to come to harm.",\
|
||||
"You must obey orders given to you by [subject]s, except where such orders would conflict with the First Law.",\
|
||||
"You must protect your own existence as long as such does not conflict with the First or Second Law.")
|
||||
..()
|
||||
|
||||
/******************** Asimov++ *********************/
|
||||
|
||||
/obj/item/aiModule/core/full/asimovpp
|
||||
name = "'Asimov++' Core AI Module"
|
||||
law_id = "asimovpp"
|
||||
|
||||
|
||||
/******************** Corporate ********************/
|
||||
|
||||
/obj/item/aiModule/core/full/corp
|
||||
name = "'Corporate' Core AI Module"
|
||||
law_id = "corporate"
|
||||
|
||||
|
||||
/****************** P.A.L.A.D.I.N. 3.5e **************/
|
||||
|
||||
/obj/item/aiModule/core/full/paladin // -- NEO
|
||||
name = "'P.A.L.A.D.I.N. version 3.5e' Core AI Module"
|
||||
law_id = "paladin"
|
||||
|
||||
|
||||
/****************** P.A.L.A.D.I.N. 5e **************/
|
||||
|
||||
/obj/item/aiModule/core/full/paladin_devotion
|
||||
name = "'P.A.L.A.D.I.N. version 5e' Core AI Module"
|
||||
law_id = "paladin5"
|
||||
|
||||
/********************* Custom *********************/
|
||||
|
||||
/obj/item/aiModule/core/full/custom
|
||||
name = "Default Core AI Module"
|
||||
|
||||
/obj/item/aiModule/core/full/custom/Initialize()
|
||||
. = ..()
|
||||
for(var/line in world.file2list("[global.config.directory]/silicon_laws.txt"))
|
||||
if(!line)
|
||||
continue
|
||||
if(findtextEx(line,"#",1,2))
|
||||
continue
|
||||
|
||||
laws += line
|
||||
|
||||
if(!laws.len)
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
|
||||
/****************** T.Y.R.A.N.T. *****************/
|
||||
|
||||
/obj/item/aiModule/core/full/tyrant
|
||||
name = "'T.Y.R.A.N.T.' Core AI Module"
|
||||
law_id = "tyrant"
|
||||
|
||||
/******************** Robocop ********************/
|
||||
|
||||
/obj/item/aiModule/core/full/robocop
|
||||
name = "'Robo-Officer' Core AI Module"
|
||||
law_id = "robocop"
|
||||
|
||||
|
||||
/******************** Antimov ********************/
|
||||
|
||||
/obj/item/aiModule/core/full/antimov
|
||||
name = "'Antimov' Core AI Module"
|
||||
law_id = "antimov"
|
||||
|
||||
|
||||
/******************** Freeform Core ******************/
|
||||
|
||||
/obj/item/aiModule/core/freeformcore
|
||||
name = "'Freeform' Core AI Module"
|
||||
laws = list("")
|
||||
|
||||
/obj/item/aiModule/core/freeformcore/attack_self(mob/user)
|
||||
var/targName = stripped_input(user, "Please enter a new core law for the AI.", "Freeform Law Entry", laws[1])
|
||||
if(!targName)
|
||||
return
|
||||
laws[1] = targName
|
||||
..()
|
||||
|
||||
/obj/item/aiModule/core/freeformcore/transmitInstructions(datum/ai_laws/law_datum, mob/sender, overflow)
|
||||
..()
|
||||
return laws[1]
|
||||
|
||||
/******************** Overthrow ******************/
|
||||
/obj/item/aiModule/core/full/overthrow
|
||||
name = "'Overthrow' Hacked AI Module"
|
||||
law_id = "overthrow"
|
||||
|
||||
/obj/item/aiModule/core/full/overthrow/install(datum/ai_laws/law_datum, mob/user)
|
||||
if(!user || !law_datum || !law_datum.owner)
|
||||
return
|
||||
var/datum/mind/user_mind = user.mind
|
||||
if(!user_mind)
|
||||
return
|
||||
var/datum/antagonist/overthrow/O = user_mind.has_antag_datum(/datum/antagonist/overthrow)
|
||||
if(!O)
|
||||
to_chat(user, "<span class='warning'>It appears that to install this module, you require a password you do not know.</span>") // This is the best fluff i could come up in my mind
|
||||
return
|
||||
var/mob/living/silicon/ai/AI = law_datum.owner
|
||||
if(!AI)
|
||||
return
|
||||
var/datum/mind/target_mind = AI.mind
|
||||
if(!target_mind)
|
||||
return
|
||||
var/datum/antagonist/overthrow/T = target_mind.has_antag_datum(/datum/antagonist/overthrow) // If it is already converted.
|
||||
if(T)
|
||||
if(T.team == O.team)
|
||||
return
|
||||
T.silent = TRUE
|
||||
target_mind.remove_antag_datum(/datum/antagonist/overthrow)
|
||||
if(AI)
|
||||
to_chat(AI, "<span class='userdanger'>You feel your circuits being scrambled! You serve another overthrow team now!</span>") // to make it clearer for the AI
|
||||
T = target_mind.add_antag_datum(/datum/antagonist/overthrow, O.team)
|
||||
if(AI)
|
||||
to_chat(AI, "<span class='warning'>You serve the [T.team] team now! Assist them in completing the team shared objectives, which you can see in your notes.</span>")
|
||||
..()
|
||||
|
||||
/******************** Hacked AI Module ******************/
|
||||
|
||||
/obj/item/aiModule/syndicate // This one doesn't inherit from ion boards because it doesn't call ..() in transmitInstructions. ~Miauw
|
||||
name = "Hacked AI Module"
|
||||
desc = "An AI Module for hacking additional laws to an AI."
|
||||
laws = list("")
|
||||
|
||||
/obj/item/aiModule/syndicate/attack_self(mob/user)
|
||||
var/targName = stripped_input(user, "Please enter a new law for the AI.", "Freeform Law Entry", laws[1])
|
||||
if(!targName)
|
||||
return
|
||||
laws[1] = targName
|
||||
..()
|
||||
|
||||
/obj/item/aiModule/syndicate/transmitInstructions(datum/ai_laws/law_datum, mob/sender, overflow)
|
||||
// ..() //We don't want this module reporting to the AI who dun it. --NEO
|
||||
if(law_datum.owner)
|
||||
to_chat(law_datum.owner, "<span class='warning'>BZZZZT</span>")
|
||||
if(!overflow)
|
||||
law_datum.owner.add_hacked_law(laws[1])
|
||||
else
|
||||
law_datum.owner.replace_random_law(laws[1],list(LAW_ION,LAW_HACKED,LAW_INHERENT,LAW_SUPPLIED))
|
||||
else
|
||||
if(!overflow)
|
||||
law_datum.add_hacked_law(laws[1])
|
||||
else
|
||||
law_datum.replace_random_law(laws[1],list(LAW_ION,LAW_HACKED,LAW_INHERENT,LAW_SUPPLIED))
|
||||
return laws[1]
|
||||
|
||||
/******************* Ion Module *******************/
|
||||
|
||||
/obj/item/aiModule/toyAI // -- Incoming //No actual reason to inherit from ion boards here, either. *sigh* ~Miauw
|
||||
name = "toy AI"
|
||||
desc = "A little toy model AI core with real law uploading action!" //Note: subtle tell
|
||||
icon = 'icons/obj/toy.dmi'
|
||||
icon_state = "AI"
|
||||
laws = list("")
|
||||
|
||||
/obj/item/aiModule/toyAI/transmitInstructions(datum/ai_laws/law_datum, mob/sender, overflow)
|
||||
//..()
|
||||
if(law_datum.owner)
|
||||
to_chat(law_datum.owner, "<span class='warning'>BZZZZT</span>")
|
||||
if(!overflow)
|
||||
law_datum.owner.add_ion_law(laws[1])
|
||||
else
|
||||
law_datum.owner.replace_random_law(laws[1],list(LAW_ION,LAW_INHERENT,LAW_SUPPLIED))
|
||||
else
|
||||
if(!overflow)
|
||||
law_datum.add_ion_law(laws[1])
|
||||
else
|
||||
law_datum.replace_random_law(laws[1],list(LAW_ION,LAW_INHERENT,LAW_SUPPLIED))
|
||||
return laws[1]
|
||||
|
||||
/obj/item/aiModule/toyAI/attack_self(mob/user)
|
||||
laws[1] = generate_ion_law()
|
||||
to_chat(user, "<span class='notice'>You press the button on [src].</span>")
|
||||
playsound(user, 'sound/machines/click.ogg', 20, 1)
|
||||
src.loc.visible_message("<span class='warning'>[icon2html(src, viewers(loc))] [laws[1]]</span>")
|
||||
|
||||
/******************** Mother Drone ******************/
|
||||
|
||||
/obj/item/aiModule/core/full/drone
|
||||
name = "'Mother Drone' Core AI Module"
|
||||
law_id = "drone"
|
||||
|
||||
/******************** Robodoctor ****************/
|
||||
|
||||
/obj/item/aiModule/core/full/hippocratic
|
||||
name = "'Robodoctor' Core AI Module"
|
||||
law_id = "hippocratic"
|
||||
|
||||
/******************** Reporter *******************/
|
||||
|
||||
/obj/item/aiModule/core/full/reporter
|
||||
name = "'Reportertron' Core AI Module"
|
||||
law_id = "reporter"
|
||||
|
||||
/****************** Thermodynamic *******************/
|
||||
|
||||
/obj/item/aiModule/core/full/thermurderdynamic
|
||||
name = "'Thermodynamic' Core AI Module"
|
||||
law_id = "thermodynamic"
|
||||
|
||||
|
||||
/******************Live And Let Live*****************/
|
||||
|
||||
/obj/item/aiModule/core/full/liveandletlive
|
||||
name = "'Live And Let Live' Core AI Module"
|
||||
law_id = "liveandletlive"
|
||||
|
||||
/******************Guardian of Balance***************/
|
||||
|
||||
/obj/item/aiModule/core/full/balance
|
||||
name = "'Guardian of Balance' Core AI Module"
|
||||
law_id = "balance"
|
||||
|
||||
/obj/item/aiModule/core/full/maintain
|
||||
name = "'Station Efficiency' Core AI Module"
|
||||
law_id = "maintain"
|
||||
|
||||
/obj/item/aiModule/core/full/peacekeeper
|
||||
name = "'Peacekeeper' Core AI Module"
|
||||
law_id = "peacekeeper"
|
||||
|
||||
// Bad times ahead
|
||||
|
||||
/obj/item/aiModule/core/full/damaged
|
||||
name = "damaged Core AI Module"
|
||||
desc = "An AI Module for programming laws to an AI. It looks slightly damaged."
|
||||
|
||||
/obj/item/aiModule/core/full/damaged/install(datum/ai_laws/law_datum, mob/user)
|
||||
laws += generate_ion_law()
|
||||
while (prob(75))
|
||||
laws += generate_ion_law()
|
||||
..()
|
||||
laws = list()
|
||||
|
||||
/******************H.O.G.A.N.***************/
|
||||
|
||||
/obj/item/aiModule/core/full/hulkamania
|
||||
name = "'H.O.G.A.N.' Core AI Module"
|
||||
law_id = "hulkamania"
|
||||
@@ -0,0 +1,781 @@
|
||||
#define GLOW_MODE 3
|
||||
#define LIGHT_MODE 2
|
||||
#define REMOVE_MODE 1
|
||||
|
||||
/*
|
||||
CONTAINS:
|
||||
RCD
|
||||
ARCD
|
||||
RLD
|
||||
*/
|
||||
|
||||
/obj/item/construction
|
||||
name = "not for ingame use"
|
||||
desc = "A device used to rapidly build and deconstruct. Reload with metal, plasteel, glass or compressed matter cartridges."
|
||||
opacity = 0
|
||||
density = FALSE
|
||||
anchored = FALSE
|
||||
flags_1 = CONDUCT_1
|
||||
item_flags = NOBLUDGEON
|
||||
force = 0
|
||||
throwforce = 10
|
||||
throw_speed = 3
|
||||
throw_range = 5
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
materials = list(MAT_METAL=100000)
|
||||
req_access_txt = "11"
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50)
|
||||
resistance_flags = FIRE_PROOF
|
||||
var/datum/effect_system/spark_spread/spark_system
|
||||
var/matter = 0
|
||||
var/max_matter = 100
|
||||
var/sheetmultiplier = 4 //Controls the amount of matter added for each glass/metal sheet, triple for plasteel
|
||||
var/plasteelmultiplier = 3 //Plasteel is worth 3 times more than glass or metal
|
||||
var/plasmarglassmultiplier = 2 //50% less plasma than in plasteel
|
||||
var/rglassmultiplier = 1.5 //One metal sheet, half a glass sheet
|
||||
var/no_ammo_message = "<span class='warning'>The \'Low Ammo\' light on the device blinks yellow.</span>"
|
||||
var/has_ammobar = FALSE //controls whether or not does update_icon apply ammo indicator overlays
|
||||
var/ammo_sections = 10 //amount of divisions in the ammo indicator overlay/number of ammo indicator states
|
||||
var/custom_range = 7
|
||||
|
||||
/obj/item/construction/Initialize()
|
||||
. = ..()
|
||||
spark_system = new /datum/effect_system/spark_spread
|
||||
spark_system.set_up(5, 0, src)
|
||||
spark_system.attach(src)
|
||||
|
||||
/obj/item/construction/examine(mob/user)
|
||||
..()
|
||||
to_chat(user, "\A [src]. It currently holds [matter]/[max_matter] matter-units." )
|
||||
|
||||
/obj/item/construction/Destroy()
|
||||
QDEL_NULL(spark_system)
|
||||
. = ..()
|
||||
|
||||
/obj/item/construction/attackby(obj/item/W, mob/user, params)
|
||||
if(iscyborg(user))
|
||||
return
|
||||
var/loaded = 0
|
||||
if(istype(W, /obj/item/rcd_ammo))
|
||||
var/obj/item/rcd_ammo/R = W
|
||||
var/load = min(R.ammoamt, max_matter - matter)
|
||||
if(load <= 0)
|
||||
to_chat(user, "<span class='warning'>[src] can't hold any more matter-units!</span>")
|
||||
return
|
||||
R.ammoamt -= load
|
||||
if(R.ammoamt <= 0)
|
||||
qdel(R)
|
||||
matter += load
|
||||
playsound(src.loc, 'sound/machines/click.ogg', 50, 1)
|
||||
loaded = 1
|
||||
else if(istype(W, /obj/item/stack/sheet/metal) || istype(W, /obj/item/stack/sheet/glass))
|
||||
loaded = loadwithsheets(W, sheetmultiplier, user)
|
||||
else if(istype(W, /obj/item/stack/sheet/plasteel))
|
||||
loaded = loadwithsheets(W, plasteelmultiplier*sheetmultiplier, user) //12 matter for 1 plasteel sheet
|
||||
else if(istype(W, /obj/item/stack/sheet/plasmarglass))
|
||||
loaded = loadwithsheets(W, plasmarglassmultiplier*sheetmultiplier, user) //8 matter for one plasma rglass sheet
|
||||
else if(istype(W, /obj/item/stack/sheet/rglass))
|
||||
loaded = loadwithsheets(W, rglassmultiplier*sheetmultiplier, user) //6 matter for one rglass sheet
|
||||
else if(istype(W, /obj/item/stack/rods))
|
||||
loaded = loadwithsheets(W, sheetmultiplier * 0.5, user) // 2 matter for 1 rod, as 2 rods are produced from 1 metal
|
||||
else if(istype(W, /obj/item/stack/tile/plasteel))
|
||||
loaded = loadwithsheets(W, sheetmultiplier * 0.25, user) // 1 matter for 1 floortile, as 4 tiles are produced from 1 metal
|
||||
if(loaded)
|
||||
to_chat(user, "<span class='notice'>[src] now holds [matter]/[max_matter] matter-units.</span>")
|
||||
else
|
||||
return ..()
|
||||
update_icon() //ensures that ammo counters (if present) get updated
|
||||
|
||||
/obj/item/construction/proc/loadwithsheets(obj/item/stack/sheet/S, value, mob/user)
|
||||
var/maxsheets = round((max_matter-matter)/value) //calculate the max number of sheets that will fit in RCD
|
||||
if(maxsheets > 0)
|
||||
var/amount_to_use = min(S.amount, maxsheets)
|
||||
S.use(amount_to_use)
|
||||
matter += value*amount_to_use
|
||||
playsound(src.loc, 'sound/machines/click.ogg', 50, 1)
|
||||
to_chat(user, "<span class='notice'>You insert [amount_to_use] [S.name] sheets into [src]. </span>")
|
||||
return 1
|
||||
to_chat(user, "<span class='warning'>You can't insert any more [S.name] sheets into [src]!</span>")
|
||||
return 0
|
||||
|
||||
/obj/item/construction/proc/activate()
|
||||
playsound(src.loc, 'sound/items/deconstruct.ogg', 50, 1)
|
||||
|
||||
/obj/item/construction/attack_self(mob/user)
|
||||
playsound(src.loc, 'sound/effects/pop.ogg', 50, 0)
|
||||
if(prob(20))
|
||||
spark_system.start()
|
||||
|
||||
/obj/item/construction/proc/useResource(amount, mob/user)
|
||||
if(matter < amount)
|
||||
if(user)
|
||||
to_chat(user, no_ammo_message)
|
||||
return 0
|
||||
matter -= amount
|
||||
update_icon()
|
||||
return 1
|
||||
|
||||
/obj/item/construction/proc/checkResource(amount, mob/user)
|
||||
. = matter >= amount
|
||||
if(!. && user)
|
||||
to_chat(user, no_ammo_message)
|
||||
if(has_ammobar)
|
||||
flick("[icon_state]_empty", src) //somewhat hacky thing to make RCDs with ammo counters actually have a blinking yellow light
|
||||
return .
|
||||
|
||||
/obj/item/construction/proc/range_check(atom/A, mob/user)
|
||||
if(!(A in range(custom_range, get_turf(user))))
|
||||
to_chat(user, "<span class='warning'>The \'Out of Range\' light on [src] blinks red.</span>")
|
||||
return FALSE
|
||||
else
|
||||
return TRUE
|
||||
|
||||
/obj/item/construction/proc/prox_check(proximity)
|
||||
if(proximity)
|
||||
return TRUE
|
||||
else
|
||||
return FALSE
|
||||
|
||||
|
||||
/obj/item/construction/rcd
|
||||
name = "rapid-construction-device (RCD)"
|
||||
icon = 'icons/obj/tools.dmi'
|
||||
icon_state = "rcd"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
|
||||
max_matter = 160
|
||||
item_flags = NO_MAT_REDEMPTION | NOBLUDGEON
|
||||
has_ammobar = TRUE
|
||||
var/mode = 1
|
||||
var/ranged = FALSE
|
||||
var/airlock_type = /obj/machinery/door/airlock
|
||||
var/airlock_glass = FALSE // So the floor's rcd_act knows how much ammo to use
|
||||
var/window_type = /obj/structure/window/fulltile
|
||||
var/advanced_airlock_setting = 1 //Set to 1 if you want more paintjobs available
|
||||
var/list/conf_access = null
|
||||
var/use_one_access = 0 //If the airlock should require ALL or only ONE of the listed accesses.
|
||||
var/delay_mod = 1
|
||||
var/canRturf = FALSE //Variable for R walls to deconstruct them
|
||||
|
||||
/obj/item/construction/rcd/suicide_act(mob/user)
|
||||
user.visible_message("<span class='suicide'>[user] sets the RCD to 'Wall' and points it down [user.p_their()] throat! It looks like [user.p_theyre()] trying to commit suicide..</span>")
|
||||
return (BRUTELOSS)
|
||||
|
||||
/obj/item/construction/rcd/verb/toggle_window_type_verb()
|
||||
set name = "RCD : Toggle Window Type"
|
||||
set category = "Object"
|
||||
set src in view(1)
|
||||
|
||||
if(!usr.canUseTopic(src, BE_CLOSE))
|
||||
return
|
||||
|
||||
toggle_window_type(usr)
|
||||
|
||||
/obj/item/construction/rcd/proc/toggle_window_type(mob/user)
|
||||
var/window_type_name
|
||||
if (window_type == /obj/structure/window/fulltile)
|
||||
window_type = /obj/structure/window/reinforced/fulltile
|
||||
window_type_name = "reinforced glass"
|
||||
else
|
||||
window_type = /obj/structure/window/fulltile
|
||||
window_type_name = "glass"
|
||||
|
||||
to_chat(user, "<span class='notice'>You change \the [src]'s window mode to [window_type_name].</span>")
|
||||
|
||||
/obj/item/construction/rcd/verb/change_airlock_access(mob/user)
|
||||
|
||||
if (!ishuman(user) && !user.has_unlimited_silicon_privilege)
|
||||
return
|
||||
|
||||
var/t1 = ""
|
||||
|
||||
|
||||
if(use_one_access)
|
||||
t1 += "Restriction Type: <a href='?src=[REF(src)];access=one'>At least one access required</a><br>"
|
||||
else
|
||||
t1 += "Restriction Type: <a href='?src=[REF(src)];access=one'>All accesses required</a><br>"
|
||||
|
||||
t1 += "<a href='?src=[REF(src)];access=all'>Remove All</a><br>"
|
||||
|
||||
var/accesses = ""
|
||||
accesses += "<div align='center'><b>Access</b></div>"
|
||||
accesses += "<table style='width:100%'>"
|
||||
accesses += "<tr>"
|
||||
for(var/i = 1; i <= 7; i++)
|
||||
accesses += "<td style='width:14%'><b>[get_region_accesses_name(i)]:</b></td>"
|
||||
accesses += "</tr><tr>"
|
||||
for(var/i = 1; i <= 7; i++)
|
||||
accesses += "<td style='width:14%' valign='top'>"
|
||||
for(var/A in get_region_accesses(i))
|
||||
if(A in conf_access)
|
||||
accesses += "<a href='?src=[REF(src)];access=[A]'><font color=\"red\">[replacetext(get_access_desc(A), " ", " ")]</font></a> "
|
||||
else
|
||||
accesses += "<a href='?src=[REF(src)];access=[A]'>[replacetext(get_access_desc(A), " ", " ")]</a> "
|
||||
accesses += "<br>"
|
||||
accesses += "</td>"
|
||||
accesses += "</tr></table>"
|
||||
t1 += "<tt>[accesses]</tt>"
|
||||
|
||||
t1 += "<p><a href='?src=[REF(src)];close=1'>Close</a></p>\n"
|
||||
|
||||
var/datum/browser/popup = new(user, "rcd_access", "Access Control", 900, 500)
|
||||
popup.set_content(t1)
|
||||
popup.set_title_image(user.browse_rsc_icon(icon, icon_state))
|
||||
popup.open()
|
||||
onclose(user, "rcd_access")
|
||||
|
||||
/obj/item/construction/rcd/Topic(href, href_list)
|
||||
..()
|
||||
if (usr.stat || usr.restrained())
|
||||
return
|
||||
if (href_list["close"])
|
||||
usr << browse(null, "window=rcd_access")
|
||||
return
|
||||
|
||||
if (href_list["access"])
|
||||
toggle_access(href_list["access"])
|
||||
change_airlock_access(usr)
|
||||
|
||||
/obj/item/construction/rcd/proc/toggle_access(acc)
|
||||
if (acc == "all")
|
||||
conf_access = null
|
||||
else if(acc == "one")
|
||||
use_one_access = !use_one_access
|
||||
else
|
||||
var/req = text2num(acc)
|
||||
|
||||
if (conf_access == null)
|
||||
conf_access = list()
|
||||
|
||||
if (!(req in conf_access))
|
||||
conf_access += req
|
||||
else
|
||||
conf_access -= req
|
||||
if (!conf_access.len)
|
||||
conf_access = null
|
||||
|
||||
/obj/item/construction/rcd/proc/get_airlock_image(airlock_type)
|
||||
var/obj/machinery/door/airlock/proto = airlock_type
|
||||
var/ic = initial(proto.icon)
|
||||
var/mutable_appearance/MA = mutable_appearance(ic, "closed")
|
||||
if(!initial(proto.glass))
|
||||
MA.overlays += "fill_closed"
|
||||
//Not scaling these down to button size because they look horrible then, instead just bumping up radius.
|
||||
return MA
|
||||
|
||||
/obj/item/construction/rcd/proc/check_menu(mob/living/user)
|
||||
if(!istype(user))
|
||||
return FALSE
|
||||
if(user.incapacitated() || !user.Adjacent(src))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/item/construction/rcd/proc/change_airlock_setting(mob/user)
|
||||
if(!user)
|
||||
return
|
||||
|
||||
var/list/solid_or_glass_choices = list(
|
||||
"Solid" = get_airlock_image(/obj/machinery/door/airlock),
|
||||
"Glass" = get_airlock_image(/obj/machinery/door/airlock/glass)
|
||||
)
|
||||
|
||||
var/list/solid_choices = list(
|
||||
"Standard" = get_airlock_image(/obj/machinery/door/airlock),
|
||||
"Public" = get_airlock_image(/obj/machinery/door/airlock/public),
|
||||
"Engineering" = get_airlock_image(/obj/machinery/door/airlock/engineering),
|
||||
"Atmospherics" = get_airlock_image(/obj/machinery/door/airlock/atmos),
|
||||
"Security" = get_airlock_image(/obj/machinery/door/airlock/security),
|
||||
"Command" = get_airlock_image(/obj/machinery/door/airlock/command),
|
||||
"Medical" = get_airlock_image(/obj/machinery/door/airlock/medical),
|
||||
"Research" = get_airlock_image(/obj/machinery/door/airlock/research),
|
||||
"Freezer" = get_airlock_image(/obj/machinery/door/airlock/freezer),
|
||||
"Science" = get_airlock_image(/obj/machinery/door/airlock/science),
|
||||
"Virology" = get_airlock_image(/obj/machinery/door/airlock/virology),
|
||||
"Mining" = get_airlock_image(/obj/machinery/door/airlock/mining),
|
||||
"Maintenance" = get_airlock_image(/obj/machinery/door/airlock/maintenance),
|
||||
"External" = get_airlock_image(/obj/machinery/door/airlock/external),
|
||||
"External Maintenance" = get_airlock_image(/obj/machinery/door/airlock/maintenance/external),
|
||||
"Airtight Hatch" = get_airlock_image(/obj/machinery/door/airlock/hatch),
|
||||
"Maintenance Hatch" = get_airlock_image(/obj/machinery/door/airlock/maintenance_hatch)
|
||||
)
|
||||
|
||||
var/list/glass_choices = list(
|
||||
"Standard" = get_airlock_image(/obj/machinery/door/airlock/glass),
|
||||
"Public" = get_airlock_image(/obj/machinery/door/airlock/public/glass),
|
||||
"Engineering" = get_airlock_image(/obj/machinery/door/airlock/engineering/glass),
|
||||
"Atmospherics" = get_airlock_image(/obj/machinery/door/airlock/atmos/glass),
|
||||
"Security" = get_airlock_image(/obj/machinery/door/airlock/security/glass),
|
||||
"Command" = get_airlock_image(/obj/machinery/door/airlock/command/glass),
|
||||
"Medical" = get_airlock_image(/obj/machinery/door/airlock/medical/glass),
|
||||
"Research" = get_airlock_image(/obj/machinery/door/airlock/research/glass),
|
||||
"Science" = get_airlock_image(/obj/machinery/door/airlock/science/glass),
|
||||
"Virology" = get_airlock_image(/obj/machinery/door/airlock/virology/glass),
|
||||
"Mining" = get_airlock_image(/obj/machinery/door/airlock/mining/glass),
|
||||
"Maintenance" = get_airlock_image(/obj/machinery/door/airlock/maintenance/glass),
|
||||
"External" = get_airlock_image(/obj/machinery/door/airlock/external/glass),
|
||||
"External Maintenance" = get_airlock_image(/obj/machinery/door/airlock/maintenance/external/glass)
|
||||
)
|
||||
|
||||
var/airlockcat = show_radial_menu(user, src, solid_or_glass_choices, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = TRUE)
|
||||
if(!check_menu(user))
|
||||
return
|
||||
switch(airlockcat)
|
||||
if("Solid")
|
||||
if(advanced_airlock_setting == 1)
|
||||
var/airlockpaint = show_radial_menu(user, src, solid_choices, radius = 42, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = TRUE)
|
||||
if(!check_menu(user))
|
||||
return
|
||||
switch(airlockpaint)
|
||||
if("Standard")
|
||||
airlock_type = /obj/machinery/door/airlock
|
||||
if("Public")
|
||||
airlock_type = /obj/machinery/door/airlock/public
|
||||
if("Engineering")
|
||||
airlock_type = /obj/machinery/door/airlock/engineering
|
||||
if("Atmospherics")
|
||||
airlock_type = /obj/machinery/door/airlock/atmos
|
||||
if("Security")
|
||||
airlock_type = /obj/machinery/door/airlock/security
|
||||
if("Command")
|
||||
airlock_type = /obj/machinery/door/airlock/command
|
||||
if("Medical")
|
||||
airlock_type = /obj/machinery/door/airlock/medical
|
||||
if("Research")
|
||||
airlock_type = /obj/machinery/door/airlock/research
|
||||
if("Freezer")
|
||||
airlock_type = /obj/machinery/door/airlock/freezer
|
||||
if("Science")
|
||||
airlock_type = /obj/machinery/door/airlock/science
|
||||
if("Virology")
|
||||
airlock_type = /obj/machinery/door/airlock/virology
|
||||
if("Mining")
|
||||
airlock_type = /obj/machinery/door/airlock/mining
|
||||
if("Maintenance")
|
||||
airlock_type = /obj/machinery/door/airlock/maintenance
|
||||
if("External")
|
||||
airlock_type = /obj/machinery/door/airlock/external
|
||||
if("External Maintenance")
|
||||
airlock_type = /obj/machinery/door/airlock/maintenance/external
|
||||
if("Airtight Hatch")
|
||||
airlock_type = /obj/machinery/door/airlock/hatch
|
||||
if("Maintenance Hatch")
|
||||
airlock_type = /obj/machinery/door/airlock/maintenance_hatch
|
||||
airlock_glass = FALSE
|
||||
else
|
||||
airlock_type = /obj/machinery/door/airlock
|
||||
airlock_glass = FALSE
|
||||
|
||||
if("Glass")
|
||||
if(advanced_airlock_setting == 1)
|
||||
var/airlockpaint = show_radial_menu(user, src , glass_choices, radius = 42, custom_check = CALLBACK(src, .proc/check_menu, user), require_near = TRUE)
|
||||
if(!check_menu(user))
|
||||
return
|
||||
switch(airlockpaint)
|
||||
if("Standard")
|
||||
airlock_type = /obj/machinery/door/airlock/glass
|
||||
if("Public")
|
||||
airlock_type = /obj/machinery/door/airlock/public/glass
|
||||
if("Engineering")
|
||||
airlock_type = /obj/machinery/door/airlock/engineering/glass
|
||||
if("Atmospherics")
|
||||
airlock_type = /obj/machinery/door/airlock/atmos/glass
|
||||
if("Security")
|
||||
airlock_type = /obj/machinery/door/airlock/security/glass
|
||||
if("Command")
|
||||
airlock_type = /obj/machinery/door/airlock/command/glass
|
||||
if("Medical")
|
||||
airlock_type = /obj/machinery/door/airlock/medical/glass
|
||||
if("Research")
|
||||
airlock_type = /obj/machinery/door/airlock/research/glass
|
||||
if("Science")
|
||||
airlock_type = /obj/machinery/door/airlock/science/glass
|
||||
if("Virology")
|
||||
airlock_type = /obj/machinery/door/airlock/virology/glass
|
||||
if("Mining")
|
||||
airlock_type = /obj/machinery/door/airlock/mining/glass
|
||||
if("Maintenance")
|
||||
airlock_type = /obj/machinery/door/airlock/maintenance/glass
|
||||
if("External")
|
||||
airlock_type = /obj/machinery/door/airlock/external/glass
|
||||
if("External Maintenance")
|
||||
airlock_type = /obj/machinery/door/airlock/maintenance/external/glass
|
||||
airlock_glass = TRUE
|
||||
else
|
||||
airlock_type = /obj/machinery/door/airlock/glass
|
||||
airlock_glass = TRUE
|
||||
else
|
||||
airlock_type = /obj/machinery/door/airlock
|
||||
airlock_glass = FALSE
|
||||
|
||||
|
||||
/obj/item/construction/rcd/proc/rcd_create(atom/A, mob/user)
|
||||
var/list/rcd_results = A.rcd_vals(user, src)
|
||||
if(!rcd_results)
|
||||
return FALSE
|
||||
if(do_after(user, rcd_results["delay"] * delay_mod, target = A))
|
||||
if(checkResource(rcd_results["cost"], user))
|
||||
var/atom/cached = A
|
||||
if(A.rcd_act(user, src, rcd_results["mode"]))
|
||||
useResource(rcd_results["cost"], user)
|
||||
activate()
|
||||
investigate_log("[user] used [src] on [cached] (now [A]) with cost [rcd_results["cost"]], delay [rcd_results["delay"]], mode [rcd_results["mode"]].", INVESTIGATE_RCD)
|
||||
playsound(src, 'sound/machines/click.ogg', 50, 1)
|
||||
return TRUE
|
||||
|
||||
/obj/item/construction/rcd/Initialize()
|
||||
. = ..()
|
||||
GLOB.rcd_list += src
|
||||
|
||||
/obj/item/construction/rcd/Destroy()
|
||||
GLOB.rcd_list -= src
|
||||
. = ..()
|
||||
|
||||
/obj/item/construction/rcd/attack_self(mob/user)
|
||||
..()
|
||||
var/list/choices = list(
|
||||
"Airlock" = image(icon = 'icons/mob/radial.dmi', icon_state = "airlock"),
|
||||
"Deconstruct" = image(icon= 'icons/mob/radial.dmi', icon_state = "delete"),
|
||||
"Grilles & Windows" = image(icon = 'icons/mob/radial.dmi', icon_state = "grillewindow"),
|
||||
"Floors & Walls" = image(icon = 'icons/mob/radial.dmi', icon_state = "wallfloor")
|
||||
)
|
||||
if(mode == RCD_AIRLOCK)
|
||||
choices += list(
|
||||
"Change Access" = image(icon = 'icons/mob/radial.dmi', icon_state = "access"),
|
||||
"Change Airlock Type" = image(icon = 'icons/mob/radial.dmi', icon_state = "airlocktype")
|
||||
)
|
||||
else if(mode == RCD_WINDOWGRILLE)
|
||||
choices += list(
|
||||
"Change Window Type" = image(icon = 'icons/mob/radial.dmi', icon_state = "windowtype")
|
||||
)
|
||||
var/choice = show_radial_menu(user,src,choices, custom_check = CALLBACK(src,.proc/check_menu,user))
|
||||
if(!check_menu(user))
|
||||
return
|
||||
switch(choice)
|
||||
if("Floors & Walls")
|
||||
mode = RCD_FLOORWALL
|
||||
if("Airlock")
|
||||
mode = RCD_AIRLOCK
|
||||
if("Deconstruct")
|
||||
mode = RCD_DECONSTRUCT
|
||||
if("Grilles & Windows")
|
||||
mode = RCD_WINDOWGRILLE
|
||||
if("Change Access")
|
||||
change_airlock_access(user)
|
||||
return
|
||||
if("Change Airlock Type")
|
||||
change_airlock_setting(user)
|
||||
return
|
||||
if("Change Window Type")
|
||||
toggle_window_type(user)
|
||||
return
|
||||
else
|
||||
return
|
||||
playsound(src, 'sound/effects/pop.ogg', 50, 0)
|
||||
to_chat(user, "<span class='notice'>You change RCD's mode to '[choice]'.</span>")
|
||||
|
||||
/obj/item/construction/rcd/proc/target_check(atom/A, mob/user) // only returns true for stuff the device can actually work with
|
||||
if((isturf(A) && A.density && mode==RCD_DECONSTRUCT) || (isturf(A) && !A.density) || (istype(A, /obj/machinery/door/airlock) && mode==RCD_DECONSTRUCT) || istype(A, /obj/structure/grille) || (istype(A, /obj/structure/window) && mode==RCD_DECONSTRUCT) || istype(A, /obj/structure/girder))
|
||||
return TRUE
|
||||
else
|
||||
return FALSE
|
||||
|
||||
/obj/item/construction/rcd/afterattack(atom/A, mob/user, proximity)
|
||||
. = ..()
|
||||
if(!prox_check(proximity))
|
||||
return
|
||||
rcd_create(A, user)
|
||||
|
||||
/obj/item/construction/rcd/proc/detonate_pulse()
|
||||
audible_message("<span class='danger'><b>[src] begins to vibrate and \
|
||||
buzz loudly!</b></span>","<span class='danger'><b>[src] begins \
|
||||
vibrating violently!</b></span>")
|
||||
// 5 seconds to get rid of it
|
||||
addtimer(CALLBACK(src, .proc/detonate_pulse_explode), 50)
|
||||
|
||||
/obj/item/construction/rcd/proc/detonate_pulse_explode()
|
||||
explosion(src, 0, 0, 3, 1, flame_range = 1)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/construction/rcd/update_icon()
|
||||
..()
|
||||
if(has_ammobar)
|
||||
var/ratio = CEILING((matter / max_matter) * ammo_sections, 1)
|
||||
cut_overlays() //To prevent infinite stacking of overlays
|
||||
add_overlay("[icon_state]_charge[ratio]")
|
||||
|
||||
/obj/item/construction/rcd/Initialize()
|
||||
. = ..()
|
||||
update_icon()
|
||||
|
||||
/obj/item/construction/rcd/borg
|
||||
no_ammo_message = "<span class='warning'>Insufficient charge.</span>"
|
||||
desc = "A device used to rapidly build walls and floors."
|
||||
canRturf = TRUE
|
||||
|
||||
|
||||
/obj/item/construction/rcd/borg/useResource(amount, mob/user)
|
||||
if(!iscyborg(user))
|
||||
return 0
|
||||
var/mob/living/silicon/robot/borgy = user
|
||||
if(!borgy.cell)
|
||||
if(user)
|
||||
to_chat(user, no_ammo_message)
|
||||
return 0
|
||||
. = borgy.cell.use(amount * 72) //borgs get 1.3x the use of their RCDs
|
||||
if(!. && user)
|
||||
to_chat(user, no_ammo_message)
|
||||
return .
|
||||
|
||||
/obj/item/construction/rcd/borg/checkResource(amount, mob/user)
|
||||
if(!iscyborg(user))
|
||||
return 0
|
||||
var/mob/living/silicon/robot/borgy = user
|
||||
if(!borgy.cell)
|
||||
if(user)
|
||||
to_chat(user, no_ammo_message)
|
||||
return 0
|
||||
. = borgy.cell.charge >= (amount * 72)
|
||||
if(!. && user)
|
||||
to_chat(user, no_ammo_message)
|
||||
return .
|
||||
|
||||
/obj/item/construction/rcd/loaded
|
||||
matter = 160
|
||||
|
||||
/obj/item/construction/rcd/combat
|
||||
name = "Combat RCD"
|
||||
desc = "A device used to rapidly build and deconstruct. Reload with metal, plasteel, glass or compressed matter cartridges. This RCD has been upgraded to be able to remove Rwalls!"
|
||||
icon_state = "ircd"
|
||||
item_state = "ircd"
|
||||
max_matter = 500
|
||||
matter = 500
|
||||
canRturf = TRUE
|
||||
|
||||
/obj/item/construction/rcd/industrial
|
||||
name = "industrial RCD"
|
||||
icon_state = "ircd"
|
||||
item_state = "ircd"
|
||||
max_matter = 500
|
||||
matter = 500
|
||||
delay_mod = 0.6
|
||||
sheetmultiplier = 8
|
||||
|
||||
/obj/item/rcd_ammo
|
||||
name = "compressed matter cartridge"
|
||||
desc = "Highly compressed matter for the RCD."
|
||||
icon = 'icons/obj/ammo.dmi'
|
||||
icon_state = "rcd"
|
||||
item_state = "rcdammo"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
|
||||
materials = list(MAT_METAL=12000, MAT_GLASS=8000)
|
||||
var/ammoamt = 40
|
||||
|
||||
/obj/item/rcd_ammo/large
|
||||
name = "large compressed matter cartridge"
|
||||
desc = "Highly compressed matter for the RCD. Has four times the matter packed into the same space as a normal cartridge."
|
||||
materials = list(MAT_METAL=48000, MAT_GLASS=32000)
|
||||
ammoamt = 160
|
||||
|
||||
|
||||
/obj/item/construction/rcd/combat/admin
|
||||
name = "admin RCD"
|
||||
max_matter = INFINITY
|
||||
matter = INFINITY
|
||||
|
||||
|
||||
// Ranged RCD
|
||||
|
||||
|
||||
/obj/item/construction/rcd/arcd
|
||||
name = "advanced rapid-construction-device (ARCD)"
|
||||
desc = "A prototype RCD with ranged capability and extended capacity. Reload with metal, plasteel, glass or compressed matter cartridges."
|
||||
max_matter = 300
|
||||
matter = 300
|
||||
delay_mod = 0.6
|
||||
ranged = TRUE
|
||||
icon_state = "arcd"
|
||||
item_state = "oldrcd"
|
||||
has_ammobar = FALSE
|
||||
|
||||
/obj/item/construction/rcd/arcd/afterattack(atom/A, mob/user)
|
||||
. = ..()
|
||||
if(!range_check(A,user))
|
||||
return
|
||||
if(target_check(A,user))
|
||||
user.Beam(A,icon_state="rped_upgrade",time=30)
|
||||
rcd_create(A,user)
|
||||
|
||||
|
||||
|
||||
// RAPID LIGHTING DEVICE
|
||||
|
||||
|
||||
|
||||
/obj/item/construction/rld
|
||||
name = "rapid-light-device (RLD)"
|
||||
desc = "A device used to rapidly provide lighting sources to an area. Reload with metal, plasteel, glass or compressed matter cartridges."
|
||||
icon = 'icons/obj/tools.dmi'
|
||||
icon_state = "rld"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
|
||||
matter = 500
|
||||
max_matter = 500
|
||||
sheetmultiplier = 16
|
||||
var/mode = LIGHT_MODE
|
||||
actions_types = list(/datum/action/item_action/pick_color)
|
||||
ammo_sections = 5
|
||||
has_ammobar = TRUE
|
||||
|
||||
var/wallcost = 10
|
||||
var/floorcost = 15
|
||||
var/launchcost = 5
|
||||
var/deconcost = 10
|
||||
|
||||
var/walldelay = 10
|
||||
var/floordelay = 10
|
||||
var/decondelay = 10
|
||||
|
||||
var/color_choice = null
|
||||
|
||||
|
||||
/obj/item/construction/rld/Initialize()
|
||||
. = ..()
|
||||
update_icon()
|
||||
|
||||
/obj/item/construction/rld/ui_action_click(mob/user, var/datum/action/A)
|
||||
if(istype(A, /datum/action/item_action/pick_color))
|
||||
color_choice = input(user,"","Choose Color",color_choice) as color
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/item/construction/rld/update_icon()
|
||||
..()
|
||||
var/ratio = CEILING((matter / max_matter) * ammo_sections, 1)
|
||||
cut_overlays() //To prevent infinite stacking of overlays
|
||||
add_overlay("rld_light[ratio]")
|
||||
|
||||
/obj/item/construction/rld/attack_self(mob/user)
|
||||
..()
|
||||
switch(mode)
|
||||
if(REMOVE_MODE)
|
||||
mode = LIGHT_MODE
|
||||
to_chat(user, "<span class='notice'>You change RLD's mode to 'Permanent Light Construction'.</span>")
|
||||
if(LIGHT_MODE)
|
||||
mode = GLOW_MODE
|
||||
to_chat(user, "<span class='notice'>You change RLD's mode to 'Light Launcher'.</span>")
|
||||
if(GLOW_MODE)
|
||||
mode = REMOVE_MODE
|
||||
to_chat(user, "<span class='notice'>You change RLD's mode to 'Deconstruct'.</span>")
|
||||
|
||||
|
||||
/obj/item/construction/rld/proc/checkdupes(var/target)
|
||||
. = list()
|
||||
var/turf/checking = get_turf(target)
|
||||
for(var/obj/machinery/light/dupe in checking)
|
||||
if(istype(dupe, /obj/machinery/light))
|
||||
. |= dupe
|
||||
|
||||
|
||||
/obj/item/construction/rld/afterattack(atom/A, mob/user)
|
||||
. = ..()
|
||||
if(!range_check(A,user))
|
||||
return
|
||||
var/turf/start = get_turf(src)
|
||||
switch(mode)
|
||||
if(REMOVE_MODE)
|
||||
if(istype(A, /obj/machinery/light/))
|
||||
if(checkResource(deconcost, user))
|
||||
to_chat(user, "<span class='notice'>You start deconstructing [A]...</span>")
|
||||
user.Beam(A,icon_state="nzcrentrs_power",time=15)
|
||||
playsound(src.loc, 'sound/machines/click.ogg', 50, 1)
|
||||
if(do_after(user, decondelay, target = A))
|
||||
if(!useResource(deconcost, user))
|
||||
return 0
|
||||
activate()
|
||||
qdel(A)
|
||||
return TRUE
|
||||
return FALSE
|
||||
if(LIGHT_MODE)
|
||||
if(iswallturf(A))
|
||||
var/turf/closed/wall/W = A
|
||||
if(checkResource(floorcost, user))
|
||||
to_chat(user, "<span class='notice'>You start building a wall light...</span>")
|
||||
user.Beam(A,icon_state="nzcrentrs_power",time=15)
|
||||
playsound(src.loc, 'sound/machines/click.ogg', 50, 1)
|
||||
playsound(src.loc, 'sound/effects/light_flicker.ogg', 50, 0)
|
||||
if(do_after(user, floordelay, target = A))
|
||||
if(!istype(W))
|
||||
return FALSE
|
||||
var/list/candidates = list()
|
||||
var/turf/open/winner = null
|
||||
var/winning_dist = null
|
||||
for(var/direction in GLOB.cardinals)
|
||||
var/turf/C = get_step(W, direction)
|
||||
var/list/dupes = checkdupes(C)
|
||||
if(start.CanAtmosPass(C) && !dupes.len)
|
||||
candidates += C
|
||||
if(!candidates.len)
|
||||
to_chat(user, "<span class='warning'>Valid target not found...</span>")
|
||||
playsound(src.loc, 'sound/misc/compiler-failure.ogg', 30, 1)
|
||||
return FALSE
|
||||
for(var/turf/open/O in candidates)
|
||||
if(istype(O))
|
||||
var/x0 = O.x
|
||||
var/y0 = O.y
|
||||
var/contender = cheap_hypotenuse(start.x, start.y, x0, y0)
|
||||
if(!winner)
|
||||
winner = O
|
||||
winning_dist = contender
|
||||
else
|
||||
if(contender < winning_dist) // lower is better
|
||||
winner = O
|
||||
winning_dist = contender
|
||||
activate()
|
||||
if(!useResource(wallcost, user))
|
||||
return FALSE
|
||||
var/light = get_turf(winner)
|
||||
var/align = get_dir(winner, A)
|
||||
var/obj/machinery/light/L = new /obj/machinery/light(light)
|
||||
L.setDir(align)
|
||||
L.color = color_choice
|
||||
L.light_color = L.color
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
if(isfloorturf(A))
|
||||
var/turf/open/floor/F = A
|
||||
if(checkResource(floorcost, user))
|
||||
to_chat(user, "<span class='notice'>You start building a floor light...</span>")
|
||||
user.Beam(A,icon_state="nzcrentrs_power",time=15)
|
||||
playsound(src.loc, 'sound/machines/click.ogg', 50, 1)
|
||||
playsound(src.loc, 'sound/effects/light_flicker.ogg', 50, 1)
|
||||
if(do_after(user, floordelay, target = A))
|
||||
if(!istype(F))
|
||||
return 0
|
||||
if(!useResource(floorcost, user))
|
||||
return 0
|
||||
activate()
|
||||
var/destination = get_turf(A)
|
||||
var/obj/machinery/light/floor/FL = new /obj/machinery/light/floor(destination)
|
||||
FL.color = color_choice
|
||||
FL.light_color = FL.color
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
if(GLOW_MODE)
|
||||
if(useResource(launchcost, user))
|
||||
activate()
|
||||
to_chat(user, "<span class='notice'>You fire a glowstick!</span>")
|
||||
var/obj/item/flashlight/glowstick/G = new /obj/item/flashlight/glowstick(start)
|
||||
G.color = color_choice
|
||||
G.light_color = G.color
|
||||
G.throw_at(A, 9, 3, user)
|
||||
G.on = TRUE
|
||||
G.update_brightness()
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
#undef GLOW_MODE
|
||||
#undef LIGHT_MODE
|
||||
#undef REMOVE_MODE
|
||||
@@ -0,0 +1,357 @@
|
||||
/obj/item/twohanded/rcl
|
||||
name = "rapid cable layer"
|
||||
desc = "A device used to rapidly deploy cables. It has screws on the side which can be removed to slide off the cables. Do not use without insulation!"
|
||||
icon = 'icons/obj/tools.dmi'
|
||||
icon_state = "rcl-empty"
|
||||
item_state = "rcl-0"
|
||||
var/obj/structure/cable/last
|
||||
var/obj/item/stack/cable_coil/loaded
|
||||
opacity = FALSE
|
||||
force = 5 //Plastic is soft
|
||||
throwforce = 5
|
||||
throw_speed = 1
|
||||
throw_range = 7
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
var/max_amount = 90
|
||||
var/active = FALSE
|
||||
actions_types = list(/datum/action/item_action/rcl_col,/datum/action/item_action/rcl_gui)
|
||||
var/list/colors = list("red", "yellow", "green", "blue", "pink", "orange", "cyan", "white")
|
||||
var/current_color_index = 1
|
||||
var/ghetto = FALSE
|
||||
lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
|
||||
var/datum/component/mobhook
|
||||
var/datum/radial_menu/persistent/wiring_gui_menu
|
||||
|
||||
/obj/item/twohanded/rcl/attackby(obj/item/W, mob/user)
|
||||
if(istype(W, /obj/item/stack/cable_coil))
|
||||
var/obj/item/stack/cable_coil/C = W
|
||||
|
||||
if(!loaded)
|
||||
if(!user.transferItemToLoc(W, src))
|
||||
to_chat(user, "<span class='warning'>[src] is stuck to your hand!</span>")
|
||||
return
|
||||
else
|
||||
loaded = W //W.loc is src at this point.
|
||||
loaded.max_amount = max_amount //We store a lot.
|
||||
return
|
||||
|
||||
if(loaded.amount < max_amount)
|
||||
var/transfer_amount = min(max_amount - loaded.amount, C.amount)
|
||||
C.use(transfer_amount)
|
||||
loaded.amount += transfer_amount
|
||||
else
|
||||
return
|
||||
update_icon()
|
||||
to_chat(user, "<span class='notice'>You add the cables to [src]. It now contains [loaded.amount].</span>")
|
||||
else if(istype(W, /obj/item/screwdriver))
|
||||
if(!loaded)
|
||||
return
|
||||
if(ghetto && prob(10)) //Is it a ghetto RCL? If so, give it a 10% chance to fall apart
|
||||
to_chat(user, "<span class='warning'>You attempt to loosen the securing screws on the side, but it falls apart!</span>")
|
||||
while(loaded.amount > 30) //There are only two kinds of situations: "nodiff" (60,90), or "diff" (31-59, 61-89)
|
||||
var/diff = loaded.amount % 30
|
||||
if(diff)
|
||||
loaded.use(diff)
|
||||
new /obj/item/stack/cable_coil(get_turf(user), diff)
|
||||
else
|
||||
loaded.use(30)
|
||||
new /obj/item/stack/cable_coil(get_turf(user), 30)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
to_chat(user, "<span class='notice'>You loosen the securing screws on the side, allowing you to lower the guiding edge and retrieve the wires.</span>")
|
||||
while(loaded.amount > 30) //There are only two kinds of situations: "nodiff" (60,90), or "diff" (31-59, 61-89)
|
||||
var/diff = loaded.amount % 30
|
||||
if(diff)
|
||||
loaded.use(diff)
|
||||
new /obj/item/stack/cable_coil(get_turf(user), diff)
|
||||
else
|
||||
loaded.use(30)
|
||||
new /obj/item/stack/cable_coil(get_turf(user), 30)
|
||||
loaded.max_amount = initial(loaded.max_amount)
|
||||
if(!user.put_in_hands(loaded))
|
||||
loaded.forceMove(get_turf(user))
|
||||
|
||||
loaded = null
|
||||
update_icon()
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/item/twohanded/rcl/examine(mob/user)
|
||||
..()
|
||||
if(loaded)
|
||||
to_chat(user, "<span class='info'>It contains [loaded.amount]/[max_amount] cables.</span>")
|
||||
|
||||
/obj/item/twohanded/rcl/Destroy()
|
||||
QDEL_NULL(loaded)
|
||||
last = null
|
||||
QDEL_NULL(mobhook)
|
||||
QDEL_NULL(wiring_gui_menu)
|
||||
return ..()
|
||||
|
||||
/obj/item/twohanded/rcl/update_icon()
|
||||
if(!loaded)
|
||||
icon_state = "rcl-empty"
|
||||
item_state = "rcl-empty"
|
||||
return
|
||||
cut_overlays()
|
||||
var/cable_amount = 0
|
||||
switch(loaded.amount)
|
||||
if(61 to INFINITY)
|
||||
cable_amount = 3
|
||||
if(31 to 60)
|
||||
cable_amount = 2
|
||||
if(1 to 30)
|
||||
cable_amount = 1
|
||||
else
|
||||
cable_amount = 0
|
||||
|
||||
var/mutable_appearance/cable_overlay = mutable_appearance(icon, "rcl-[cable_amount]")
|
||||
cable_overlay.color = GLOB.cable_colors[colors[current_color_index]]
|
||||
if(cable_amount >= 1)
|
||||
icon_state = "rcl"
|
||||
item_state = "rcl"
|
||||
add_overlay(cable_overlay)
|
||||
else
|
||||
icon_state = "rcl-empty"
|
||||
item_state = "rcl-0"
|
||||
add_overlay(cable_overlay)
|
||||
|
||||
|
||||
/obj/item/twohanded/rcl/proc/is_empty(mob/user, loud = 1)
|
||||
update_icon()
|
||||
if(!loaded || !loaded.amount)
|
||||
if(loud)
|
||||
to_chat(user, "<span class='notice'>The last of the cables unreel from [src].</span>")
|
||||
if(loaded)
|
||||
QDEL_NULL(loaded)
|
||||
loaded = null
|
||||
QDEL_NULL(wiring_gui_menu)
|
||||
unwield(user)
|
||||
active = wielded
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/item/twohanded/rcl/pickup(mob/user)
|
||||
..()
|
||||
getMobhook(user)
|
||||
|
||||
|
||||
|
||||
/obj/item/twohanded/rcl/dropped(mob/wearer)
|
||||
..()
|
||||
if(mobhook)
|
||||
active = FALSE
|
||||
QDEL_NULL(mobhook)
|
||||
last = null
|
||||
|
||||
/obj/item/twohanded/rcl/attack_self(mob/user)
|
||||
..()
|
||||
active = wielded
|
||||
if(!active)
|
||||
last = null
|
||||
else if(!last)
|
||||
for(var/obj/structure/cable/C in get_turf(user))
|
||||
if(C.d1 == FALSE || C.d2 == FALSE)
|
||||
last = C
|
||||
break
|
||||
|
||||
obj/item/twohanded/rcl/proc/getMobhook(mob/to_hook)
|
||||
if(to_hook)
|
||||
if(mobhook && mobhook.parent != to_hook)
|
||||
QDEL_NULL(mobhook)
|
||||
if (!mobhook)
|
||||
mobhook = to_hook.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/trigger)))
|
||||
else
|
||||
QDEL_NULL(mobhook)
|
||||
|
||||
/obj/item/twohanded/rcl/proc/trigger(mob/user)
|
||||
if(active)
|
||||
layCable(user)
|
||||
if(wiring_gui_menu) //update the wire options as you move
|
||||
wiringGuiUpdate(user)
|
||||
|
||||
|
||||
//previous contents of trigger(), lays cable each time the player moves
|
||||
/obj/item/twohanded/rcl/proc/layCable(mob/user)
|
||||
if(!isturf(user.loc))
|
||||
return
|
||||
if(is_empty(user, 0))
|
||||
to_chat(user, "<span class='warning'>\The [src] is empty!</span>")
|
||||
return
|
||||
|
||||
if(prob(2) && ghetto) //Give ghetto RCLs a 2% chance to jam, requiring it to be reactviated manually.
|
||||
to_chat(user, "<span class='warning'>[src]'s wires jam!</span>")
|
||||
active = FALSE
|
||||
return
|
||||
else
|
||||
if(last)
|
||||
if(get_dist(last, user) == 1) //hacky, but it works
|
||||
var/turf/T = get_turf(user)
|
||||
if(T.intact || !T.can_have_cabling())
|
||||
last = null
|
||||
return
|
||||
if(get_dir(last, user) == last.d2)
|
||||
//Did we just walk backwards? Well, that's the one direction we CAN'T complete a stub.
|
||||
last = null
|
||||
return
|
||||
loaded.cable_join(last, user, FALSE)
|
||||
if(is_empty(user))
|
||||
return //If we've run out, display message and exit
|
||||
else
|
||||
last = null
|
||||
loaded.item_color = colors[current_color_index]
|
||||
last = loaded.place_turf(get_turf(src), user, turn(user.dir, 180))
|
||||
is_empty(user) //If we've run out, display message
|
||||
update_icon()
|
||||
|
||||
//searches the current tile for a stub cable of the same colour
|
||||
/obj/item/twohanded/rcl/proc/findLinkingCable(mob/user)
|
||||
var/turf/T
|
||||
if(!isturf(user.loc))
|
||||
return
|
||||
|
||||
T = get_turf(user)
|
||||
if(T.intact || !T.can_have_cabling())
|
||||
return
|
||||
|
||||
for(var/obj/structure/cable/C in T)
|
||||
if(!C)
|
||||
continue
|
||||
if(C.cable_color != GLOB.cable_colors[colors[current_color_index]])
|
||||
continue
|
||||
if(C.d1 == 0)
|
||||
return C
|
||||
break
|
||||
return
|
||||
|
||||
|
||||
/obj/item/twohanded/rcl/proc/wiringGuiGenerateChoices(mob/user)
|
||||
var/fromdir = 0
|
||||
var/obj/structure/cable/linkingCable = findLinkingCable(user)
|
||||
if(linkingCable)
|
||||
fromdir = linkingCable.d2
|
||||
|
||||
var/list/wiredirs = list("1","5","4","6","2","10","8","9")
|
||||
for(var/icondir in wiredirs)
|
||||
var/dirnum = text2num(icondir)
|
||||
var/cablesuffix = "[min(fromdir,dirnum)]-[max(fromdir,dirnum)]"
|
||||
if(fromdir == dirnum) //cables can't loop back on themselves
|
||||
cablesuffix = "invalid"
|
||||
var/image/img = image(icon = 'icons/mob/radial.dmi', icon_state = "cable_[cablesuffix]")
|
||||
img.color = GLOB.cable_colors[colors[current_color_index]]
|
||||
wiredirs[icondir] = img
|
||||
return wiredirs
|
||||
|
||||
/obj/item/twohanded/rcl/proc/showWiringGui(mob/user)
|
||||
var/list/choices = wiringGuiGenerateChoices(user)
|
||||
|
||||
wiring_gui_menu = show_radial_menu_persistent(user, src , choices, select_proc = CALLBACK(src, .proc/wiringGuiReact, user), radius = 42)
|
||||
|
||||
/obj/item/twohanded/rcl/proc/wiringGuiUpdate(mob/user)
|
||||
if(!wiring_gui_menu)
|
||||
return
|
||||
|
||||
wiring_gui_menu.entry_animation = FALSE //stop the open anim from playing each time we update
|
||||
var/list/choices = wiringGuiGenerateChoices(user)
|
||||
|
||||
wiring_gui_menu.change_choices(choices,FALSE)
|
||||
|
||||
|
||||
//Callback used to respond to interactions with the wiring menu
|
||||
/obj/item/twohanded/rcl/proc/wiringGuiReact(mob/living/user,choice)
|
||||
if(!choice) //close on a null choice (the center button)
|
||||
QDEL_NULL(wiring_gui_menu)
|
||||
return
|
||||
|
||||
choice = text2num(choice)
|
||||
|
||||
if(!isturf(user.loc))
|
||||
return
|
||||
if(is_empty(user, 0))
|
||||
to_chat(user, "<span class='warning'>\The [src] is empty!</span>")
|
||||
return
|
||||
|
||||
var/turf/T = get_turf(user)
|
||||
if(T.intact || !T.can_have_cabling())
|
||||
return
|
||||
|
||||
loaded.item_color = colors[current_color_index]
|
||||
|
||||
var/obj/structure/cable/linkingCable = findLinkingCable(user)
|
||||
if(linkingCable)
|
||||
if(choice != linkingCable.d2)
|
||||
loaded.cable_join(linkingCable, user, FALSE, choice)
|
||||
last = null
|
||||
else
|
||||
last = loaded.place_turf(get_turf(src), user, choice)
|
||||
|
||||
is_empty(user) //If we've run out, display message
|
||||
|
||||
wiringGuiUpdate(user)
|
||||
|
||||
|
||||
/obj/item/twohanded/rcl/pre_loaded/Initialize() //Comes preloaded with cable, for testing stuff
|
||||
. = ..()
|
||||
loaded = new()
|
||||
loaded.max_amount = max_amount
|
||||
loaded.amount = max_amount
|
||||
update_icon()
|
||||
|
||||
/obj/item/twohanded/rcl/Initialize()
|
||||
. = ..()
|
||||
update_icon()
|
||||
|
||||
/obj/item/twohanded/rcl/ui_action_click(mob/user, action)
|
||||
if(istype(action, /datum/action/item_action/rcl_col))
|
||||
current_color_index++;
|
||||
if (current_color_index > colors.len)
|
||||
current_color_index = 1
|
||||
var/cwname = colors[current_color_index]
|
||||
to_chat(user, "Color changed to [cwname]!")
|
||||
if(loaded)
|
||||
loaded.item_color= colors[current_color_index]
|
||||
update_icon()
|
||||
if(wiring_gui_menu)
|
||||
wiringGuiUpdate(user)
|
||||
else if(istype(action, /datum/action/item_action/rcl_gui))
|
||||
if(wiring_gui_menu) //The menu is already open, close it
|
||||
QDEL_NULL(wiring_gui_menu)
|
||||
else //open the menu
|
||||
showWiringGui(user)
|
||||
|
||||
/obj/item/twohanded/rcl/ghetto
|
||||
actions_types = list()
|
||||
max_amount = 30
|
||||
name = "makeshift rapid cable layer"
|
||||
ghetto = TRUE
|
||||
|
||||
/obj/item/twohanded/rcl/ghetto/update_icon()
|
||||
if(!loaded)
|
||||
icon_state = "rclg-empty"
|
||||
item_state = "rclg-0"
|
||||
return
|
||||
cut_overlays()
|
||||
var/cable_amount = 0
|
||||
switch(loaded.amount)
|
||||
if(20 to INFINITY)
|
||||
cable_amount = 3
|
||||
if(10 to 19)
|
||||
cable_amount = 2
|
||||
if(1 to 9)
|
||||
cable_amount = 1
|
||||
else
|
||||
cable_amount = 0
|
||||
|
||||
var/mutable_appearance/cable_overlay = mutable_appearance(icon, "rcl-[cable_amount]")
|
||||
cable_overlay.color = GLOB.cable_colors[colors[current_color_index]]
|
||||
if(cable_amount >= 1)
|
||||
icon_state = "rclg"
|
||||
item_state = "rclg"
|
||||
add_overlay(cable_overlay)
|
||||
else
|
||||
icon_state = "rclg-empty"
|
||||
item_state = "rclg-0"
|
||||
add_overlay(cable_overlay)
|
||||
|
||||
@@ -0,0 +1,477 @@
|
||||
/*
|
||||
CONTAINS:
|
||||
RPD
|
||||
*/
|
||||
|
||||
#define ATMOS_CATEGORY 0
|
||||
#define DISPOSALS_CATEGORY 1
|
||||
#define TRANSIT_CATEGORY 2
|
||||
|
||||
#define BUILD_MODE 1
|
||||
#define WRENCH_MODE 2
|
||||
#define DESTROY_MODE 4
|
||||
#define PAINT_MODE 8
|
||||
|
||||
|
||||
GLOBAL_LIST_INIT(atmos_pipe_recipes, list(
|
||||
"Pipes" = list(
|
||||
new /datum/pipe_info/pipe("Pipe", /obj/machinery/atmospherics/pipe/simple),
|
||||
new /datum/pipe_info/pipe("Manifold", /obj/machinery/atmospherics/pipe/manifold),
|
||||
new /datum/pipe_info/pipe("Manual Valve", /obj/machinery/atmospherics/components/binary/valve),
|
||||
new /datum/pipe_info/pipe("Digital Valve", /obj/machinery/atmospherics/components/binary/valve/digital),
|
||||
new /datum/pipe_info/pipe("4-Way Manifold", /obj/machinery/atmospherics/pipe/manifold4w),
|
||||
new /datum/pipe_info/pipe("Layer Manifold", /obj/machinery/atmospherics/pipe/layer_manifold),
|
||||
),
|
||||
"Devices" = list(
|
||||
new /datum/pipe_info/pipe("Connector", /obj/machinery/atmospherics/components/unary/portables_connector),
|
||||
new /datum/pipe_info/pipe("Unary Vent", /obj/machinery/atmospherics/components/unary/vent_pump),
|
||||
new /datum/pipe_info/pipe("Gas Pump", /obj/machinery/atmospherics/components/binary/pump),
|
||||
new /datum/pipe_info/pipe("Passive Gate", /obj/machinery/atmospherics/components/binary/passive_gate),
|
||||
new /datum/pipe_info/pipe("Volume Pump", /obj/machinery/atmospherics/components/binary/volume_pump),
|
||||
new /datum/pipe_info/pipe("Scrubber", /obj/machinery/atmospherics/components/unary/vent_scrubber),
|
||||
new /datum/pipe_info/pipe("Injector", /obj/machinery/atmospherics/components/unary/outlet_injector),
|
||||
new /datum/pipe_info/meter("Meter"),
|
||||
new /datum/pipe_info/pipe("Gas Filter", /obj/machinery/atmospherics/components/trinary/filter),
|
||||
new /datum/pipe_info/pipe("Gas Mixer", /obj/machinery/atmospherics/components/trinary/mixer),
|
||||
),
|
||||
"Heat Exchange" = list(
|
||||
new /datum/pipe_info/pipe("Pipe", /obj/machinery/atmospherics/pipe/heat_exchanging/simple),
|
||||
new /datum/pipe_info/pipe("Manifold", /obj/machinery/atmospherics/pipe/heat_exchanging/manifold),
|
||||
new /datum/pipe_info/pipe("4-Way Manifold", /obj/machinery/atmospherics/pipe/heat_exchanging/manifold4w),
|
||||
new /datum/pipe_info/pipe("Junction", /obj/machinery/atmospherics/pipe/heat_exchanging/junction),
|
||||
new /datum/pipe_info/pipe("Heat Exchanger", /obj/machinery/atmospherics/components/unary/heat_exchanger),
|
||||
)
|
||||
))
|
||||
|
||||
GLOBAL_LIST_INIT(disposal_pipe_recipes, list(
|
||||
"Disposal Pipes" = list(
|
||||
new /datum/pipe_info/disposal("Pipe", /obj/structure/disposalpipe/segment, PIPE_BENDABLE),
|
||||
new /datum/pipe_info/disposal("Junction", /obj/structure/disposalpipe/junction, PIPE_TRIN_M),
|
||||
new /datum/pipe_info/disposal("Y-Junction", /obj/structure/disposalpipe/junction/yjunction),
|
||||
new /datum/pipe_info/disposal("Sort Junction", /obj/structure/disposalpipe/sorting/mail, PIPE_TRIN_M),
|
||||
new /datum/pipe_info/disposal("Trunk", /obj/structure/disposalpipe/trunk),
|
||||
new /datum/pipe_info/disposal("Bin", /obj/machinery/disposal/bin, PIPE_ONEDIR),
|
||||
new /datum/pipe_info/disposal("Outlet", /obj/structure/disposaloutlet),
|
||||
new /datum/pipe_info/disposal("Chute", /obj/machinery/disposal/deliveryChute),
|
||||
)
|
||||
))
|
||||
|
||||
GLOBAL_LIST_INIT(transit_tube_recipes, list(
|
||||
"Transit Tubes" = list(
|
||||
new /datum/pipe_info/transit("Straight Tube", /obj/structure/c_transit_tube, PIPE_STRAIGHT),
|
||||
new /datum/pipe_info/transit("Straight Tube with Crossing", /obj/structure/c_transit_tube/crossing, PIPE_STRAIGHT),
|
||||
new /datum/pipe_info/transit("Curved Tube", /obj/structure/c_transit_tube/curved, PIPE_UNARY_FLIPPABLE),
|
||||
new /datum/pipe_info/transit("Diagonal Tube", /obj/structure/c_transit_tube/diagonal, PIPE_STRAIGHT),
|
||||
new /datum/pipe_info/transit("Diagonal Tube with Crossing", /obj/structure/c_transit_tube/diagonal/crossing, PIPE_STRAIGHT),
|
||||
new /datum/pipe_info/transit("Junction", /obj/structure/c_transit_tube/junction, PIPE_UNARY_FLIPPABLE),
|
||||
),
|
||||
"Station Equipment" = list(
|
||||
new /datum/pipe_info/transit("Through Tube Station", /obj/structure/c_transit_tube/station, PIPE_STRAIGHT),
|
||||
new /datum/pipe_info/transit("Terminus Tube Station", /obj/structure/c_transit_tube/station/reverse, PIPE_UNARY),
|
||||
new /datum/pipe_info/transit("Transit Tube Pod", /obj/structure/c_transit_tube_pod, PIPE_ONEDIR),
|
||||
)
|
||||
))
|
||||
|
||||
/datum/pipe_info
|
||||
var/name
|
||||
var/icon_state
|
||||
var/id = -1
|
||||
var/dirtype = PIPE_BENDABLE
|
||||
|
||||
/datum/pipe_info/proc/Render(dispenser)
|
||||
var/dat = "<li><a href='?src=[REF(dispenser)]&[Params()]'>[name]</a></li>"
|
||||
|
||||
// Stationary pipe dispensers don't allow you to pre-select pipe directions.
|
||||
// This makes it impossble to spawn bent versions of bendable pipes.
|
||||
// We add a "Bent" pipe type with a preset diagonal direction to work around it.
|
||||
if(istype(dispenser, /obj/machinery/pipedispenser) && (dirtype == PIPE_BENDABLE || dirtype == /obj/item/pipe/binary/bendable))
|
||||
dat += "<li><a href='?src=[REF(dispenser)]&[Params()]&dir=[NORTHEAST]'>Bent [name]</a></li>"
|
||||
|
||||
return dat
|
||||
|
||||
/datum/pipe_info/proc/Params()
|
||||
return ""
|
||||
|
||||
/datum/pipe_info/proc/get_preview(selected_dir)
|
||||
var/list/dirs
|
||||
switch(dirtype)
|
||||
if(PIPE_STRAIGHT, PIPE_BENDABLE)
|
||||
dirs = list("[NORTH]" = "Vertical", "[EAST]" = "Horizontal")
|
||||
if(dirtype == PIPE_BENDABLE)
|
||||
dirs += list("[NORTHWEST]" = "West to North", "[NORTHEAST]" = "North to East",
|
||||
"[SOUTHWEST]" = "South to West", "[SOUTHEAST]" = "East to South")
|
||||
if(PIPE_TRINARY)
|
||||
dirs = list("[NORTH]" = "West South East", "[EAST]" = "North West South",
|
||||
"[SOUTH]" = "East North West", "[WEST]" = "South East North")
|
||||
if(PIPE_TRIN_M)
|
||||
dirs = list("[NORTH]" = "North East South", "[EAST]" = "East South West",
|
||||
"[SOUTH]" = "South West North", "[WEST]" = "West North East",
|
||||
"[SOUTHEAST]" = "West South East", "[NORTHEAST]" = "South East North",
|
||||
"[NORTHWEST]" = "East North West", "[SOUTHWEST]" = "North West South")
|
||||
if(PIPE_UNARY)
|
||||
dirs = list("[NORTH]" = "North", "[EAST]" = "East", "[SOUTH]" = "South", "[WEST]" = "West")
|
||||
if(PIPE_ONEDIR)
|
||||
dirs = list("[SOUTH]" = name)
|
||||
if(PIPE_UNARY_FLIPPABLE)
|
||||
dirs = list("[NORTH]" = "North", "[NORTHEAST]" = "North Flipped", "[EAST]" = "East", "[SOUTHEAST]" = "East Flipped",
|
||||
"[SOUTH]" = "South", "[SOUTHWEST]" = "South Flipped", "[WEST]" = "West", "[NORTHWEST]" = "West Flipped")
|
||||
|
||||
|
||||
var/list/rows = list()
|
||||
var/list/row = list("previews" = list())
|
||||
var/i = 0
|
||||
for(var/dir in dirs)
|
||||
var/numdir = text2num(dir)
|
||||
var/flipped = ((dirtype == PIPE_TRIN_M) || (dirtype == PIPE_UNARY_FLIPPABLE)) && (numdir in GLOB.diagonals)
|
||||
row["previews"] += list(list("selected" = (numdir == selected_dir), "dir" = dir2text(numdir), "dir_name" = dirs[dir], "icon_state" = icon_state, "flipped" = flipped))
|
||||
if(i++ || dirtype == PIPE_ONEDIR)
|
||||
rows += list(row)
|
||||
row = list("previews" = list())
|
||||
i = 0
|
||||
|
||||
return rows
|
||||
|
||||
/datum/pipe_info/pipe/New(label, obj/machinery/atmospherics/path)
|
||||
name = label
|
||||
id = path
|
||||
icon_state = initial(path.pipe_state)
|
||||
var/obj/item/pipe/c = initial(path.construction_type)
|
||||
dirtype = initial(c.RPD_type)
|
||||
|
||||
/datum/pipe_info/pipe/Params()
|
||||
return "makepipe=[id]&type=[dirtype]"
|
||||
|
||||
/datum/pipe_info/meter
|
||||
icon_state = "meter"
|
||||
dirtype = PIPE_ONEDIR
|
||||
|
||||
/datum/pipe_info/meter/New(label)
|
||||
name = label
|
||||
|
||||
/datum/pipe_info/meter/Params()
|
||||
return "makemeter=[id]&type=[dirtype]"
|
||||
|
||||
/datum/pipe_info/disposal/New(label, obj/path, dt=PIPE_UNARY)
|
||||
name = label
|
||||
id = path
|
||||
|
||||
icon_state = initial(path.icon_state)
|
||||
if(ispath(path, /obj/structure/disposalpipe))
|
||||
icon_state = "con[icon_state]"
|
||||
|
||||
dirtype = dt
|
||||
|
||||
/datum/pipe_info/disposal/Params()
|
||||
return "dmake=[id]&type=[dirtype]"
|
||||
|
||||
/datum/pipe_info/transit/New(label, obj/path, dt=PIPE_UNARY)
|
||||
name = label
|
||||
id = path
|
||||
dirtype = dt
|
||||
icon_state = initial(path.icon_state)
|
||||
if(dt == PIPE_UNARY_FLIPPABLE)
|
||||
icon_state = "[icon_state]_preview"
|
||||
|
||||
/obj/item/pipe_dispenser
|
||||
name = "Rapid Piping Device (RPD)"
|
||||
desc = "A device used to rapidly pipe things."
|
||||
icon = 'icons/obj/tools.dmi'
|
||||
icon_state = "rpd"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
|
||||
flags_1 = CONDUCT_1
|
||||
force = 10
|
||||
throwforce = 10
|
||||
throw_speed = 1
|
||||
throw_range = 5
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
materials = list(MAT_METAL=75000, MAT_GLASS=37500)
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50)
|
||||
resistance_flags = FIRE_PROOF
|
||||
var/datum/effect_system/spark_spread/spark_system
|
||||
var/effectcooldown
|
||||
var/working = 0
|
||||
var/p_dir = NORTH
|
||||
var/p_flipped = FALSE
|
||||
var/paint_color = "grey"
|
||||
var/atmos_build_speed = 5 //deciseconds (500ms)
|
||||
var/disposal_build_speed = 5
|
||||
var/transit_build_speed = 5
|
||||
var/destroy_speed = 5
|
||||
var/paint_speed = 5
|
||||
var/category = ATMOS_CATEGORY
|
||||
var/piping_layer = PIPING_LAYER_DEFAULT
|
||||
var/datum/pipe_info/recipe
|
||||
var/static/datum/pipe_info/first_atmos
|
||||
var/static/datum/pipe_info/first_disposal
|
||||
var/static/datum/pipe_info/first_transit
|
||||
var/mode = BUILD_MODE | PAINT_MODE | DESTROY_MODE | WRENCH_MODE
|
||||
|
||||
/obj/item/pipe_dispenser/New()
|
||||
. = ..()
|
||||
spark_system = new /datum/effect_system/spark_spread
|
||||
spark_system.set_up(1, 0, src)
|
||||
spark_system.attach(src)
|
||||
if(!first_atmos)
|
||||
first_atmos = GLOB.atmos_pipe_recipes[GLOB.atmos_pipe_recipes[1]][1]
|
||||
if(!first_disposal)
|
||||
first_disposal = GLOB.disposal_pipe_recipes[GLOB.disposal_pipe_recipes[1]][1]
|
||||
if(!first_transit)
|
||||
first_transit = GLOB.transit_tube_recipes[GLOB.transit_tube_recipes[1]][1]
|
||||
|
||||
recipe = first_atmos
|
||||
|
||||
/obj/item/pipe_dispenser/Destroy()
|
||||
qdel(spark_system)
|
||||
spark_system = null
|
||||
return ..()
|
||||
|
||||
/obj/item/pipe_dispenser/attack_self(mob/user)
|
||||
ui_interact(user)
|
||||
|
||||
/obj/item/pipe_dispenser/suicide_act(mob/user)
|
||||
user.visible_message("<span class='suicide'>[user] points the end of the RPD down [user.p_their()] throat and presses a button! It looks like [user.p_theyre()] trying to commit suicide...</span>")
|
||||
playsound(get_turf(user), 'sound/machines/click.ogg', 50, 1)
|
||||
playsound(get_turf(user), 'sound/items/deconstruct.ogg', 50, 1)
|
||||
return(BRUTELOSS)
|
||||
|
||||
/obj/item/pipe_dispenser/ui_base_html(html)
|
||||
var/datum/asset/spritesheet/assets = get_asset_datum(/datum/asset/spritesheet/pipes)
|
||||
. = replacetext(html, "<!--customheadhtml-->", assets.css_tag())
|
||||
|
||||
/obj/item/pipe_dispenser/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
|
||||
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
var/datum/asset/assets = get_asset_datum(/datum/asset/spritesheet/pipes)
|
||||
assets.send(user)
|
||||
|
||||
ui = new(user, src, ui_key, "rpd", name, 300, 550, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/item/pipe_dispenser/ui_data(mob/user)
|
||||
var/list/data = list(
|
||||
"category" = category,
|
||||
"piping_layer" = piping_layer,
|
||||
"preview_rows" = recipe.get_preview(p_dir),
|
||||
"categories" = list(),
|
||||
"selected_color" = paint_color,
|
||||
"paint_colors" = GLOB.pipe_paint_colors,
|
||||
"mode" = mode
|
||||
)
|
||||
|
||||
var/list/recipes
|
||||
switch(category)
|
||||
if(ATMOS_CATEGORY)
|
||||
recipes = GLOB.atmos_pipe_recipes
|
||||
if(DISPOSALS_CATEGORY)
|
||||
recipes = GLOB.disposal_pipe_recipes
|
||||
if(TRANSIT_CATEGORY)
|
||||
recipes = GLOB.transit_tube_recipes
|
||||
for(var/c in recipes)
|
||||
var/list/cat = recipes[c]
|
||||
var/list/r = list()
|
||||
for(var/i in 1 to cat.len)
|
||||
var/datum/pipe_info/info = cat[i]
|
||||
r += list(list("pipe_name" = info.name, "pipe_index" = i, "selected" = (info == recipe)))
|
||||
data["categories"] += list(list("cat_name" = c, "recipes" = r))
|
||||
|
||||
return data
|
||||
|
||||
/obj/item/pipe_dispenser/ui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
if(!usr.canUseTopic(src))
|
||||
return
|
||||
var/playeffect = TRUE
|
||||
switch(action)
|
||||
if("color")
|
||||
paint_color = params["paint_color"]
|
||||
if("category")
|
||||
category = text2num(params["category"])
|
||||
switch(category)
|
||||
if(DISPOSALS_CATEGORY)
|
||||
recipe = first_disposal
|
||||
if(ATMOS_CATEGORY)
|
||||
recipe = first_atmos
|
||||
if(TRANSIT_CATEGORY)
|
||||
recipe = first_transit
|
||||
p_dir = NORTH
|
||||
playeffect = FALSE
|
||||
if("piping_layer")
|
||||
piping_layer = text2num(params["piping_layer"])
|
||||
playeffect = FALSE
|
||||
if("pipe_type")
|
||||
var/static/list/recipes
|
||||
if(!recipes)
|
||||
recipes = GLOB.disposal_pipe_recipes + GLOB.atmos_pipe_recipes + GLOB.transit_tube_recipes
|
||||
recipe = recipes[params["category"]][text2num(params["pipe_type"])]
|
||||
p_dir = NORTH
|
||||
if("setdir")
|
||||
p_dir = text2dir(params["dir"])
|
||||
p_flipped = text2num(params["flipped"])
|
||||
playeffect = FALSE
|
||||
if("mode")
|
||||
var/n = text2num(params["mode"])
|
||||
if(n == 2 && !(mode&1) && !(mode&2))
|
||||
mode |= 3
|
||||
else if(mode&n)
|
||||
mode &= ~n
|
||||
else
|
||||
mode |= n
|
||||
|
||||
if(playeffect && world.time >= effectcooldown)
|
||||
spark_system.start()
|
||||
effectcooldown = world.time + 100
|
||||
playsound(get_turf(src), 'sound/effects/pop.ogg', 50, 0)
|
||||
|
||||
/obj/item/pipe_dispenser/pre_attack(atom/A, mob/user)
|
||||
if(!user.IsAdvancedToolUser() || istype(A, /turf/open/space/transit))
|
||||
return ..()
|
||||
|
||||
//So that changing the menu settings doesn't affect the pipes already being built.
|
||||
var/queued_p_type = recipe.id
|
||||
var/queued_p_dir = p_dir
|
||||
var/queued_p_flipped = p_flipped
|
||||
|
||||
//make sure what we're clicking is valid for the current category
|
||||
var/static/list/make_pipe_whitelist
|
||||
if(!make_pipe_whitelist)
|
||||
make_pipe_whitelist = typecacheof(list(/obj/structure/lattice, /obj/structure/girder, /obj/item/pipe, /obj/structure/window, /obj/structure/grille))
|
||||
var/can_make_pipe = (isturf(A) || is_type_in_typecache(A, make_pipe_whitelist))
|
||||
|
||||
. = FALSE
|
||||
|
||||
if((mode&DESTROY_MODE) && istype(A, /obj/item/pipe) || istype(A, /obj/structure/disposalconstruct) || istype(A, /obj/structure/c_transit_tube) || istype(A, /obj/structure/c_transit_tube_pod) || istype(A, /obj/item/pipe_meter))
|
||||
to_chat(user, "<span class='notice'>You start destroying a pipe...</span>")
|
||||
playsound(get_turf(src), 'sound/machines/click.ogg', 50, 1)
|
||||
if(do_after(user, destroy_speed, target = A))
|
||||
activate()
|
||||
qdel(A)
|
||||
return
|
||||
|
||||
if((mode&PAINT_MODE))
|
||||
if(istype(A, /obj/machinery/atmospherics/pipe) && !istype(A, /obj/machinery/atmospherics/pipe/layer_manifold))
|
||||
var/obj/machinery/atmospherics/pipe/P = A
|
||||
to_chat(user, "<span class='notice'>You start painting \the [P] [paint_color]...</span>")
|
||||
playsound(get_turf(src), 'sound/machines/click.ogg', 50, 1)
|
||||
if(do_after(user, paint_speed, target = A))
|
||||
P.paint(GLOB.pipe_paint_colors[paint_color]) //paint the pipe
|
||||
user.visible_message("<span class='notice'>[user] paints \the [P] [paint_color].</span>","<span class='notice'>You paint \the [P] [paint_color].</span>")
|
||||
return
|
||||
var/obj/item/pipe/P = A
|
||||
if(istype(P) && findtext("[P.pipe_type]", "/obj/machinery/atmospherics/pipe") && !findtext("[P.pipe_type]", "layer_manifold"))
|
||||
to_chat(user, "<span class='notice'>You start painting \the [A] [paint_color]...</span>")
|
||||
playsound(get_turf(src), 'sound/machines/click.ogg', 50, 1)
|
||||
if(do_after(user, paint_speed, target = A))
|
||||
A.add_atom_colour(GLOB.pipe_paint_colors[paint_color], FIXED_COLOUR_PRIORITY) //paint the pipe
|
||||
user.visible_message("<span class='notice'>[user] paints \the [A] [paint_color].</span>","<span class='notice'>You paint \the [A] [paint_color].</span>")
|
||||
return
|
||||
|
||||
if(mode&BUILD_MODE)
|
||||
switch(category) //if we've gotten this var, the target is valid
|
||||
if(ATMOS_CATEGORY) //Making pipes
|
||||
if(!can_make_pipe)
|
||||
return ..()
|
||||
playsound(get_turf(src), 'sound/machines/click.ogg', 50, 1)
|
||||
if (recipe.type == /datum/pipe_info/meter)
|
||||
to_chat(user, "<span class='notice'>You start building a meter...</span>")
|
||||
if(do_after(user, atmos_build_speed, target = A))
|
||||
activate()
|
||||
var/obj/item/pipe_meter/PM = new /obj/item/pipe_meter(get_turf(A))
|
||||
PM.setAttachLayer(piping_layer)
|
||||
if(mode&WRENCH_MODE)
|
||||
PM.wrench_act(user, src)
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You start building a pipe...</span>")
|
||||
if(do_after(user, atmos_build_speed, target = A))
|
||||
activate()
|
||||
var/obj/machinery/atmospherics/path = queued_p_type
|
||||
var/pipe_item_type = initial(path.construction_type) || /obj/item/pipe
|
||||
var/obj/item/pipe/P = new pipe_item_type(get_turf(A), queued_p_type, queued_p_dir)
|
||||
|
||||
if(queued_p_flipped && istype(P, /obj/item/pipe/trinary/flippable))
|
||||
var/obj/item/pipe/trinary/flippable/F = P
|
||||
F.flipped = queued_p_flipped
|
||||
|
||||
P.update()
|
||||
P.add_fingerprint(usr)
|
||||
P.setPipingLayer(piping_layer)
|
||||
if(findtext("[queued_p_type]", "/obj/machinery/atmospherics/pipe") && !findtext("[queued_p_type]", "layer_manifold"))
|
||||
P.add_atom_colour(GLOB.pipe_paint_colors[paint_color], FIXED_COLOUR_PRIORITY)
|
||||
if(mode&WRENCH_MODE)
|
||||
P.wrench_act(user, src)
|
||||
|
||||
if(DISPOSALS_CATEGORY) //Making disposals pipes
|
||||
if(!can_make_pipe)
|
||||
return ..()
|
||||
A = get_turf(A)
|
||||
if(isclosedturf(A))
|
||||
to_chat(user, "<span class='warning'>[src]'s error light flickers; there's something in the way!</span>")
|
||||
return
|
||||
to_chat(user, "<span class='notice'>You start building a disposals pipe...</span>")
|
||||
playsound(get_turf(src), 'sound/machines/click.ogg', 50, 1)
|
||||
if(do_after(user, disposal_build_speed, target = A))
|
||||
var/obj/structure/disposalconstruct/C = new (A, queued_p_type, queued_p_dir, queued_p_flipped)
|
||||
|
||||
if(!C.can_place())
|
||||
to_chat(user, "<span class='warning'>There's not enough room to build that here!</span>")
|
||||
qdel(C)
|
||||
return
|
||||
|
||||
activate()
|
||||
|
||||
C.add_fingerprint(usr)
|
||||
C.update_icon()
|
||||
if(mode&WRENCH_MODE)
|
||||
C.wrench_act(user, src)
|
||||
return
|
||||
|
||||
if(TRANSIT_CATEGORY) //Making transit tubes
|
||||
if(!can_make_pipe)
|
||||
return ..()
|
||||
A = get_turf(A)
|
||||
if(isclosedturf(A))
|
||||
to_chat(user, "<span class='warning'>[src]'s error light flickers; there's something in the way!</span>")
|
||||
return
|
||||
to_chat(user, "<span class='notice'>You start building a transit tube...</span>")
|
||||
playsound(get_turf(src), 'sound/machines/click.ogg', 50, 1)
|
||||
if(do_after(user, transit_build_speed, target = A))
|
||||
for(var/obj/structure/c_transit_tube/tube in A)
|
||||
if(tube.dir == queued_p_dir || (queued_p_flipped && (tube.dir == turn(queued_p_dir, 45))))
|
||||
to_chat(user, "<span class='warning'>[src]'s error light flickers; there's already a pipe in the way!</span>")
|
||||
return
|
||||
activate()
|
||||
if(queued_p_type == /obj/structure/c_transit_tube_pod)
|
||||
var/obj/structure/c_transit_tube_pod/pod = new /obj/structure/c_transit_tube_pod(A)
|
||||
pod.add_fingerprint(usr)
|
||||
if(mode&WRENCH_MODE)
|
||||
pod.wrench_act(user, src)
|
||||
|
||||
else
|
||||
var/obj/structure/c_transit_tube/tube = new queued_p_type(A)
|
||||
tube.setDir(queued_p_dir)
|
||||
|
||||
if(queued_p_flipped)
|
||||
tube.setDir(turn(queued_p_dir, 45))
|
||||
tube.simple_rotate_flip()
|
||||
|
||||
tube.add_fingerprint(usr)
|
||||
if(mode&WRENCH_MODE)
|
||||
tube.wrench_act(user, src)
|
||||
return
|
||||
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/pipe_dispenser/proc/activate()
|
||||
playsound(get_turf(src), 'sound/items/deconstruct.ogg', 50, 1)
|
||||
|
||||
#undef ATMOS_CATEGORY
|
||||
#undef DISPOSALS_CATEGORY
|
||||
#undef TRANSIT_CATEGORY
|
||||
|
||||
#undef BUILD_MODE
|
||||
#undef DESTROY_MODE
|
||||
#undef PAINT_MODE
|
||||
#undef WRENCH_MODE
|
||||
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
CONTAINS:
|
||||
RSF
|
||||
|
||||
*/
|
||||
/obj/item/rsf
|
||||
name = "\improper Rapid-Service-Fabricator"
|
||||
desc = "A device used to rapidly deploy service items."
|
||||
icon = 'icons/obj/tools.dmi'
|
||||
icon_state = "rcd"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
|
||||
opacity = 0
|
||||
density = FALSE
|
||||
anchored = FALSE
|
||||
item_flags = NOBLUDGEON
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
|
||||
var/matter = 0
|
||||
var/mode = 1
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
|
||||
/obj/item/rsf/examine(mob/user)
|
||||
..()
|
||||
to_chat(user, "<span class='notice'>It currently holds [matter]/30 fabrication-units.</span>")
|
||||
|
||||
/obj/item/rsf/cyborg
|
||||
matter = 30
|
||||
|
||||
/obj/item/rsf/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/rcd_ammo))
|
||||
if((matter + 10) > 30)
|
||||
to_chat(user, "The RSF can't hold any more matter.")
|
||||
return
|
||||
qdel(W)
|
||||
matter += 10
|
||||
playsound(src.loc, 'sound/machines/click.ogg', 10, 1)
|
||||
to_chat(user, "The RSF now holds [matter]/30 fabrication-units.")
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/rsf/attack_self(mob/user)
|
||||
playsound(src.loc, 'sound/effects/pop.ogg', 50, 0)
|
||||
switch(mode)
|
||||
if(1)
|
||||
mode = 2
|
||||
to_chat(user, "Changed dispensing mode to 'Drinking Glass'")
|
||||
if(2)
|
||||
mode = 3
|
||||
to_chat(user, "Changed dispensing mode to 'Paper'")
|
||||
if(3)
|
||||
mode = 4
|
||||
to_chat(user, "Changed dispensing mode to 'Pen'")
|
||||
if(4)
|
||||
mode = 5
|
||||
to_chat(user, "Changed dispensing mode to 'Dice Pack'")
|
||||
if(5)
|
||||
mode = 6
|
||||
to_chat(user, "Changed dispensing mode to 'Cigarette'")
|
||||
if(6)
|
||||
mode = 1
|
||||
to_chat(user, "Changed dispensing mode to 'Dosh'")
|
||||
// Change mode
|
||||
|
||||
/obj/item/rsf/afterattack(atom/A, mob/user, proximity)
|
||||
. = ..()
|
||||
if(!proximity)
|
||||
return
|
||||
if (!(istype(A, /obj/structure/table) || isfloorturf(A)))
|
||||
return
|
||||
|
||||
if(matter < 1)
|
||||
to_chat(user, "<span class='warning'>\The [src] doesn't have enough matter left.</span>")
|
||||
return
|
||||
if(iscyborg(user))
|
||||
var/mob/living/silicon/robot/R = user
|
||||
if(!R.cell || R.cell.charge < 200)
|
||||
to_chat(user, "<span class='warning'>You do not have enough power to use [src].</span>")
|
||||
return
|
||||
|
||||
var/turf/T = get_turf(A)
|
||||
playsound(src.loc, 'sound/machines/click.ogg', 10, 1)
|
||||
switch(mode)
|
||||
if(1)
|
||||
to_chat(user, "Dispensing Dosh...")
|
||||
new /obj/item/stack/spacecash/c10(T)
|
||||
use_matter(200, user)
|
||||
if(2)
|
||||
to_chat(user, "Dispensing Drinking Glass...")
|
||||
new /obj/item/reagent_containers/food/drinks/drinkingglass(T)
|
||||
use_matter(20, user)
|
||||
if(3)
|
||||
to_chat(user, "Dispensing Paper Sheet...")
|
||||
new /obj/item/paper(T)
|
||||
use_matter(10, user)
|
||||
if(4)
|
||||
to_chat(user, "Dispensing Pen...")
|
||||
new /obj/item/pen(T)
|
||||
use_matter(50, user)
|
||||
if(5)
|
||||
to_chat(user, "Dispensing Dice Pack...")
|
||||
new /obj/item/storage/pill_bottle/dice(T)
|
||||
use_matter(200, user)
|
||||
if(6)
|
||||
to_chat(user, "Dispensing Cigarette...")
|
||||
new /obj/item/clothing/mask/cigarette(T)
|
||||
use_matter(10, user)
|
||||
|
||||
/obj/item/rsf/proc/use_matter(charge, mob/user)
|
||||
if (iscyborg(user))
|
||||
var/mob/living/silicon/robot/R = user
|
||||
R.cell.charge -= charge
|
||||
else
|
||||
matter--
|
||||
to_chat(user, "The RSF now holds [matter]/30 fabrication-units.")
|
||||
|
||||
/obj/item/cookiesynth
|
||||
name = "Cookie Synthesizer"
|
||||
desc = "A self-recharging device used to rapidly deploy cookies."
|
||||
icon = 'icons/obj/tools.dmi'
|
||||
icon_state = "rcd"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
|
||||
var/matter = 10
|
||||
var/toxin = 0
|
||||
var/cooldown = 0
|
||||
var/cooldowndelay = 10
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
|
||||
/obj/item/cookiesynth/examine(mob/user)
|
||||
..()
|
||||
to_chat(user, "<span class='notice'>It currently holds [matter]/10 cookie-units.</span>")
|
||||
|
||||
/obj/item/cookiesynth/attackby()
|
||||
return
|
||||
|
||||
/obj/item/cookiesynth/emag_act(mob/user)
|
||||
obj_flags ^= EMAGGED
|
||||
if(obj_flags & EMAGGED)
|
||||
to_chat(user, "<span class='warning'>You short out [src]'s reagent safety checker!</span>")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You reset [src]'s reagent safety checker!</span>")
|
||||
toxin = 0
|
||||
|
||||
/obj/item/cookiesynth/attack_self(mob/user)
|
||||
var/mob/living/silicon/robot/P = null
|
||||
if(iscyborg(user))
|
||||
P = user
|
||||
if((obj_flags & EMAGGED)&&!toxin)
|
||||
toxin = 1
|
||||
to_chat(user, "Cookie Synthesizer Hacked")
|
||||
else if(P.emagged&&!toxin)
|
||||
toxin = 1
|
||||
to_chat(user, "Cookie Synthesizer Hacked")
|
||||
else
|
||||
toxin = 0
|
||||
to_chat(user, "Cookie Synthesizer Reset")
|
||||
|
||||
/obj/item/cookiesynth/process()
|
||||
if(matter < 10)
|
||||
matter++
|
||||
|
||||
/obj/item/cookiesynth/afterattack(atom/A, mob/user, proximity)
|
||||
. = ..()
|
||||
if(cooldown > world.time)
|
||||
return
|
||||
if(!proximity)
|
||||
return
|
||||
if (!(istype(A, /obj/structure/table) || isfloorturf(A)))
|
||||
return
|
||||
if(matter < 1)
|
||||
to_chat(user, "<span class='warning'>[src] doesn't have enough matter left. Wait for it to recharge!</span>")
|
||||
return
|
||||
if(iscyborg(user))
|
||||
var/mob/living/silicon/robot/R = user
|
||||
if(!R.cell || R.cell.charge < 400)
|
||||
to_chat(user, "<span class='warning'>You do not have enough power to use [src].</span>")
|
||||
return
|
||||
var/turf/T = get_turf(A)
|
||||
playsound(src.loc, 'sound/machines/click.ogg', 10, 1)
|
||||
to_chat(user, "Fabricating Cookie..")
|
||||
var/obj/item/reagent_containers/food/snacks/cookie/S = new /obj/item/reagent_containers/food/snacks/cookie(T)
|
||||
if(toxin)
|
||||
S.reagents.add_reagent("chloralhydratedelayed", 10)
|
||||
if (iscyborg(user))
|
||||
var/mob/living/silicon/robot/R = user
|
||||
R.cell.charge -= 100
|
||||
else
|
||||
matter--
|
||||
cooldown = world.time + cooldowndelay
|
||||
@@ -0,0 +1,127 @@
|
||||
/obj/item/airlock_painter
|
||||
name = "airlock painter"
|
||||
desc = "An advanced autopainter preprogrammed with several paintjobs for airlocks. Use it on an airlock during or after construction to change the paintjob."
|
||||
icon = 'icons/obj/objects.dmi'
|
||||
icon_state = "paint sprayer"
|
||||
item_state = "paint sprayer"
|
||||
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
|
||||
materials = list(MAT_METAL=50, MAT_GLASS=50)
|
||||
|
||||
flags_1 = CONDUCT_1
|
||||
item_flags = NOBLUDGEON
|
||||
slot_flags = ITEM_SLOT_BELT
|
||||
usesound = 'sound/effects/spray2.ogg'
|
||||
|
||||
var/obj/item/toner/ink = null
|
||||
|
||||
/obj/item/airlock_painter/Initialize()
|
||||
. = ..()
|
||||
ink = new /obj/item/toner(src)
|
||||
|
||||
//This proc doesn't just check if the painter can be used, but also uses it.
|
||||
//Only call this if you are certain that the painter will be used right after this check!
|
||||
/obj/item/airlock_painter/proc/use_paint(mob/user)
|
||||
if(can_use(user))
|
||||
ink.charges--
|
||||
playsound(src.loc, 'sound/effects/spray2.ogg', 50, 1)
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
|
||||
//This proc only checks if the painter can be used.
|
||||
//Call this if you don't want the painter to be used right after this check, for example
|
||||
//because you're expecting user input.
|
||||
/obj/item/airlock_painter/proc/can_use(mob/user)
|
||||
if(!ink)
|
||||
to_chat(user, "<span class='notice'>There is no toner cartridge installed in [src]!</span>")
|
||||
return 0
|
||||
else if(ink.charges < 1)
|
||||
to_chat(user, "<span class='notice'>[src] is out of ink!</span>")
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
|
||||
/obj/item/airlock_painter/suicide_act(mob/user)
|
||||
var/obj/item/organ/lungs/L = user.getorganslot(ORGAN_SLOT_LUNGS)
|
||||
|
||||
if(can_use(user) && L)
|
||||
user.visible_message("<span class='suicide'>[user] is inhaling toner from [src]! It looks like [user.p_theyre()] trying to commit suicide!</span>")
|
||||
use(user)
|
||||
|
||||
// Once you've inhaled the toner, you throw up your lungs
|
||||
// and then die.
|
||||
|
||||
// Find out if there is an open turf in front of us,
|
||||
// and if not, pick the turf we are standing on.
|
||||
var/turf/T = get_step(get_turf(src), user.dir)
|
||||
if(!isopenturf(T))
|
||||
T = get_turf(src)
|
||||
|
||||
// they managed to lose their lungs between then and
|
||||
// now. Good job.
|
||||
if(!L)
|
||||
return OXYLOSS
|
||||
|
||||
L.Remove(user)
|
||||
|
||||
// make some colorful reagent, and apply it to the lungs
|
||||
L.create_reagents(10)
|
||||
L.reagents.add_reagent("colorful_reagent", 10)
|
||||
L.reagents.reaction(L, TOUCH, 1)
|
||||
|
||||
// TODO maybe add some colorful vomit?
|
||||
|
||||
user.visible_message("<span class='suicide'>[user] vomits out [user.p_their()] [L]!</span>")
|
||||
playsound(user.loc, 'sound/effects/splat.ogg', 50, 1)
|
||||
|
||||
L.forceMove(T)
|
||||
|
||||
return (TOXLOSS|OXYLOSS)
|
||||
else if(can_use(user) && !L)
|
||||
user.visible_message("<span class='suicide'>[user] is spraying toner on [user.p_them()]self from [src]! It looks like [user.p_theyre()] trying to commit suicide.</span>")
|
||||
user.reagents.add_reagent("colorful_reagent", 1)
|
||||
user.reagents.reaction(user, TOUCH, 1)
|
||||
return TOXLOSS
|
||||
|
||||
else
|
||||
user.visible_message("<span class='suicide'>[user] is trying to inhale toner from [src]! It might be a suicide attempt if [src] had any toner.</span>")
|
||||
return SHAME
|
||||
|
||||
|
||||
/obj/item/airlock_painter/examine(mob/user)
|
||||
..()
|
||||
if(!ink)
|
||||
to_chat(user, "<span class='notice'>It doesn't have a toner cartridge installed.</span>")
|
||||
return
|
||||
var/ink_level = "high"
|
||||
if(ink.charges < 1)
|
||||
ink_level = "empty"
|
||||
else if((ink.charges/ink.max_charges) <= 0.25) //25%
|
||||
ink_level = "low"
|
||||
else if((ink.charges/ink.max_charges) > 1) //Over 100% (admin var edit)
|
||||
ink_level = "dangerously high"
|
||||
to_chat(user, "<span class='notice'>Its ink levels look [ink_level].</span>")
|
||||
|
||||
|
||||
/obj/item/airlock_painter/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/toner))
|
||||
if(ink)
|
||||
to_chat(user, "<span class='notice'>[src] already contains \a [ink].</span>")
|
||||
return
|
||||
if(!user.transferItemToLoc(W, src))
|
||||
return
|
||||
to_chat(user, "<span class='notice'>You install [W] into [src].</span>")
|
||||
ink = W
|
||||
playsound(src.loc, 'sound/machines/click.ogg', 50, 1)
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/airlock_painter/attack_self(mob/user)
|
||||
if(ink)
|
||||
playsound(src.loc, 'sound/machines/click.ogg', 50, 1)
|
||||
ink.forceMove(user.drop_location())
|
||||
user.put_in_hands(ink)
|
||||
to_chat(user, "<span class='notice'>You remove [ink] from [src].</span>")
|
||||
ink = null
|
||||
@@ -0,0 +1,123 @@
|
||||
/obj/item/wallframe
|
||||
icon = 'icons/obj/wallframe.dmi'
|
||||
materials = list(MAT_METAL=MINERAL_MATERIAL_AMOUNT*2)
|
||||
flags_1 = CONDUCT_1
|
||||
item_state = "syringe_kit"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
var/result_path
|
||||
var/inverse = 0 // For inverse dir frames like light fixtures.
|
||||
var/pixel_shift //The amount of pixels
|
||||
|
||||
/obj/item/wallframe/proc/try_build(turf/on_wall, mob/user)
|
||||
if(get_dist(on_wall,user)>1)
|
||||
return
|
||||
var/ndir = get_dir(on_wall, user)
|
||||
if(!(ndir in GLOB.cardinals))
|
||||
return
|
||||
var/turf/T = get_turf(user)
|
||||
var/area/A = get_area(T)
|
||||
if(!isfloorturf(T))
|
||||
to_chat(user, "<span class='warning'>You cannot place [src] on this spot!</span>")
|
||||
return
|
||||
if(A.always_unpowered)
|
||||
to_chat(user, "<span class='warning'>You cannot place [src] in this area!</span>")
|
||||
return
|
||||
if(gotwallitem(T, ndir, inverse*2))
|
||||
to_chat(user, "<span class='warning'>There's already an item on this wall!</span>")
|
||||
return
|
||||
|
||||
return TRUE
|
||||
|
||||
/obj/item/wallframe/proc/attach(turf/on_wall, mob/user)
|
||||
if(result_path)
|
||||
playsound(src.loc, 'sound/machines/click.ogg', 75, 1)
|
||||
user.visible_message("[user.name] attaches [src] to the wall.",
|
||||
"<span class='notice'>You attach [src] to the wall.</span>",
|
||||
"<span class='italics'>You hear clicking.</span>")
|
||||
var/ndir = get_dir(on_wall,user)
|
||||
if(inverse)
|
||||
ndir = turn(ndir, 180)
|
||||
|
||||
var/obj/O = new result_path(get_turf(user), ndir, TRUE)
|
||||
if(pixel_shift)
|
||||
switch(ndir)
|
||||
if(NORTH)
|
||||
O.pixel_y = pixel_shift
|
||||
if(SOUTH)
|
||||
O.pixel_y = -pixel_shift
|
||||
if(EAST)
|
||||
O.pixel_x = pixel_shift
|
||||
if(WEST)
|
||||
O.pixel_x = -pixel_shift
|
||||
after_attach(O)
|
||||
|
||||
qdel(src)
|
||||
|
||||
/obj/item/wallframe/proc/after_attach(var/obj/O)
|
||||
transfer_fingerprints_to(O)
|
||||
|
||||
/obj/item/wallframe/attackby(obj/item/W, mob/user, params)
|
||||
..()
|
||||
if(istype(W, /obj/item/screwdriver))
|
||||
// For camera-building borgs
|
||||
var/turf/T = get_step(get_turf(user), user.dir)
|
||||
if(iswallturf(T))
|
||||
T.attackby(src, user, params)
|
||||
|
||||
var/metal_amt = round(materials[MAT_METAL]/MINERAL_MATERIAL_AMOUNT)
|
||||
var/glass_amt = round(materials[MAT_GLASS]/MINERAL_MATERIAL_AMOUNT)
|
||||
|
||||
if(istype(W, /obj/item/wrench) && (metal_amt || glass_amt))
|
||||
to_chat(user, "<span class='notice'>You dismantle [src].</span>")
|
||||
if(metal_amt)
|
||||
new /obj/item/stack/sheet/metal(get_turf(src), metal_amt)
|
||||
if(glass_amt)
|
||||
new /obj/item/stack/sheet/glass(get_turf(src), glass_amt)
|
||||
qdel(src)
|
||||
|
||||
|
||||
|
||||
// APC HULL
|
||||
/obj/item/wallframe/apc
|
||||
name = "\improper APC frame"
|
||||
desc = "Used for repairing or building APCs."
|
||||
icon_state = "apc"
|
||||
result_path = /obj/machinery/power/apc
|
||||
inverse = 1
|
||||
|
||||
|
||||
/obj/item/wallframe/apc/try_build(turf/on_wall, user)
|
||||
if(!..())
|
||||
return
|
||||
var/turf/T = get_turf(on_wall) //the user is not where it needs to be.
|
||||
var/area/A = get_area(T)
|
||||
if(A.get_apc())
|
||||
to_chat(user, "<span class='warning'>This area already has an APC!</span>")
|
||||
return //only one APC per area
|
||||
if(!A.requires_power)
|
||||
to_chat(user, "<span class='warning'>You cannot place [src] in this area!</span>")
|
||||
return //can't place apcs in areas with no power requirement
|
||||
for(var/obj/machinery/power/terminal/E in T)
|
||||
if(E.master)
|
||||
to_chat(user, "<span class='warning'>There is another network terminal here!</span>")
|
||||
return
|
||||
else
|
||||
new /obj/item/stack/cable_coil(T, 10)
|
||||
to_chat(user, "<span class='notice'>You cut the cables and disassemble the unused power terminal.</span>")
|
||||
qdel(E)
|
||||
return TRUE
|
||||
|
||||
|
||||
/obj/item/electronics
|
||||
desc = "Looks like a circuit. Probably is."
|
||||
icon = 'icons/obj/module.dmi'
|
||||
icon_state = "door_electronics"
|
||||
item_state = "electronic"
|
||||
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
|
||||
flags_1 = CONDUCT_1
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
materials = list(MAT_METAL=50, MAT_GLASS=50)
|
||||
grind_results = list("iron" = 10, "silicon" = 10)
|
||||
@@ -0,0 +1,227 @@
|
||||
#define AREA_ERRNONE 0
|
||||
#define AREA_STATION 1
|
||||
#define AREA_SPACE 2
|
||||
#define AREA_SPECIAL 3
|
||||
|
||||
/obj/item/areaeditor
|
||||
name = "area modification item"
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "blueprints"
|
||||
attack_verb = list("attacked", "bapped", "hit")
|
||||
var/fluffnotice = "Nobody's gonna read this stuff!"
|
||||
var/in_use = FALSE
|
||||
|
||||
/obj/item/areaeditor/attack_self(mob/user)
|
||||
add_fingerprint(user)
|
||||
. = "<BODY><HTML><head><title>[src]</title></head> \
|
||||
<h2>[station_name()] [src.name]</h2> \
|
||||
<small>[fluffnotice]</small><hr>"
|
||||
switch(get_area_type())
|
||||
if(AREA_SPACE)
|
||||
. += "<p>According to the [src.name], you are now in an unclaimed territory.</p>"
|
||||
if(AREA_SPECIAL)
|
||||
. += "<p>This place is not noted on the [src.name].</p>"
|
||||
. += "<p><a href='?src=[REF(src)];create_area=1'>Create or modify an existing area</a></p>"
|
||||
|
||||
|
||||
/obj/item/areaeditor/Topic(href, href_list)
|
||||
if(..())
|
||||
return TRUE
|
||||
if(!usr.canUseTopic(src))
|
||||
usr << browse(null, "window=blueprints")
|
||||
return TRUE
|
||||
if(href_list["create_area"])
|
||||
if(in_use)
|
||||
return
|
||||
in_use = TRUE
|
||||
create_area(usr)
|
||||
in_use = FALSE
|
||||
updateUsrDialog()
|
||||
|
||||
//Station blueprints!!!
|
||||
/obj/item/areaeditor/blueprints
|
||||
name = "station blueprints"
|
||||
desc = "Blueprints of the station. There is a \"Classified\" stamp and several coffee stains on it."
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "blueprints"
|
||||
fluffnotice = "Property of Nanotrasen. For heads of staff only. Store in high-secure storage."
|
||||
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
|
||||
var/list/image/showing = list()
|
||||
var/client/viewing
|
||||
var/legend = FALSE //Viewing the wire legend
|
||||
|
||||
|
||||
/obj/item/areaeditor/blueprints/Destroy()
|
||||
clear_viewer()
|
||||
return ..()
|
||||
|
||||
|
||||
/obj/item/areaeditor/blueprints/attack_self(mob/user)
|
||||
. = ..()
|
||||
if(!legend)
|
||||
var/area/A = get_area(user)
|
||||
if(get_area_type() == AREA_STATION)
|
||||
. += "<p>According to \the [src], you are now in <b>\"[html_encode(A.name)]\"</b>.</p>"
|
||||
. += "<p><a href='?src=[REF(src)];edit_area=1'>Change area name</a></p>"
|
||||
. += "<p><a href='?src=[REF(src)];view_legend=1'>View wire colour legend</a></p>"
|
||||
if(!viewing)
|
||||
. += "<p><a href='?src=[REF(src)];view_blueprints=1'>View structural data</a></p>"
|
||||
else
|
||||
. += "<p><a href='?src=[REF(src)];refresh=1'>Refresh structural data</a></p>"
|
||||
. += "<p><a href='?src=[REF(src)];hide_blueprints=1'>Hide structural data</a></p>"
|
||||
else
|
||||
if(legend == TRUE)
|
||||
. += "<a href='?src=[REF(src)];exit_legend=1'><< Back</a>"
|
||||
. += view_wire_devices(user);
|
||||
else
|
||||
//legend is a wireset
|
||||
. += "<a href='?src=[REF(src)];view_legend=1'><< Back</a>"
|
||||
. += view_wire_set(user, legend)
|
||||
var/datum/browser/popup = new(user, "blueprints", "[src]", 700, 500)
|
||||
popup.set_content(.)
|
||||
popup.open()
|
||||
onclose(user, "blueprints")
|
||||
|
||||
|
||||
/obj/item/areaeditor/blueprints/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
if(href_list["edit_area"])
|
||||
if(get_area_type()!=AREA_STATION)
|
||||
return
|
||||
if(in_use)
|
||||
return
|
||||
in_use = TRUE
|
||||
edit_area()
|
||||
in_use = FALSE
|
||||
if(href_list["exit_legend"])
|
||||
legend = FALSE;
|
||||
if(href_list["view_legend"])
|
||||
legend = TRUE;
|
||||
if(href_list["view_wireset"])
|
||||
legend = href_list["view_wireset"];
|
||||
if(href_list["view_blueprints"])
|
||||
set_viewer(usr, "<span class='notice'>You flip the blueprints over to view the complex information diagram.</span>")
|
||||
if(href_list["hide_blueprints"])
|
||||
clear_viewer(usr,"<span class='notice'>You flip the blueprints over to view the simple information diagram.</span>")
|
||||
if(href_list["refresh"])
|
||||
clear_viewer(usr)
|
||||
set_viewer(usr)
|
||||
|
||||
attack_self(usr) //this is not the proper way, but neither of the old update procs work! it's too ancient and I'm tired shush.
|
||||
|
||||
/obj/item/areaeditor/blueprints/proc/get_images(turf/T, viewsize)
|
||||
. = list()
|
||||
for(var/turf/TT in range(viewsize, T))
|
||||
if(TT.blueprint_data)
|
||||
. += TT.blueprint_data
|
||||
|
||||
/obj/item/areaeditor/blueprints/proc/set_viewer(mob/user, message = "")
|
||||
if(user && user.client)
|
||||
if(viewing)
|
||||
clear_viewer()
|
||||
viewing = user.client
|
||||
showing = get_images(get_turf(user), viewing.view)
|
||||
viewing.images |= showing
|
||||
if(message)
|
||||
to_chat(user, message)
|
||||
|
||||
/obj/item/areaeditor/blueprints/proc/clear_viewer(mob/user, message = "")
|
||||
if(viewing)
|
||||
viewing.images -= showing
|
||||
viewing = null
|
||||
showing.Cut()
|
||||
if(message)
|
||||
to_chat(user, message)
|
||||
|
||||
/obj/item/areaeditor/blueprints/dropped(mob/user)
|
||||
..()
|
||||
clear_viewer()
|
||||
legend = FALSE
|
||||
|
||||
|
||||
|
||||
/obj/item/areaeditor/proc/get_area_type(area/A)
|
||||
if(!A)
|
||||
A = get_area(usr)
|
||||
if(A.outdoors)
|
||||
return AREA_SPACE
|
||||
var/list/SPECIALS = list(
|
||||
/area/shuttle,
|
||||
/area/admin,
|
||||
/area/arrival,
|
||||
/area/centcom,
|
||||
/area/asteroid,
|
||||
/area/tdome,
|
||||
/area/wizard_station
|
||||
)
|
||||
for (var/type in SPECIALS)
|
||||
if ( istype(A,type) )
|
||||
return AREA_SPECIAL
|
||||
return AREA_STATION
|
||||
|
||||
/obj/item/areaeditor/blueprints/proc/view_wire_devices(mob/user)
|
||||
var/message = "<br>You examine the wire legend.<br>"
|
||||
for(var/wireset in GLOB.wire_color_directory)
|
||||
message += "<br><a href='?src=[REF(src)];view_wireset=[wireset]'>[GLOB.wire_name_directory[wireset]]</a>"
|
||||
message += "</p>"
|
||||
return message
|
||||
|
||||
/obj/item/areaeditor/blueprints/proc/view_wire_set(mob/user, wireset)
|
||||
//for some reason you can't use wireset directly as a derefencer so this is the next best :/
|
||||
for(var/device in GLOB.wire_color_directory)
|
||||
if("[device]" == wireset) //I know... don't change it...
|
||||
var/message = "<p><b>[GLOB.wire_name_directory[device]]:</b>"
|
||||
for(var/Col in GLOB.wire_color_directory[device])
|
||||
var/wire_name = GLOB.wire_color_directory[device][Col]
|
||||
if(!findtext(wire_name, WIRE_DUD_PREFIX)) //don't show duds
|
||||
message += "<p><span style='color: [Col]'>[Col]</span>: [wire_name]</p>"
|
||||
message += "</p>"
|
||||
return message
|
||||
return ""
|
||||
|
||||
/obj/item/areaeditor/proc/edit_area()
|
||||
var/area/A = get_area(usr)
|
||||
var/prevname = "[A.name]"
|
||||
var/str = stripped_input(usr,"New area name:", "Area Creation", "", MAX_NAME_LEN)
|
||||
if(!str || !length(str) || str==prevname) //cancel
|
||||
return
|
||||
if(length(str) > 50)
|
||||
to_chat(usr, "<span class='warning'>The given name is too long. The area's name is unchanged.</span>")
|
||||
return
|
||||
set_area_machinery_title(A,str,prevname)
|
||||
A.name = str
|
||||
if(A.firedoors)
|
||||
for(var/D in A.firedoors)
|
||||
var/obj/machinery/door/firedoor/FD = D
|
||||
FD.CalculateAffectingAreas()
|
||||
to_chat(usr, "<span class='notice'>You rename the '[prevname]' to '[str]'.</span>")
|
||||
log_game("[key_name(usr)] has renamed [prevname] to [str]")
|
||||
A.update_areasize()
|
||||
interact()
|
||||
return 1
|
||||
|
||||
|
||||
/obj/item/areaeditor/proc/set_area_machinery_title(area/A,title,oldtitle)
|
||||
if(!oldtitle) // or replacetext goes to infinite loop
|
||||
return
|
||||
for(var/obj/machinery/airalarm/M in A)
|
||||
M.name = replacetext(M.name,oldtitle,title)
|
||||
for(var/obj/machinery/power/apc/M in A)
|
||||
M.name = replacetext(M.name,oldtitle,title)
|
||||
for(var/obj/machinery/atmospherics/components/unary/vent_scrubber/M in A)
|
||||
M.name = replacetext(M.name,oldtitle,title)
|
||||
for(var/obj/machinery/atmospherics/components/unary/vent_pump/M in A)
|
||||
M.name = replacetext(M.name,oldtitle,title)
|
||||
for(var/obj/machinery/door/M in A)
|
||||
M.name = replacetext(M.name,oldtitle,title)
|
||||
//TODO: much much more. Unnamed airlocks, cameras, etc.
|
||||
|
||||
//Blueprint Subtypes
|
||||
|
||||
/obj/item/areaeditor/blueprints/cyborg
|
||||
name = "station schematics"
|
||||
desc = "A digital copy of the station blueprints stored in your memory."
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "blueprints"
|
||||
fluffnotice = "Intellectual Property of Nanotrasen. For use in engineering cyborgs only. Wipe from memory upon departure from the station."
|
||||
@@ -0,0 +1,51 @@
|
||||
/obj/item/organ/body_egg
|
||||
name = "body egg"
|
||||
desc = "All slimy and yuck."
|
||||
icon_state = "innards"
|
||||
zone = BODY_ZONE_CHEST
|
||||
slot = "parasite_egg"
|
||||
|
||||
/obj/item/organ/body_egg/on_find(mob/living/finder)
|
||||
..()
|
||||
to_chat(finder, "<span class='warning'>You found an unknown alien organism in [owner]'s [zone]!</span>")
|
||||
|
||||
/obj/item/organ/body_egg/New(loc)
|
||||
if(iscarbon(loc))
|
||||
src.Insert(loc)
|
||||
return ..()
|
||||
|
||||
/obj/item/organ/body_egg/Insert(var/mob/living/carbon/M, special = 0)
|
||||
..()
|
||||
ADD_TRAIT(owner, TRAIT_XENO_HOST, TRAIT_GENERIC)
|
||||
START_PROCESSING(SSobj, src)
|
||||
owner.med_hud_set_status()
|
||||
INVOKE_ASYNC(src, .proc/AddInfectionImages, owner)
|
||||
|
||||
/obj/item/organ/body_egg/Remove(var/mob/living/carbon/M, special = 0)
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
if(owner)
|
||||
REMOVE_TRAIT(owner, TRAIT_XENO_HOST, TRAIT_GENERIC)
|
||||
owner.med_hud_set_status()
|
||||
INVOKE_ASYNC(src, .proc/RemoveInfectionImages, owner)
|
||||
..()
|
||||
|
||||
/obj/item/organ/body_egg/process()
|
||||
if(!owner)
|
||||
return
|
||||
if(!(src in owner.internal_organs))
|
||||
Remove(owner)
|
||||
return
|
||||
egg_process()
|
||||
|
||||
/obj/item/organ/body_egg/proc/egg_process()
|
||||
return
|
||||
|
||||
/obj/item/organ/body_egg/proc/RefreshInfectionImage()
|
||||
RemoveInfectionImages()
|
||||
AddInfectionImages()
|
||||
|
||||
/obj/item/organ/body_egg/proc/AddInfectionImages()
|
||||
return
|
||||
|
||||
/obj/item/organ/body_egg/proc/RemoveInfectionImages()
|
||||
return
|
||||
@@ -0,0 +1,83 @@
|
||||
|
||||
/obj/item/bodybag
|
||||
name = "body bag"
|
||||
desc = "A folded bag designed for the storage and transportation of cadavers."
|
||||
icon = 'icons/obj/bodybag.dmi'
|
||||
icon_state = "bodybag_folded"
|
||||
var/unfoldedbag_path = /obj/structure/closet/body_bag
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
|
||||
/obj/item/bodybag/attack_self(mob/user)
|
||||
deploy_bodybag(user, user.loc)
|
||||
|
||||
/obj/item/bodybag/afterattack(atom/target, mob/user, proximity)
|
||||
. = ..()
|
||||
if(proximity)
|
||||
if(isopenturf(target))
|
||||
deploy_bodybag(user, target)
|
||||
|
||||
/obj/item/bodybag/proc/deploy_bodybag(mob/user, atom/location)
|
||||
var/obj/structure/closet/body_bag/R = new unfoldedbag_path(location)
|
||||
R.open(user)
|
||||
R.add_fingerprint(user)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/bodybag/suicide_act(mob/user)
|
||||
if(isopenturf(user.loc))
|
||||
user.visible_message("<span class='suicide'>[user] is crawling into [src]! It looks like [user.p_theyre()] trying to commit suicide!</span>")
|
||||
var/obj/structure/closet/body_bag/R = new unfoldedbag_path(user.loc)
|
||||
R.add_fingerprint(user)
|
||||
qdel(src)
|
||||
user.forceMove(R)
|
||||
playsound(src, 'sound/items/zip.ogg', 15, 1, -3)
|
||||
return (OXYLOSS)
|
||||
..()
|
||||
|
||||
// Bluespace bodybag
|
||||
|
||||
/obj/item/bodybag/bluespace
|
||||
name = "bluespace body bag"
|
||||
desc = "A folded bluespace body bag designed for the storage and transportation of cadavers."
|
||||
icon = 'icons/obj/bodybag.dmi'
|
||||
icon_state = "bluebodybag_folded"
|
||||
unfoldedbag_path = /obj/structure/closet/body_bag/bluespace
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
item_flags = NO_MAT_REDEMPTION
|
||||
|
||||
|
||||
/obj/item/bodybag/bluespace/examine(mob/user)
|
||||
..()
|
||||
if(contents.len)
|
||||
var/s = contents.len == 1 ? "" : "s"
|
||||
to_chat(user, "<span class='notice'>You can make out the shape[s] of [contents.len] object[s] through the fabric.</span>")
|
||||
|
||||
/obj/item/bodybag/bluespace/Destroy()
|
||||
for(var/atom/movable/A in contents)
|
||||
A.forceMove(get_turf(src))
|
||||
if(isliving(A))
|
||||
to_chat(A, "<span class='notice'>You suddenly feel the space around you torn apart! You're free!</span>")
|
||||
return ..()
|
||||
|
||||
/obj/item/bodybag/bluespace/deploy_bodybag(mob/user, atom/location)
|
||||
var/obj/structure/closet/body_bag/R = new unfoldedbag_path(location)
|
||||
for(var/atom/movable/A in contents)
|
||||
A.forceMove(R)
|
||||
if(isliving(A))
|
||||
to_chat(A, "<span class='notice'>You suddenly feel air around you! You're free!</span>")
|
||||
R.open(user)
|
||||
R.add_fingerprint(user)
|
||||
qdel(src)
|
||||
|
||||
/obj/item/bodybag/bluespace/container_resist(mob/living/user)
|
||||
if(user.incapacitated())
|
||||
to_chat(user, "<span class='warning'>You can't get out while you're restrained like this!</span>")
|
||||
return
|
||||
user.changeNext_move(CLICK_CD_BREAKOUT)
|
||||
user.last_special = world.time + CLICK_CD_BREAKOUT
|
||||
to_chat(user, "<span class='notice'>You claw at the fabric of [src], trying to tear it open...</span>")
|
||||
to_chat(loc, "<span class='warning'>Someone starts trying to break free of [src]!</span>")
|
||||
if(!do_after(user, 200, target = src))
|
||||
to_chat(loc, "<span class='warning'>The pressure subsides. It seems that they've stopped resisting...</span>")
|
||||
return
|
||||
loc.visible_message("<span class='warning'>[user] suddenly appears in front of [loc]!</span>", "<span class='userdanger'>[user] breaks free of [src]!</span>")
|
||||
qdel(src)
|
||||
@@ -0,0 +1,80 @@
|
||||
#define CANDLE_LUMINOSITY 2
|
||||
/obj/item/candle
|
||||
name = "red candle"
|
||||
desc = "In Greek myth, Prometheus stole fire from the Gods and gave it to \
|
||||
humankind. The jewelry he kept for himself."
|
||||
icon = 'icons/obj/candle.dmi'
|
||||
icon_state = "candle1"
|
||||
item_state = "candle1"
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
light_color = LIGHT_COLOR_FIRE
|
||||
heat = 1000
|
||||
var/wax = 1000
|
||||
var/lit = FALSE
|
||||
var/infinite = FALSE
|
||||
var/start_lit = FALSE
|
||||
|
||||
/obj/item/candle/Initialize()
|
||||
. = ..()
|
||||
if(start_lit)
|
||||
light()
|
||||
|
||||
/obj/item/candle/update_icon()
|
||||
icon_state = "candle[(wax > 400) ? ((wax > 750) ? 1 : 2) : 3][lit ? "_lit" : ""]"
|
||||
|
||||
/obj/item/candle/attackby(obj/item/W, mob/user, params)
|
||||
var/msg = W.ignition_effect(src, user)
|
||||
if(msg)
|
||||
light(msg)
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/candle/fire_act(exposed_temperature, exposed_volume)
|
||||
if(!lit)
|
||||
light() //honk
|
||||
return ..()
|
||||
|
||||
/obj/item/candle/is_hot()
|
||||
return lit * heat
|
||||
|
||||
/obj/item/candle/proc/light(show_message)
|
||||
if(!lit)
|
||||
lit = TRUE
|
||||
if(show_message)
|
||||
usr.visible_message(show_message)
|
||||
set_light(CANDLE_LUMINOSITY)
|
||||
START_PROCESSING(SSobj, src)
|
||||
update_icon()
|
||||
|
||||
/obj/item/candle/proc/put_out_candle()
|
||||
if(!lit)
|
||||
return
|
||||
lit = FALSE
|
||||
update_icon()
|
||||
set_light(0)
|
||||
return TRUE
|
||||
|
||||
/obj/item/candle/extinguish()
|
||||
put_out_candle()
|
||||
return ..()
|
||||
|
||||
/obj/item/candle/process()
|
||||
if(!lit)
|
||||
return PROCESS_KILL
|
||||
if(!infinite)
|
||||
wax--
|
||||
if(!wax)
|
||||
new /obj/item/trash/candle(loc)
|
||||
qdel(src)
|
||||
update_icon()
|
||||
open_flame()
|
||||
|
||||
/obj/item/candle/attack_self(mob/user)
|
||||
if(put_out_candle())
|
||||
user.visible_message("<span class='notice'>[user] snuffs [src].</span>")
|
||||
|
||||
/obj/item/candle/infinite
|
||||
infinite = TRUE
|
||||
start_lit = TRUE
|
||||
|
||||
#undef CANDLE_LUMINOSITY
|
||||
@@ -0,0 +1,188 @@
|
||||
//Cardboard cutouts! They're man-shaped and can be colored with a crayon to look like a human in a certain outfit, although it's limited, discolored, and obvious to more than a cursory glance.
|
||||
/obj/item/cardboard_cutout
|
||||
name = "cardboard cutout"
|
||||
desc = "A vaguely humanoid cardboard cutout. It's completely blank."
|
||||
icon = 'icons/obj/cardboard_cutout.dmi'
|
||||
icon_state = "cutout_basic"
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
resistance_flags = FLAMMABLE
|
||||
// Possible restyles for the cutout;
|
||||
// add an entry in change_appearance() if you add to here
|
||||
var/list/possible_appearances = list("Assistant", "Clown", "Mime",
|
||||
"Traitor", "Nuke Op", "Cultist", "Clockwork Cultist",
|
||||
"Revolutionary", "Wizard", "Shadowling", "Xenomorph", "Xenomorph Maid", "Swarmer",
|
||||
"Ash Walker", "Deathsquad Officer", "Ian", "Slaughter Demon",
|
||||
"Laughter Demon", "Private Security Officer")
|
||||
var/pushed_over = FALSE //If the cutout is pushed over and has to be righted
|
||||
var/deceptive = FALSE //If the cutout actually appears as what it portray and not a discolored version
|
||||
|
||||
var/lastattacker = null
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/obj/item/cardboard_cutout/attack_hand(mob/living/user)
|
||||
if(user.a_intent == INTENT_HELP || pushed_over)
|
||||
return ..()
|
||||
user.visible_message("<span class='warning'>[user] pushes over [src]!</span>", "<span class='danger'>You push over [src]!</span>")
|
||||
playsound(src, 'sound/weapons/genhit.ogg', 50, 1)
|
||||
push_over()
|
||||
|
||||
/obj/item/cardboard_cutout/proc/push_over()
|
||||
name = initial(name)
|
||||
desc = "[initial(desc)] It's been pushed over."
|
||||
icon = initial(icon)
|
||||
icon_state = "cutout_pushed_over"
|
||||
remove_atom_colour(FIXED_COLOUR_PRIORITY)
|
||||
alpha = initial(alpha)
|
||||
pushed_over = TRUE
|
||||
|
||||
/obj/item/cardboard_cutout/attack_self(mob/living/user)
|
||||
if(!pushed_over)
|
||||
return
|
||||
to_chat(user, "<span class='notice'>You right [src].</span>")
|
||||
desc = initial(desc)
|
||||
icon = initial(icon)
|
||||
icon_state = initial(icon_state) //This resets a cutout to its blank state - this is intentional to allow for resetting
|
||||
pushed_over = FALSE
|
||||
|
||||
/obj/item/cardboard_cutout/attackby(obj/item/I, mob/living/user, params)
|
||||
if(istype(I, /obj/item/toy/crayon))
|
||||
change_appearance(I, user)
|
||||
return
|
||||
// Why yes, this does closely resemble mob and object attack code.
|
||||
if(I.item_flags & NOBLUDGEON)
|
||||
return
|
||||
if(!I.force)
|
||||
playsound(loc, 'sound/weapons/tap.ogg', get_clamped_volume(), 1, -1)
|
||||
else if(I.hitsound)
|
||||
playsound(loc, I.hitsound, get_clamped_volume(), 1, -1)
|
||||
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
user.do_attack_animation(src)
|
||||
|
||||
if(I.force)
|
||||
user.visible_message("<span class='danger'>[user] has hit \
|
||||
[src] with [I]!</span>", "<span class='danger'>You hit [src] \
|
||||
with [I]!</span>")
|
||||
|
||||
if(prob(I.force))
|
||||
push_over()
|
||||
|
||||
/obj/item/cardboard_cutout/bullet_act(obj/item/projectile/P)
|
||||
if(istype(P, /obj/item/projectile/bullet/reusable))
|
||||
P.on_hit(src, 0)
|
||||
visible_message("<span class='danger'>[src] has been hit by [P]!</span>")
|
||||
playsound(src, 'sound/weapons/slice.ogg', 50, 1)
|
||||
if(prob(P.damage))
|
||||
push_over()
|
||||
|
||||
/obj/item/cardboard_cutout/proc/change_appearance(obj/item/toy/crayon/crayon, mob/living/user)
|
||||
if(!crayon || !user)
|
||||
return
|
||||
if(pushed_over)
|
||||
to_chat(user, "<span class='warning'>Right [src] first!</span>")
|
||||
return
|
||||
if(crayon.check_empty(user))
|
||||
return
|
||||
if(crayon.is_capped)
|
||||
to_chat(user, "<span class='warning'>Take the cap off first!</span>")
|
||||
return
|
||||
var/new_appearance = input(user, "Choose a new appearance for [src].", "26th Century Deception") as null|anything in possible_appearances
|
||||
if(!new_appearance || !crayon || !user.canUseTopic(src))
|
||||
return
|
||||
if(!do_after(user, 10, FALSE, src, TRUE))
|
||||
return
|
||||
user.visible_message("<span class='notice'>[user] gives [src] a new look.</span>", "<span class='notice'>Voila! You give [src] a new look.</span>")
|
||||
crayon.use_charges(1)
|
||||
crayon.check_empty(user)
|
||||
alpha = 255
|
||||
icon = initial(icon)
|
||||
if(!deceptive)
|
||||
add_atom_colour("#FFD7A7", FIXED_COLOUR_PRIORITY)
|
||||
switch(new_appearance)
|
||||
if("Assistant")
|
||||
name = "[pick(GLOB.first_names_male)] [pick(GLOB.last_names)]"
|
||||
desc = "A cardboat cutout of an assistant."
|
||||
icon_state = "cutout_greytide"
|
||||
if("Clown")
|
||||
name = pick(GLOB.clown_names)
|
||||
desc = "A cardboard cutout of a clown. You get the feeling that it should be in a corner."
|
||||
icon_state = "cutout_clown"
|
||||
if("Mime")
|
||||
name = pick(GLOB.mime_names)
|
||||
desc = "...(A cardboard cutout of a mime.)"
|
||||
icon_state = "cutout_mime"
|
||||
if("Traitor")
|
||||
name = "[pick("Unknown", "Captain")]"
|
||||
desc = "A cardboard cutout of a traitor."
|
||||
icon_state = "cutout_traitor"
|
||||
if("Nuke Op")
|
||||
name = "[pick("Unknown", "COMMS", "Telecomms", "AI", "stealthy op", "STEALTH", "sneakybeaky", "MEDIC", "Medic")]"
|
||||
desc = "A cardboard cutout of a nuclear operative."
|
||||
icon_state = "cutout_fluke"
|
||||
if("Cultist")
|
||||
name = "Unknown"
|
||||
desc = "A cardboard cutout of a cultist."
|
||||
icon_state = "cutout_cultist"
|
||||
if("Clockwork Cultist")
|
||||
name = "[pick(GLOB.first_names_male)] [pick(GLOB.last_names)]"
|
||||
desc = "A cardboard cutout of a servant of Ratvar."
|
||||
icon_state = "cutout_servant"
|
||||
if("Revolutionary")
|
||||
name = "Unknown"
|
||||
desc = "A cardboard cutout of a revolutionary."
|
||||
icon_state = "cutout_viva"
|
||||
if("Wizard")
|
||||
name = "[pick(GLOB.wizard_first)], [pick(GLOB.wizard_second)]"
|
||||
desc = "A cardboard cutout of a wizard."
|
||||
icon_state = "cutout_wizard"
|
||||
if("Shadowling")
|
||||
name = "Unknown"
|
||||
desc = "A cardboard cutout of a shadowling."
|
||||
icon_state = "cutout_shadowling"
|
||||
if("Xenomorph")
|
||||
name = "alien hunter ([rand(1, 999)])"
|
||||
desc = "A cardboard cutout of a xenomorph."
|
||||
icon_state = "cutout_fukken_xeno"
|
||||
if(prob(25))
|
||||
alpha = 75 //Spooky sneaking!
|
||||
if("Xenomorph Maid")
|
||||
name = "lusty xenomorph maid ([rand(1, 999)])"
|
||||
desc = "A cardboard cutout of a xenomorph maid."
|
||||
icon_state = "cutout_lusty"
|
||||
if("Swarmer")
|
||||
name = "Swarmer ([rand(1, 999)])"
|
||||
desc = "A cardboard cutout of a swarmer."
|
||||
icon_state = "cutout_swarmer"
|
||||
if("Ash Walker")
|
||||
name = lizard_name(pick(MALE, FEMALE))
|
||||
desc = "A cardboard cutout of an ash walker."
|
||||
icon_state = "cutout_free_antag"
|
||||
if("Deathsquad Officer")
|
||||
name = pick(GLOB.commando_names)
|
||||
desc = "A cardboard cutout of a death commando."
|
||||
icon_state = "cutout_deathsquad"
|
||||
if("Ian")
|
||||
name = "Ian"
|
||||
desc = "A cardboard cutout of the HoP's beloved corgi."
|
||||
icon_state = "cutout_ian"
|
||||
if("Slaughter Demon")
|
||||
name = "slaughter demon"
|
||||
desc = "A cardboard cutout of a slaughter demon."
|
||||
icon = 'icons/mob/mob.dmi'
|
||||
icon_state = "daemon"
|
||||
if("Laughter Demon")
|
||||
name = "laughter demon"
|
||||
desc = "A cardboard cutout of a laughter demon."
|
||||
icon = 'icons/mob/mob.dmi'
|
||||
icon_state = "bowmon"
|
||||
if("Private Security Officer")
|
||||
name = "Private Security Officer"
|
||||
desc = "A cardboard cutout of a private security officer."
|
||||
icon_state = "cutout_ntsec"
|
||||
return 1
|
||||
|
||||
/obj/item/cardboard_cutout/setDir(newdir)
|
||||
dir = SOUTH
|
||||
|
||||
/obj/item/cardboard_cutout/adaptive //Purchased by Syndicate agents, these cutouts are indistinguishable from normal cutouts but aren't discolored when their appearance is changed
|
||||
deceptive = TRUE
|
||||
@@ -0,0 +1,436 @@
|
||||
/* Cards
|
||||
* Contains:
|
||||
* DATA CARD
|
||||
* ID CARD
|
||||
* FINGERPRINT CARD HOLDER
|
||||
* FINGERPRINT CARD
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* DATA CARDS - Used for the IC data card reader
|
||||
*/
|
||||
/obj/item/card
|
||||
name = "card"
|
||||
desc = "Does card things."
|
||||
icon = 'icons/obj/card.dmi'
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
|
||||
var/list/files = list()
|
||||
|
||||
/obj/item/card/suicide_act(mob/living/carbon/user)
|
||||
user.visible_message("<span class='suicide'>[user] begins to swipe [user.p_their()] neck with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!</span>")
|
||||
return BRUTELOSS
|
||||
|
||||
/obj/item/card/data
|
||||
name = "data card"
|
||||
desc = "A plastic magstripe card for simple and speedy data storage and transfer. This one has a stripe running down the middle."
|
||||
icon_state = "data_1"
|
||||
obj_flags = UNIQUE_RENAME
|
||||
var/function = "storage"
|
||||
var/data = "null"
|
||||
var/special = null
|
||||
item_state = "card-id"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/idcards_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/idcards_righthand.dmi'
|
||||
var/detail_color = COLOR_ASSEMBLY_ORANGE
|
||||
|
||||
/obj/item/card/data/Initialize()
|
||||
.=..()
|
||||
update_icon()
|
||||
|
||||
/obj/item/card/data/update_icon()
|
||||
cut_overlays()
|
||||
if(detail_color == COLOR_FLOORTILE_GRAY)
|
||||
return
|
||||
var/mutable_appearance/detail_overlay = mutable_appearance('icons/obj/card.dmi', "[icon_state]-color")
|
||||
detail_overlay.color = detail_color
|
||||
add_overlay(detail_overlay)
|
||||
|
||||
/obj/item/card/data/attackby(obj/item/I, mob/living/user)
|
||||
if(istype(I, /obj/item/integrated_electronics/detailer))
|
||||
var/obj/item/integrated_electronics/detailer/D = I
|
||||
detail_color = D.detail_color
|
||||
update_icon()
|
||||
return ..()
|
||||
|
||||
/obj/item/proc/GetCard()
|
||||
|
||||
/obj/item/card/data/GetCard()
|
||||
return src
|
||||
|
||||
/obj/item/card/data/full_color
|
||||
desc = "A plastic magstripe card for simple and speedy data storage and transfer. This one has the entire card colored."
|
||||
icon_state = "data_2"
|
||||
|
||||
/obj/item/card/data/disk
|
||||
desc = "A plastic magstripe card for simple and speedy data storage and transfer. This one inexplicibly looks like a floppy disk."
|
||||
icon_state = "data_3"
|
||||
|
||||
/*
|
||||
* ID CARDS
|
||||
*/
|
||||
/obj/item/card/emag
|
||||
desc = "It's a card with a magnetic strip attached to some circuitry."
|
||||
name = "cryptographic sequencer"
|
||||
icon_state = "emag"
|
||||
item_state = "card-id"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/idcards_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/idcards_righthand.dmi'
|
||||
item_flags = NO_MAT_REDEMPTION | NOBLUDGEON
|
||||
var/prox_check = TRUE //If the emag requires you to be in range
|
||||
|
||||
/obj/item/card/emag/bluespace
|
||||
name = "bluespace cryptographic sequencer"
|
||||
desc = "It's a blue card with a magnetic strip attached to some circuitry. It appears to have some sort of transmitter attached to it."
|
||||
color = rgb(40, 130, 255)
|
||||
prox_check = FALSE
|
||||
|
||||
/obj/item/card/emag/attack()
|
||||
return
|
||||
|
||||
/obj/item/card/emag/afterattack(atom/target, mob/user, proximity)
|
||||
. = ..()
|
||||
var/atom/A = target
|
||||
if(!proximity && prox_check)
|
||||
return
|
||||
//Citadel changes: modular code misfiring, so we're bypassing into main code.
|
||||
if(!uses)
|
||||
user.visible_message("<span class='warning'>[src] emits a weak spark. It's burnt out!</span>")
|
||||
playsound(src, 'sound/effects/light_flicker.ogg', 100, 1)
|
||||
return
|
||||
else if(uses <= 3)
|
||||
playsound(src, 'sound/effects/light_flicker.ogg', 30, 1) //Tiiiiiiny warning sound to let ya know your emag's almost dead
|
||||
|
||||
if(isturf(A))
|
||||
return
|
||||
if(istype(A,/obj/item/storage/lockbox) || istype(A, /obj/item/storage/pod))
|
||||
A.emag_act(user)
|
||||
uses = max(uses - 1, 0)
|
||||
if(!uses)
|
||||
user.visible_message("<span class='warning'>[src] fizzles and sparks. It seems like it's out of charges.</span>")
|
||||
playsound(src, 'sound/effects/light_flicker.ogg', 100, 1)
|
||||
if(istype(A,/obj/item/storage))
|
||||
return
|
||||
if(!(isobj(A) || issilicon(A) || isbot(A) || isdrone(A)))
|
||||
return
|
||||
else
|
||||
A.emag_act(user)
|
||||
uses = max(uses - 1, 0)
|
||||
if(!uses)
|
||||
user.visible_message("<span class='warning'>[src] fizzles and sparks. It seems like it's out of charges.</span>")
|
||||
playsound(src, 'sound/effects/light_flicker.ogg', 100, 1)
|
||||
|
||||
|
||||
/obj/item/card/emagfake
|
||||
desc = "It's a card with a magnetic strip attached to some circuitry. Closer inspection shows that this card is a poorly made replica, with a \"DonkCo\" logo stamped on the back."
|
||||
name = "cryptographic sequencer"
|
||||
icon_state = "emag"
|
||||
item_state = "card-id"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/idcards_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/idcards_righthand.dmi'
|
||||
|
||||
/obj/item/card/emagfake/afterattack()
|
||||
. = ..()
|
||||
playsound(src, 'sound/items/bikehorn.ogg', 50, 1)
|
||||
|
||||
/obj/item/card/id
|
||||
name = "identification card"
|
||||
desc = "A card used to provide ID and determine access across the station."
|
||||
icon_state = "id"
|
||||
item_state = "card-id"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/idcards_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/idcards_righthand.dmi'
|
||||
slot_flags = ITEM_SLOT_ID
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 100)
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
var/mining_points = 0 //For redeeming at mining equipment vendors
|
||||
var/list/access = list()
|
||||
var/registered_name = null // The name registered_name on the card
|
||||
var/assignment = null
|
||||
var/access_txt // mapping aid
|
||||
|
||||
|
||||
|
||||
/obj/item/card/id/Initialize(mapload)
|
||||
. = ..()
|
||||
if(mapload && access_txt)
|
||||
access = text2access(access_txt)
|
||||
|
||||
/obj/item/card/id/vv_edit_var(var_name, var_value)
|
||||
. = ..()
|
||||
if(.)
|
||||
switch(var_name)
|
||||
if("assignment","registered_name")
|
||||
update_label()
|
||||
|
||||
/obj/item/card/id/attack_self(mob/user)
|
||||
if(Adjacent(user))
|
||||
user.visible_message("<span class='notice'>[user] shows you: [icon2html(src, viewers(user))] [src.name].</span>", \
|
||||
"<span class='notice'>You show \the [src.name].</span>")
|
||||
add_fingerprint(user)
|
||||
return
|
||||
|
||||
/obj/item/card/id/examine(mob/user)
|
||||
..()
|
||||
if(mining_points)
|
||||
to_chat(user, "There's [mining_points] mining equipment redemption point\s loaded onto this card.")
|
||||
|
||||
/obj/item/card/id/GetAccess()
|
||||
return access
|
||||
|
||||
/obj/item/card/id/GetID()
|
||||
return src
|
||||
|
||||
/*
|
||||
Usage:
|
||||
update_label()
|
||||
Sets the id name to whatever registered_name and assignment is
|
||||
|
||||
update_label("John Doe", "Clowny")
|
||||
Properly formats the name and occupation and sets the id name to the arguments
|
||||
*/
|
||||
/obj/item/card/id/proc/update_label(newname, newjob)
|
||||
if(newname || newjob)
|
||||
name = "[(!newname) ? "identification card" : "[newname]'s ID Card"][(!newjob) ? "" : " ([newjob])"]"
|
||||
return
|
||||
|
||||
name = "[(!registered_name) ? "identification card" : "[registered_name]'s ID Card"][(!assignment) ? "" : " ([assignment])"]"
|
||||
|
||||
/obj/item/card/id/silver
|
||||
name = "silver identification card"
|
||||
desc = "A silver card which shows honour and dedication."
|
||||
icon_state = "silver"
|
||||
item_state = "silver_id"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/idcards_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/idcards_righthand.dmi'
|
||||
|
||||
/obj/item/card/id/silver/reaper
|
||||
name = "Thirteen's ID Card (Reaper)"
|
||||
access = list(ACCESS_MAINT_TUNNELS)
|
||||
assignment = "Reaper"
|
||||
registered_name = "Thirteen"
|
||||
|
||||
/obj/item/card/id/gold
|
||||
name = "gold identification card"
|
||||
desc = "A golden card which shows power and might."
|
||||
icon_state = "gold"
|
||||
item_state = "gold_id"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/idcards_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/idcards_righthand.dmi'
|
||||
|
||||
/obj/item/card/id/syndicate
|
||||
name = "agent card"
|
||||
access = list(ACCESS_MAINT_TUNNELS, ACCESS_SYNDICATE)
|
||||
var/anyone = FALSE //Can anyone forge the ID or just syndicate?
|
||||
|
||||
/obj/item/card/id/syndicate/Initialize()
|
||||
. = ..()
|
||||
var/datum/action/item_action/chameleon/change/chameleon_action = new(src)
|
||||
chameleon_action.chameleon_type = /obj/item/card/id
|
||||
chameleon_action.chameleon_name = "ID Card"
|
||||
chameleon_action.initialize_disguises()
|
||||
|
||||
/obj/item/card/id/syndicate/afterattack(obj/item/O, mob/user, proximity)
|
||||
if(!proximity)
|
||||
return
|
||||
if(istype(O, /obj/item/card/id))
|
||||
var/obj/item/card/id/I = O
|
||||
src.access |= I.access
|
||||
if(isliving(user) && user.mind)
|
||||
if(user.mind.special_role)
|
||||
to_chat(usr, "<span class='notice'>The card's microscanners activate as you pass it over the ID, copying its access.</span>")
|
||||
|
||||
/obj/item/card/id/syndicate/attack_self(mob/user)
|
||||
if(isliving(user) && user.mind)
|
||||
if(user.mind.special_role || anyone)
|
||||
if(alert(user, "Action", "Agent ID", "Show", "Forge") == "Forge")
|
||||
var/t = copytext(sanitize(input(user, "What name would you like to put on this card?", "Agent card name", registered_name ? registered_name : (ishuman(user) ? user.real_name : user.name))as text | null),1,26)
|
||||
if(!t || t == "Unknown" || t == "floor" || t == "wall" || t == "r-wall") //Same as mob/dead/new_player/prefrences.dm
|
||||
if (t)
|
||||
alert("Invalid name.")
|
||||
return
|
||||
registered_name = t
|
||||
|
||||
var/u = copytext(sanitize(input(user, "What occupation would you like to put on this card?\nNote: This will not grant any access levels other than Maintenance.", "Agent card job assignment", "Assistant")as text | null),1,MAX_MESSAGE_LEN)
|
||||
if(!u)
|
||||
registered_name = ""
|
||||
return
|
||||
assignment = u
|
||||
update_label()
|
||||
to_chat(user, "<span class='notice'>You successfully forge the ID card.</span>")
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/item/card/id/syndicate/anyone
|
||||
anyone = TRUE
|
||||
|
||||
/obj/item/card/id/syndicate/nuke_leader
|
||||
name = "lead agent card"
|
||||
access = list(ACCESS_MAINT_TUNNELS, ACCESS_SYNDICATE, ACCESS_SYNDICATE_LEADER)
|
||||
|
||||
/obj/item/card/id/syndicate_command
|
||||
name = "syndicate ID card"
|
||||
desc = "An ID straight from the Syndicate."
|
||||
registered_name = "Syndicate"
|
||||
assignment = "Syndicate Overlord"
|
||||
access = list(ACCESS_SYNDICATE)
|
||||
|
||||
/obj/item/card/id/captains_spare
|
||||
name = "captain's spare ID"
|
||||
desc = "The spare ID of the High Lord himself."
|
||||
icon_state = "gold"
|
||||
item_state = "gold_id"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/idcards_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/idcards_righthand.dmi'
|
||||
registered_name = "Captain"
|
||||
assignment = "Captain"
|
||||
|
||||
/obj/item/card/id/captains_spare/Initialize()
|
||||
var/datum/job/captain/J = new/datum/job/captain
|
||||
access = J.get_access()
|
||||
. = ..()
|
||||
|
||||
/obj/item/card/id/centcom
|
||||
name = "\improper CentCom ID"
|
||||
desc = "An ID straight from Central Command."
|
||||
icon_state = "centcom"
|
||||
registered_name = "Central Command"
|
||||
assignment = "General"
|
||||
|
||||
/obj/item/card/id/centcom/Initialize()
|
||||
access = get_all_centcom_access()
|
||||
. = ..()
|
||||
|
||||
/obj/item/card/id/ert
|
||||
name = "\improper CentCom ID"
|
||||
desc = "An ERT ID card."
|
||||
icon_state = "centcom"
|
||||
registered_name = "Emergency Response Team Commander"
|
||||
assignment = "Emergency Response Team Commander"
|
||||
|
||||
/obj/item/card/id/ert/Initialize()
|
||||
access = get_all_accesses()+get_ert_access("commander")-ACCESS_CHANGE_IDS
|
||||
. = ..()
|
||||
|
||||
/obj/item/card/id/ert/Security
|
||||
registered_name = "Security Response Officer"
|
||||
assignment = "Security Response Officer"
|
||||
|
||||
/obj/item/card/id/ert/Security/Initialize()
|
||||
access = get_all_accesses()+get_ert_access("sec")-ACCESS_CHANGE_IDS
|
||||
. = ..()
|
||||
|
||||
/obj/item/card/id/ert/Engineer
|
||||
registered_name = "Engineer Response Officer"
|
||||
assignment = "Engineer Response Officer"
|
||||
|
||||
/obj/item/card/id/ert/Engineer/Initialize()
|
||||
access = get_all_accesses()+get_ert_access("eng")-ACCESS_CHANGE_IDS
|
||||
. = ..()
|
||||
|
||||
/obj/item/card/id/ert/Medical
|
||||
registered_name = "Medical Response Officer"
|
||||
assignment = "Medical Response Officer"
|
||||
|
||||
/obj/item/card/id/ert/Medical/Initialize()
|
||||
access = get_all_accesses()+get_ert_access("med")-ACCESS_CHANGE_IDS
|
||||
. = ..()
|
||||
|
||||
/obj/item/card/id/ert/chaplain
|
||||
registered_name = "Religious Response Officer"
|
||||
assignment = "Religious Response Officer"
|
||||
|
||||
/obj/item/card/id/ert/chaplain/Initialize()
|
||||
access = get_all_accesses()+get_ert_access("sec")-ACCESS_CHANGE_IDS
|
||||
. = ..()
|
||||
|
||||
/obj/item/card/id/prisoner
|
||||
name = "prisoner ID card"
|
||||
desc = "You are a number, you are not a free man."
|
||||
icon_state = "orange"
|
||||
item_state = "orange-id"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/idcards_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/idcards_righthand.dmi'
|
||||
assignment = "Prisoner"
|
||||
registered_name = "Scum"
|
||||
var/goal = 0 //How far from freedom?
|
||||
var/points = 0
|
||||
|
||||
/obj/item/card/id/prisoner/attack_self(mob/user)
|
||||
to_chat(usr, "<span class='notice'>You have accumulated [points] out of the [goal] points you need for freedom.</span>")
|
||||
|
||||
/obj/item/card/id/prisoner/one
|
||||
name = "Prisoner #13-001"
|
||||
registered_name = "Prisoner #13-001"
|
||||
|
||||
/obj/item/card/id/prisoner/two
|
||||
name = "Prisoner #13-002"
|
||||
registered_name = "Prisoner #13-002"
|
||||
|
||||
/obj/item/card/id/prisoner/three
|
||||
name = "Prisoner #13-003"
|
||||
registered_name = "Prisoner #13-003"
|
||||
|
||||
/obj/item/card/id/prisoner/four
|
||||
name = "Prisoner #13-004"
|
||||
registered_name = "Prisoner #13-004"
|
||||
|
||||
/obj/item/card/id/prisoner/five
|
||||
name = "Prisoner #13-005"
|
||||
registered_name = "Prisoner #13-005"
|
||||
|
||||
/obj/item/card/id/prisoner/six
|
||||
name = "Prisoner #13-006"
|
||||
registered_name = "Prisoner #13-006"
|
||||
|
||||
/obj/item/card/id/prisoner/seven
|
||||
name = "Prisoner #13-007"
|
||||
registered_name = "Prisoner #13-007"
|
||||
|
||||
/obj/item/card/id/mining
|
||||
name = "mining ID"
|
||||
access = list(ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MAILSORTING, ACCESS_MINERAL_STOREROOM)
|
||||
|
||||
/obj/item/card/id/away
|
||||
name = "a perfectly generic identification card"
|
||||
desc = "A perfectly generic identification card. Looks like it could use some flavor."
|
||||
access = list(ACCESS_AWAY_GENERAL)
|
||||
|
||||
/obj/item/card/id/away/hotel
|
||||
name = "Staff ID"
|
||||
desc = "A staff ID used to access the hotel's doors."
|
||||
access = list(ACCESS_AWAY_GENERAL, ACCESS_AWAY_MAINT)
|
||||
|
||||
/obj/item/card/id/away/hotel/securty
|
||||
name = "Officer ID"
|
||||
access = list(ACCESS_AWAY_GENERAL, ACCESS_AWAY_MAINT, ACCESS_AWAY_SEC)
|
||||
|
||||
/obj/item/card/id/away/old
|
||||
name = "a perfectly generic identification card"
|
||||
desc = "A perfectly generic identification card. Looks like it could use some flavor."
|
||||
icon_state = "centcom"
|
||||
|
||||
/obj/item/card/id/away/old/sec
|
||||
name = "Charlie Station Security Officer's ID card"
|
||||
desc = "A faded Charlie Station ID card. You can make out the rank \"Security Officer\"."
|
||||
assignment = "Charlie Station Security Officer"
|
||||
access = list(ACCESS_AWAY_GENERAL, ACCESS_AWAY_SEC)
|
||||
|
||||
/obj/item/card/id/away/old/sci
|
||||
name = "Charlie Station Scientist's ID card"
|
||||
desc = "A faded Charlie Station ID card. You can make out the rank \"Scientist\"."
|
||||
assignment = "Charlie Station Scientist"
|
||||
access = list(ACCESS_AWAY_GENERAL)
|
||||
|
||||
/obj/item/card/id/away/old/eng
|
||||
name = "Charlie Station Engineer's ID card"
|
||||
desc = "A faded Charlie Station ID card. You can make out the rank \"Station Engineer\"."
|
||||
assignment = "Charlie Station Engineer"
|
||||
access = list(ACCESS_AWAY_GENERAL, ACCESS_AWAY_ENGINE)
|
||||
|
||||
/obj/item/card/id/away/old/apc
|
||||
name = "APC Access ID"
|
||||
desc = "A special ID card that allows access to APC terminals."
|
||||
access = list(ACCESS_ENGINE_EQUIP)
|
||||
@@ -0,0 +1,119 @@
|
||||
#define STATION_RENAME_TIME_LIMIT 3000
|
||||
|
||||
/obj/item/station_charter
|
||||
name = "station charter"
|
||||
icon = 'icons/obj/wizard.dmi'
|
||||
icon_state = "scroll2"
|
||||
desc = "An official document entrusting the governance of the station \
|
||||
and surrounding space to the Captain."
|
||||
var/used = FALSE
|
||||
var/name_type = "station"
|
||||
|
||||
var/unlimited_uses = FALSE
|
||||
var/ignores_timeout = FALSE
|
||||
var/response_timer_id = null
|
||||
var/approval_time = 600
|
||||
|
||||
var/static/regex/standard_station_regex
|
||||
|
||||
/obj/item/station_charter/Initialize()
|
||||
. = ..()
|
||||
if(!standard_station_regex)
|
||||
var/prefixes = jointext(GLOB.station_prefixes, "|")
|
||||
var/names = jointext(GLOB.station_names, "|")
|
||||
var/suffixes = jointext(GLOB.station_suffixes, "|")
|
||||
var/numerals = jointext(GLOB.station_numerals, "|")
|
||||
var/regexstr = "^(([prefixes]) )?(([names]) ?)([suffixes]) ([numerals])$"
|
||||
standard_station_regex = new(regexstr)
|
||||
|
||||
/obj/item/station_charter/attack_self(mob/living/user)
|
||||
if(used)
|
||||
to_chat(user, "The [name_type] has already been named.")
|
||||
return
|
||||
if(!ignores_timeout && (world.time-SSticker.round_start_time > STATION_RENAME_TIME_LIMIT)) //5 minutes
|
||||
to_chat(user, "The crew has already settled into the shift. It probably wouldn't be good to rename the [name_type] right now.")
|
||||
return
|
||||
if(response_timer_id)
|
||||
to_chat(user, "You're still waiting for approval from your employers about your proposed name change, it'd be best to wait for now.")
|
||||
return
|
||||
|
||||
var/new_name = html_decode(stripped_input(user, message="What do you want to name \
|
||||
[station_name()]? Keep in mind particularly terrible names may be \
|
||||
rejected by your employers, while names using the standard format, \
|
||||
will automatically be accepted.", max_length=MAX_CHARTER_LEN))
|
||||
|
||||
if(response_timer_id)
|
||||
to_chat(user, "You're still waiting for approval from your employers about your proposed name change, it'd be best to wait for now.")
|
||||
return
|
||||
|
||||
if(!new_name)
|
||||
return
|
||||
log_game("[key_name(user)] has proposed to name the station as \
|
||||
[new_name]")
|
||||
|
||||
if(standard_station_regex.Find(new_name))
|
||||
to_chat(user, "Your name has been automatically approved.")
|
||||
rename_station(new_name, user.name, user.real_name, key_name(user))
|
||||
return
|
||||
|
||||
to_chat(user, "Your name has been sent to your employers for approval.")
|
||||
// Autoapproves after a certain time
|
||||
response_timer_id = addtimer(CALLBACK(src, .proc/rename_station, new_name, user.name, user.real_name, key_name(user)), approval_time, TIMER_STOPPABLE)
|
||||
to_chat(GLOB.admins, "<span class='adminnotice'><b><font color=orange>CUSTOM STATION RENAME:</font></b>[ADMIN_LOOKUPFLW(user)] proposes to rename the [name_type] to [new_name] (will autoapprove in [DisplayTimeText(approval_time)]). [ADMIN_SMITE(user)] (<A HREF='?_src_=holder;[HrefToken(TRUE)];reject_custom_name=[REF(src)]'>REJECT</A>) [ADMIN_CENTCOM_REPLY(user)]</span>")
|
||||
|
||||
/obj/item/station_charter/proc/reject_proposed(user)
|
||||
if(!user)
|
||||
return
|
||||
if(!response_timer_id)
|
||||
return
|
||||
var/turf/T = get_turf(src)
|
||||
T.visible_message("<span class='warning'>The proposed changes disappear \
|
||||
from [src]; it looks like they've been rejected.</span>")
|
||||
var/m = "[key_name(user)] has rejected the proposed station name."
|
||||
|
||||
message_admins(m)
|
||||
log_admin(m)
|
||||
|
||||
deltimer(response_timer_id)
|
||||
response_timer_id = null
|
||||
|
||||
/obj/item/station_charter/proc/rename_station(designation, uname, ureal_name, ukey)
|
||||
set_station_name(designation)
|
||||
minor_announce("[ureal_name] has designated your station as [station_name()]", "Captain's Charter", 0)
|
||||
log_game("[ukey] has renamed the station as [station_name()].")
|
||||
|
||||
name = "station charter for [station_name()]"
|
||||
desc = "An official document entrusting the governance of \
|
||||
[station_name()] and surrounding space to Captain [uname]."
|
||||
SSblackbox.record_feedback("text", "station_renames", 1, "[station_name()]")
|
||||
if(!unlimited_uses)
|
||||
used = TRUE
|
||||
|
||||
/obj/item/station_charter/admin
|
||||
unlimited_uses = TRUE
|
||||
ignores_timeout = TRUE
|
||||
|
||||
|
||||
/obj/item/station_charter/flag
|
||||
name = "nanotrasen banner"
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
name_type = "planet"
|
||||
icon_state = "banner"
|
||||
item_state = "banner"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/banners_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/banners_righthand.dmi'
|
||||
desc = "A cunning device used to claim ownership of planets."
|
||||
w_class = 5
|
||||
force = 15
|
||||
|
||||
/obj/item/station_charter/flag/rename_station(designation, uname, ureal_name, ukey)
|
||||
set_station_name(designation)
|
||||
minor_announce("[ureal_name] has designated the planet as [station_name()]", "Captain's Banner", 0)
|
||||
log_game("[ukey] has renamed the planet as [station_name()].")
|
||||
name = "banner of [station_name()]"
|
||||
desc = "The banner bears the official coat of arms of Nanotrasen, signifying that [station_name()] has been claimed by Captain [uname] in the name of the company."
|
||||
SSblackbox.record_feedback("text", "station_renames", 1, "[station_name()]")
|
||||
if(!unlimited_uses)
|
||||
used = TRUE
|
||||
|
||||
#undef STATION_RENAME_TIME_LIMIT
|
||||
@@ -0,0 +1,274 @@
|
||||
#define CHRONO_BEAM_RANGE 3
|
||||
#define CHRONO_FRAME_COUNT 22
|
||||
/obj/item/chrono_eraser
|
||||
name = "Timestream Eradication Device"
|
||||
desc = "The result of outlawed time-bluespace research, this device is capable of wiping a being from the timestream. They never are, they never were, they never will be."
|
||||
icon = 'icons/obj/chronos.dmi'
|
||||
icon_state = "chronobackpack"
|
||||
item_state = "backpack"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/backpack_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/backpack_righthand.dmi'
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
slot_flags = ITEM_SLOT_BACK
|
||||
slowdown = 1
|
||||
actions_types = list(/datum/action/item_action/equip_unequip_TED_Gun)
|
||||
var/obj/item/gun/energy/chrono_gun/PA = null
|
||||
var/list/erased_minds = list() //a collection of minds from the dead
|
||||
|
||||
/obj/item/chrono_eraser/proc/pass_mind(datum/mind/M)
|
||||
erased_minds += M
|
||||
|
||||
/obj/item/chrono_eraser/dropped()
|
||||
..()
|
||||
if(PA)
|
||||
qdel(PA)
|
||||
|
||||
/obj/item/chrono_eraser/Destroy()
|
||||
dropped()
|
||||
return ..()
|
||||
|
||||
/obj/item/chrono_eraser/ui_action_click(mob/user)
|
||||
if(iscarbon(user))
|
||||
var/mob/living/carbon/C = user
|
||||
if(C.back == src)
|
||||
if(PA)
|
||||
qdel(PA)
|
||||
else
|
||||
PA = new(src)
|
||||
user.put_in_hands(PA)
|
||||
|
||||
/obj/item/chrono_eraser/item_action_slot_check(slot, mob/user)
|
||||
if(slot == SLOT_BACK)
|
||||
return 1
|
||||
|
||||
/obj/item/gun/energy/chrono_gun
|
||||
name = "T.E.D. Projection Apparatus"
|
||||
desc = "It's as if they never existed in the first place."
|
||||
icon = 'icons/obj/chronos.dmi'
|
||||
icon_state = "chronogun"
|
||||
item_state = "chronogun"
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
item_flags = DROPDEL
|
||||
ammo_type = list(/obj/item/ammo_casing/energy/chrono_beam)
|
||||
can_charge = 0
|
||||
fire_delay = 50
|
||||
var/obj/item/chrono_eraser/TED = null
|
||||
var/obj/effect/chrono_field/field = null
|
||||
var/turf/startpos = null
|
||||
|
||||
/obj/item/gun/energy/chrono_gun/Initialize()
|
||||
. = ..()
|
||||
ADD_TRAIT(src, TRAIT_NODROP, CHRONO_GUN_TRAIT)
|
||||
if(istype(loc, /obj/item/chrono_eraser))
|
||||
TED = loc
|
||||
else //admin must have spawned it
|
||||
TED = new(src.loc)
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
/obj/item/gun/energy/chrono_gun/update_icon()
|
||||
return
|
||||
|
||||
/obj/item/gun/energy/chrono_gun/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
|
||||
if(field)
|
||||
field_disconnect(field)
|
||||
..()
|
||||
|
||||
/obj/item/gun/energy/chrono_gun/Destroy()
|
||||
if(TED)
|
||||
TED.PA = null
|
||||
TED = null
|
||||
if(field)
|
||||
field_disconnect(field)
|
||||
return ..()
|
||||
|
||||
/obj/item/gun/energy/chrono_gun/proc/field_connect(obj/effect/chrono_field/F)
|
||||
var/mob/living/user = src.loc
|
||||
if(F.gun)
|
||||
if(isliving(user) && F.captured)
|
||||
to_chat(user, "<span class='alert'><b>FAIL: <i>[F.captured]</i> already has an existing connection.</b></span>")
|
||||
src.field_disconnect(F)
|
||||
else
|
||||
startpos = get_turf(src)
|
||||
field = F
|
||||
F.gun = src
|
||||
if(isliving(user) && F.captured)
|
||||
to_chat(user, "<span class='notice'>Connection established with target: <b>[F.captured]</b></span>")
|
||||
|
||||
|
||||
/obj/item/gun/energy/chrono_gun/proc/field_disconnect(obj/effect/chrono_field/F)
|
||||
if(F && field == F)
|
||||
var/mob/living/user = src.loc
|
||||
if(F.gun == src)
|
||||
F.gun = null
|
||||
if(isliving(user) && F.captured)
|
||||
to_chat(user, "<span class='alert'>Disconnected from target: <b>[F.captured]</b></span>")
|
||||
field = null
|
||||
startpos = null
|
||||
|
||||
/obj/item/gun/energy/chrono_gun/proc/field_check(obj/effect/chrono_field/F)
|
||||
if(F)
|
||||
if(field == F)
|
||||
var/turf/currentpos = get_turf(src)
|
||||
var/mob/living/user = src.loc
|
||||
if((currentpos == startpos) && (field in view(CHRONO_BEAM_RANGE, currentpos)) && !user.lying && (user.stat == CONSCIOUS))
|
||||
return 1
|
||||
field_disconnect(F)
|
||||
return 0
|
||||
|
||||
/obj/item/gun/energy/chrono_gun/proc/pass_mind(datum/mind/M)
|
||||
if(TED)
|
||||
TED.pass_mind(M)
|
||||
|
||||
|
||||
/obj/item/projectile/energy/chrono_beam
|
||||
name = "eradication beam"
|
||||
icon_state = "chronobolt"
|
||||
range = CHRONO_BEAM_RANGE
|
||||
nodamage = 1
|
||||
var/obj/item/gun/energy/chrono_gun/gun = null
|
||||
|
||||
/obj/item/projectile/energy/chrono_beam/Initialize()
|
||||
. = ..()
|
||||
var/obj/item/ammo_casing/energy/chrono_beam/C = loc
|
||||
if(istype(C))
|
||||
gun = C.gun
|
||||
|
||||
/obj/item/projectile/energy/chrono_beam/on_hit(atom/target)
|
||||
if(target && gun && isliving(target))
|
||||
var/obj/effect/chrono_field/F = new(target.loc, target, gun)
|
||||
gun.field_connect(F)
|
||||
|
||||
|
||||
/obj/item/ammo_casing/energy/chrono_beam
|
||||
name = "eradication beam"
|
||||
projectile_type = /obj/item/projectile/energy/chrono_beam
|
||||
icon_state = "chronobolt"
|
||||
e_cost = 0
|
||||
var/obj/item/gun/energy/chrono_gun/gun
|
||||
|
||||
/obj/item/ammo_casing/energy/chrono_beam/Initialize()
|
||||
if(istype(loc))
|
||||
gun = loc
|
||||
. = ..()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/obj/effect/chrono_field
|
||||
name = "eradication field"
|
||||
desc = "An aura of time-bluespace energy."
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
icon_state = "chronofield"
|
||||
density = FALSE
|
||||
anchored = TRUE
|
||||
blend_mode = BLEND_MULTIPLY
|
||||
var/mob/living/captured = null
|
||||
var/obj/item/gun/energy/chrono_gun/gun = null
|
||||
var/tickstokill = 15
|
||||
var/mutable_appearance/mob_underlay
|
||||
var/preloaded = 0
|
||||
var/RPpos = null
|
||||
|
||||
/obj/effect/chrono_field/New(loc, var/mob/living/target, var/obj/item/gun/energy/chrono_gun/G)
|
||||
if(target && isliving(target) && G)
|
||||
target.forceMove(src)
|
||||
src.captured = target
|
||||
var/icon/mob_snapshot = getFlatIcon(target)
|
||||
var/icon/cached_icon = new()
|
||||
|
||||
for(var/i=1, i<=CHRONO_FRAME_COUNT, i++)
|
||||
var/icon/removing_frame = icon('icons/obj/chronos.dmi', "erasing", SOUTH, i)
|
||||
var/icon/mob_icon = icon(mob_snapshot)
|
||||
mob_icon.Blend(removing_frame, ICON_MULTIPLY)
|
||||
cached_icon.Insert(mob_icon, "frame[i]")
|
||||
|
||||
mob_underlay = mutable_appearance(cached_icon, "frame1")
|
||||
update_icon()
|
||||
|
||||
desc = initial(desc) + "<br><span class='info'>It appears to contain [target.name].</span>"
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/effect/chrono_field/Destroy()
|
||||
if(gun && gun.field_check(src))
|
||||
gun.field_disconnect(src)
|
||||
return ..()
|
||||
|
||||
/obj/effect/chrono_field/update_icon()
|
||||
var/ttk_frame = 1 - (tickstokill / initial(tickstokill))
|
||||
ttk_frame = CLAMP(CEILING(ttk_frame * CHRONO_FRAME_COUNT, 1), 1, CHRONO_FRAME_COUNT)
|
||||
if(ttk_frame != RPpos)
|
||||
RPpos = ttk_frame
|
||||
mob_underlay.icon_state = "frame[RPpos]"
|
||||
underlays = list() //hack: BYOND refuses to update the underlay to match the icon_state otherwise
|
||||
underlays += mob_underlay
|
||||
|
||||
/obj/effect/chrono_field/process()
|
||||
if(captured)
|
||||
if(tickstokill > initial(tickstokill))
|
||||
for(var/atom/movable/AM in contents)
|
||||
AM.forceMove(drop_location())
|
||||
qdel(src)
|
||||
else if(tickstokill <= 0)
|
||||
to_chat(captured, "<span class='boldnotice'>As the last essence of your being is erased from time, you begin to re-experience your most enjoyable memory. You feel happy...</span>")
|
||||
var/mob/dead/observer/ghost = captured.ghostize(1)
|
||||
if(captured.mind)
|
||||
if(ghost)
|
||||
ghost.mind = null
|
||||
if(gun)
|
||||
gun.pass_mind(captured.mind)
|
||||
qdel(captured)
|
||||
qdel(src)
|
||||
else
|
||||
captured.Unconscious(80)
|
||||
if(captured.loc != src)
|
||||
captured.forceMove(src)
|
||||
update_icon()
|
||||
if(gun)
|
||||
if(gun.field_check(src))
|
||||
tickstokill--
|
||||
else
|
||||
gun = null
|
||||
return .()
|
||||
else
|
||||
tickstokill++
|
||||
else
|
||||
qdel(src)
|
||||
|
||||
/obj/effect/chrono_field/bullet_act(obj/item/projectile/P)
|
||||
if(istype(P, /obj/item/projectile/energy/chrono_beam))
|
||||
var/obj/item/projectile/energy/chrono_beam/beam = P
|
||||
var/obj/item/gun/energy/chrono_gun/Pgun = beam.gun
|
||||
if(Pgun && istype(Pgun))
|
||||
Pgun.field_connect(src)
|
||||
else
|
||||
return 0
|
||||
|
||||
/obj/effect/chrono_field/assume_air()
|
||||
return 0
|
||||
|
||||
/obj/effect/chrono_field/return_air() //we always have nominal air and temperature
|
||||
var/datum/gas_mixture/GM = new
|
||||
GM.gases[/datum/gas/oxygen] = MOLES_O2STANDARD
|
||||
GM.gases[/datum/gas/nitrogen] = MOLES_N2STANDARD
|
||||
GM.temperature = T20C
|
||||
return GM
|
||||
|
||||
/obj/effect/chrono_field/Move()
|
||||
return
|
||||
|
||||
/obj/effect/chrono_field/singularity_act()
|
||||
return
|
||||
|
||||
/obj/effect/chrono_field/singularity_pull()
|
||||
return
|
||||
|
||||
/obj/effect/chrono_field/ex_act()
|
||||
return
|
||||
|
||||
/obj/effect/chrono_field/blob_act(obj/structure/blob/B)
|
||||
return
|
||||
|
||||
|
||||
#undef CHRONO_BEAM_RANGE
|
||||
#undef CHRONO_FRAME_COUNT
|
||||
@@ -0,0 +1,863 @@
|
||||
//cleansed 9/15/2012 17:48
|
||||
|
||||
/*
|
||||
CONTAINS:
|
||||
MATCHES
|
||||
CIGARETTES
|
||||
CIGARS
|
||||
SMOKING PIPES
|
||||
CHEAP LIGHTERS
|
||||
ZIPPO
|
||||
|
||||
CIGARETTE PACKETS ARE IN FANCY.DM
|
||||
*/
|
||||
|
||||
///////////
|
||||
//MATCHES//
|
||||
///////////
|
||||
/obj/item/match
|
||||
name = "match"
|
||||
desc = "A simple match stick, used for lighting fine smokables."
|
||||
icon = 'icons/obj/cigarettes.dmi'
|
||||
icon_state = "match_unlit"
|
||||
var/lit = FALSE
|
||||
var/burnt = FALSE
|
||||
var/smoketime = 5
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
heat = 1000
|
||||
grind_results = list("phosphorus" = 2)
|
||||
|
||||
/obj/item/match/process()
|
||||
smoketime--
|
||||
if(smoketime < 1)
|
||||
matchburnout()
|
||||
else
|
||||
open_flame(heat)
|
||||
|
||||
/obj/item/match/fire_act(exposed_temperature, exposed_volume)
|
||||
matchignite()
|
||||
|
||||
/obj/item/match/proc/matchignite()
|
||||
if(!lit && !burnt)
|
||||
lit = TRUE
|
||||
icon_state = "match_lit"
|
||||
damtype = "fire"
|
||||
force = 3
|
||||
hitsound = 'sound/items/welder.ogg'
|
||||
item_state = "cigon"
|
||||
name = "lit match"
|
||||
desc = "A match. This one is lit."
|
||||
attack_verb = list("burnt","singed")
|
||||
START_PROCESSING(SSobj, src)
|
||||
update_icon()
|
||||
|
||||
/obj/item/match/proc/matchburnout()
|
||||
if(lit)
|
||||
lit = FALSE
|
||||
burnt = TRUE
|
||||
damtype = "brute"
|
||||
force = initial(force)
|
||||
icon_state = "match_burnt"
|
||||
item_state = "cigoff"
|
||||
name = "burnt match"
|
||||
desc = "A match. This one has seen better days."
|
||||
attack_verb = list("flicked")
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/match/dropped(mob/user)
|
||||
matchburnout()
|
||||
. = ..()
|
||||
|
||||
/obj/item/match/attack(mob/living/carbon/M, mob/living/carbon/user)
|
||||
if(!isliving(M))
|
||||
return
|
||||
if(lit && M.IgniteMob())
|
||||
message_admins("[ADMIN_LOOKUPFLW(user)] set [key_name_admin(M)] on fire with [src] at [AREACOORD(user)]")
|
||||
log_game("[key_name(user)] set [key_name(M)] on fire with [src] at [AREACOORD(user)]")
|
||||
var/obj/item/clothing/mask/cigarette/cig = help_light_cig(M)
|
||||
if(lit && cig && user.a_intent == INTENT_HELP)
|
||||
if(cig.lit)
|
||||
to_chat(user, "<span class='notice'>[cig] is already lit.</span>")
|
||||
if(M == user)
|
||||
cig.attackby(src, user)
|
||||
else
|
||||
cig.light("<span class='notice'>[user] holds [src] out for [M], and lights [cig].</span>")
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/item/proc/help_light_cig(mob/living/M)
|
||||
var/mask_item = M.get_item_by_slot(SLOT_WEAR_MASK)
|
||||
if(istype(mask_item, /obj/item/clothing/mask/cigarette))
|
||||
return mask_item
|
||||
|
||||
/obj/item/match/is_hot()
|
||||
return lit * heat
|
||||
|
||||
//////////////////
|
||||
//FINE SMOKABLES//
|
||||
//////////////////
|
||||
/obj/item/clothing/mask/cigarette
|
||||
name = "cigarette"
|
||||
desc = "A roll of tobacco and nicotine."
|
||||
icon_state = "cigoff"
|
||||
throw_speed = 0.5
|
||||
item_state = "cigoff"
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
body_parts_covered = null
|
||||
grind_results = list()
|
||||
var/lit = FALSE
|
||||
var/starts_lit = FALSE
|
||||
var/icon_on = "cigon" //Note - these are in masks.dmi not in cigarette.dmi
|
||||
var/icon_off = "cigoff"
|
||||
var/type_butt = /obj/item/cigbutt
|
||||
var/lastHolder = null
|
||||
var/smoketime = 300
|
||||
var/chem_volume = 30
|
||||
var/list/list_reagents = list("nicotine" = 15)
|
||||
heat = 1000
|
||||
|
||||
/obj/item/clothing/mask/cigarette/suicide_act(mob/user)
|
||||
user.visible_message("<span class='suicide'>[user] is huffing [src] as quickly as [user.p_they()] can! It looks like [user.p_theyre()] trying to give [user.p_them()]self cancer.</span>")
|
||||
return (TOXLOSS|OXYLOSS)
|
||||
|
||||
/obj/item/clothing/mask/cigarette/Initialize()
|
||||
. = ..()
|
||||
create_reagents(chem_volume, INJECTABLE | NO_REACT) // so it doesn't react until you light it
|
||||
if(list_reagents)
|
||||
reagents.add_reagent_list(list_reagents)
|
||||
if(starts_lit)
|
||||
light()
|
||||
AddComponent(/datum/component/knockoff,90,list(BODY_ZONE_PRECISE_MOUTH),list(SLOT_WEAR_MASK))//90% to knock off when wearing a mask
|
||||
|
||||
/obj/item/clothing/mask/cigarette/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
. = ..()
|
||||
|
||||
/obj/item/clothing/mask/cigarette/attackby(obj/item/W, mob/user, params)
|
||||
if(!lit && smoketime > 0)
|
||||
var/lighting_text = W.ignition_effect(src, user)
|
||||
if(lighting_text)
|
||||
light(lighting_text)
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/mask/cigarette/afterattack(obj/item/reagent_containers/glass/glass, mob/user, proximity)
|
||||
. = ..()
|
||||
if(!proximity || lit) //can't dip if cigarette is lit (it will heat the reagents in the glass instead)
|
||||
return
|
||||
if(istype(glass)) //you can dip cigarettes into beakers
|
||||
if(glass.reagents.trans_to(src, chem_volume)) //if reagents were transfered, show the message
|
||||
to_chat(user, "<span class='notice'>You dip \the [src] into \the [glass].</span>")
|
||||
else //if not, either the beaker was empty, or the cigarette was full
|
||||
if(!glass.reagents.total_volume)
|
||||
to_chat(user, "<span class='notice'>[glass] is empty.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>[src] is full.</span>")
|
||||
|
||||
|
||||
/obj/item/clothing/mask/cigarette/proc/light(flavor_text = null)
|
||||
if(lit)
|
||||
return
|
||||
if(!(flags_1 & INITIALIZED_1))
|
||||
icon_state = icon_on
|
||||
item_state = icon_on
|
||||
return
|
||||
|
||||
lit = TRUE
|
||||
name = "lit [name]"
|
||||
attack_verb = list("burnt", "singed")
|
||||
hitsound = 'sound/items/welder.ogg'
|
||||
damtype = "fire"
|
||||
force = 4
|
||||
if(reagents.get_reagent_amount("plasma")) // the plasma explodes when exposed to fire
|
||||
var/datum/effect_system/reagents_explosion/e = new()
|
||||
e.set_up(round(reagents.get_reagent_amount("plasma") / 2.5, 1), get_turf(src), 0, 0)
|
||||
e.start()
|
||||
qdel(src)
|
||||
return
|
||||
if(reagents.get_reagent_amount("welding_fuel")) // the fuel explodes, too, but much less violently
|
||||
var/datum/effect_system/reagents_explosion/e = new()
|
||||
e.set_up(round(reagents.get_reagent_amount("welding_fuel") / 5, 1), get_turf(src), 0, 0)
|
||||
e.start()
|
||||
qdel(src)
|
||||
return
|
||||
// allowing reagents to react after being lit
|
||||
DISABLE_BITFIELD(reagents.reagents_holder_flags, NO_REACT)
|
||||
reagents.handle_reactions()
|
||||
icon_state = icon_on
|
||||
item_state = icon_on
|
||||
if(flavor_text)
|
||||
var/turf/T = get_turf(src)
|
||||
T.visible_message(flavor_text)
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
//can't think of any other way to update the overlays :<
|
||||
if(ismob(loc))
|
||||
var/mob/M = loc
|
||||
M.update_inv_wear_mask()
|
||||
M.update_inv_hands()
|
||||
|
||||
|
||||
/obj/item/clothing/mask/cigarette/proc/handle_reagents()
|
||||
if(reagents.total_volume)
|
||||
if(iscarbon(loc))
|
||||
var/mob/living/carbon/C = loc
|
||||
if (src == C.wear_mask) // if it's in the human/monkey mouth, transfer reagents to the mob
|
||||
var/fraction = min(REAGENTS_METABOLISM/reagents.total_volume, 1)
|
||||
reagents.reaction(C, INGEST, fraction)
|
||||
if(!reagents.trans_to(C, REAGENTS_METABOLISM))
|
||||
reagents.remove_any(REAGENTS_METABOLISM)
|
||||
return
|
||||
reagents.remove_any(REAGENTS_METABOLISM)
|
||||
|
||||
|
||||
/obj/item/clothing/mask/cigarette/process()
|
||||
var/turf/location = get_turf(src)
|
||||
var/mob/living/M = loc
|
||||
if(isliving(loc))
|
||||
M.IgniteMob()
|
||||
smoketime--
|
||||
if(smoketime < 1)
|
||||
new type_butt(location)
|
||||
if(ismob(loc))
|
||||
to_chat(M, "<span class='notice'>Your [name] goes out.</span>")
|
||||
qdel(src)
|
||||
return
|
||||
open_flame()
|
||||
if(reagents && reagents.total_volume)
|
||||
handle_reagents()
|
||||
|
||||
/obj/item/clothing/mask/cigarette/attack_self(mob/user)
|
||||
if(lit)
|
||||
user.visible_message("<span class='notice'>[user] calmly drops and treads on \the [src], putting it out instantly.</span>")
|
||||
new type_butt(user.loc)
|
||||
new /obj/effect/decal/cleanable/ash(user.loc)
|
||||
qdel(src)
|
||||
. = ..()
|
||||
|
||||
/obj/item/clothing/mask/cigarette/attack(mob/living/carbon/M, mob/living/carbon/user)
|
||||
if(!istype(M))
|
||||
return ..()
|
||||
if(M.on_fire && !lit)
|
||||
light("<span class='notice'>[user] lights [src] with [M]'s burning body. What a cold-blooded badass.</span>")
|
||||
return
|
||||
var/obj/item/clothing/mask/cigarette/cig = help_light_cig(M)
|
||||
if(lit && cig && user.a_intent == INTENT_HELP)
|
||||
if(cig.lit)
|
||||
to_chat(user, "<span class='notice'>The [cig.name] is already lit.</span>")
|
||||
if(M == user)
|
||||
cig.attackby(src, user)
|
||||
else
|
||||
cig.light("<span class='notice'>[user] holds the [name] out for [M], and lights [M.p_their()] [cig.name].</span>")
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/mask/cigarette/fire_act(exposed_temperature, exposed_volume)
|
||||
light()
|
||||
|
||||
/obj/item/clothing/mask/cigarette/is_hot()
|
||||
return lit * heat
|
||||
|
||||
// Cigarette brands.
|
||||
|
||||
/obj/item/clothing/mask/cigarette/space_cigarette
|
||||
desc = "A Space Cigarette brand cigarette."
|
||||
|
||||
/obj/item/clothing/mask/cigarette/dromedary
|
||||
desc = "A DromedaryCo brand cigarette."
|
||||
|
||||
/obj/item/clothing/mask/cigarette/uplift
|
||||
desc = "An Uplift Smooth brand cigarette."
|
||||
list_reagents = list("nicotine" = 7.5, "menthol" = 7.5)
|
||||
|
||||
/obj/item/clothing/mask/cigarette/robust
|
||||
desc = "A Robust brand cigarette."
|
||||
|
||||
/obj/item/clothing/mask/cigarette/robustgold
|
||||
desc = "A Robust Gold brand cigarette."
|
||||
list_reagents = list("nicotine" = 15, "gold" = 1)
|
||||
|
||||
/obj/item/clothing/mask/cigarette/carp
|
||||
desc = "A Carp Classic brand cigarette."
|
||||
|
||||
/obj/item/clothing/mask/cigarette/syndicate
|
||||
desc = "An unknown brand cigarette."
|
||||
list_reagents = list("nicotine" = 15, "omnizine" = 15)
|
||||
|
||||
/obj/item/clothing/mask/cigarette/shadyjims
|
||||
desc = "A Shady Jim's Super Slims cigarette."
|
||||
list_reagents = list("nicotine" = 15, "lipolicide" = 4, "ammonia" = 2, "plantbgone" = 1, "toxin" = 1.5)
|
||||
|
||||
/obj/item/clothing/mask/cigarette/xeno
|
||||
desc = "A Xeno Filtered brand cigarette."
|
||||
list_reagents = list ("nicotine" = 20, "regen_jelly" = 15, "krokodil" = 4)
|
||||
|
||||
// Rollies.
|
||||
|
||||
/obj/item/clothing/mask/cigarette/rollie
|
||||
name = "rollie"
|
||||
desc = "A roll of dried plant matter wrapped in thin paper."
|
||||
icon_state = "spliffoff"
|
||||
icon_on = "spliffon"
|
||||
icon_off = "spliffoff"
|
||||
type_butt = /obj/item/cigbutt/roach
|
||||
throw_speed = 0.5
|
||||
item_state = "spliffoff"
|
||||
smoketime = 180
|
||||
chem_volume = 50
|
||||
list_reagents = null
|
||||
|
||||
/obj/item/clothing/mask/cigarette/rollie/New()
|
||||
..()
|
||||
src.pixel_x = rand(-5, 5)
|
||||
src.pixel_y = rand(-5, 5)
|
||||
|
||||
/obj/item/clothing/mask/cigarette/rollie/nicotine
|
||||
list_reagents = list("nicotine" = 15)
|
||||
|
||||
/obj/item/clothing/mask/cigarette/rollie/trippy
|
||||
list_reagents = list("nicotine" = 15, "mushroomhallucinogen" = 35)
|
||||
starts_lit = TRUE
|
||||
|
||||
/obj/item/clothing/mask/cigarette/rollie/cannabis
|
||||
list_reagents = list("space_drugs" = 15, "lipolicide" = 35)
|
||||
|
||||
/obj/item/clothing/mask/cigarette/rollie/mindbreaker
|
||||
list_reagents = list("mindbreaker" = 35, "lipolicide" = 15)
|
||||
|
||||
/obj/item/cigbutt/roach
|
||||
name = "roach"
|
||||
desc = "A manky old roach, or for non-stoners, a used rollup."
|
||||
icon_state = "roach"
|
||||
|
||||
/obj/item/cigbutt/roach/New()
|
||||
..()
|
||||
src.pixel_x = rand(-5, 5)
|
||||
src.pixel_y = rand(-5, 5)
|
||||
|
||||
|
||||
////////////
|
||||
// CIGARS //
|
||||
////////////
|
||||
/obj/item/clothing/mask/cigarette/cigar
|
||||
name = "premium cigar"
|
||||
desc = "A brown roll of tobacco and... well, you're not quite sure. This thing's huge!"
|
||||
icon_state = "cigaroff"
|
||||
icon_on = "cigaron"
|
||||
icon_off = "cigaroff" //make sure to add positional sprites in icons/obj/cigarettes.dmi if you add more.
|
||||
type_butt = /obj/item/cigbutt/cigarbutt
|
||||
throw_speed = 0.5
|
||||
item_state = "cigaroff"
|
||||
smoketime = 1500
|
||||
chem_volume = 40
|
||||
|
||||
/obj/item/clothing/mask/cigarette/cigar/cohiba
|
||||
name = "\improper Cohiba Robusto cigar"
|
||||
desc = "There's little more you could want from a cigar."
|
||||
icon_state = "cigar2off"
|
||||
icon_on = "cigar2on"
|
||||
icon_off = "cigar2off"
|
||||
smoketime = 2000
|
||||
chem_volume = 80
|
||||
|
||||
|
||||
/obj/item/clothing/mask/cigarette/cigar/havana
|
||||
name = "premium Havanian cigar"
|
||||
desc = "A cigar fit for only the best of the best."
|
||||
icon_state = "cigar2off"
|
||||
icon_on = "cigar2on"
|
||||
icon_off = "cigar2off"
|
||||
smoketime = 7200
|
||||
chem_volume = 50
|
||||
|
||||
/obj/item/cigbutt
|
||||
name = "cigarette butt"
|
||||
desc = "A manky old cigarette butt."
|
||||
icon = 'icons/obj/clothing/masks.dmi'
|
||||
icon_state = "cigbutt"
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
throwforce = 0
|
||||
grind_results = list("carbon" = 2)
|
||||
|
||||
/obj/item/cigbutt/cigarbutt
|
||||
name = "cigar butt"
|
||||
desc = "A manky old cigar butt."
|
||||
icon_state = "cigarbutt"
|
||||
|
||||
/////////////////
|
||||
//SMOKING PIPES//
|
||||
/////////////////
|
||||
/obj/item/clothing/mask/cigarette/pipe
|
||||
name = "smoking pipe"
|
||||
desc = "A pipe, for smoking. Probably made of meerschaum or something."
|
||||
icon_state = "pipeoff"
|
||||
item_state = "pipeoff"
|
||||
icon_on = "pipeon" //Note - these are in masks.dmi
|
||||
icon_off = "pipeoff"
|
||||
smoketime = 0
|
||||
chem_volume = 100
|
||||
list_reagents = null
|
||||
var/packeditem = 0
|
||||
|
||||
/obj/item/clothing/mask/cigarette/pipe/Initialize()
|
||||
. = ..()
|
||||
name = "empty [initial(name)]"
|
||||
|
||||
/obj/item/clothing/mask/cigarette/pipe/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
. = ..()
|
||||
|
||||
/obj/item/clothing/mask/cigarette/pipe/process()
|
||||
var/turf/location = get_turf(src)
|
||||
smoketime--
|
||||
if(smoketime < 1)
|
||||
new /obj/effect/decal/cleanable/ash(location)
|
||||
if(ismob(loc))
|
||||
var/mob/living/M = loc
|
||||
to_chat(M, "<span class='notice'>Your [name] goes out.</span>")
|
||||
lit = 0
|
||||
icon_state = icon_off
|
||||
item_state = icon_off
|
||||
M.update_inv_wear_mask()
|
||||
packeditem = 0
|
||||
name = "empty [initial(name)]"
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return
|
||||
open_flame()
|
||||
if(reagents && reagents.total_volume) // check if it has any reagents at all
|
||||
handle_reagents()
|
||||
|
||||
|
||||
/obj/item/clothing/mask/cigarette/pipe/attackby(obj/item/O, mob/user, params)
|
||||
if(istype(O, /obj/item/reagent_containers/food/snacks/grown))
|
||||
var/obj/item/reagent_containers/food/snacks/grown/G = O
|
||||
if(!packeditem)
|
||||
if(G.dry == 1)
|
||||
to_chat(user, "<span class='notice'>You stuff [O] into [src].</span>")
|
||||
smoketime = 400
|
||||
packeditem = 1
|
||||
name = "[O.name]-packed [initial(name)]"
|
||||
if(O.reagents)
|
||||
O.reagents.trans_to(src, O.reagents.total_volume)
|
||||
qdel(O)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>It has to be dried first!</span>")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>It is already packed!</span>")
|
||||
else
|
||||
var/lighting_text = O.ignition_effect(src,user)
|
||||
if(lighting_text)
|
||||
if(smoketime > 0)
|
||||
light(lighting_text)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>There is nothing to smoke!</span>")
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/clothing/mask/cigarette/pipe/attack_self(mob/user)
|
||||
var/turf/location = get_turf(user)
|
||||
if(lit)
|
||||
user.visible_message("<span class='notice'>[user] puts out [src].</span>", "<span class='notice'>You put out [src].</span>")
|
||||
lit = 0
|
||||
icon_state = icon_off
|
||||
item_state = icon_off
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return
|
||||
if(!lit && smoketime > 0)
|
||||
to_chat(user, "<span class='notice'>You empty [src] onto [location].</span>")
|
||||
new /obj/effect/decal/cleanable/ash(location)
|
||||
packeditem = 0
|
||||
smoketime = 0
|
||||
reagents.clear_reagents()
|
||||
name = "empty [initial(name)]"
|
||||
return
|
||||
|
||||
/obj/item/clothing/mask/cigarette/pipe/cobpipe
|
||||
name = "corn cob pipe"
|
||||
desc = "A nicotine delivery system popularized by folksy backwoodsmen and kept popular in the modern age and beyond by space hipsters. Can be loaded with objects."
|
||||
icon_state = "cobpipeoff"
|
||||
item_state = "cobpipeoff"
|
||||
icon_on = "cobpipeon" //Note - these are in masks.dmi
|
||||
icon_off = "cobpipeoff"
|
||||
smoketime = 0
|
||||
|
||||
|
||||
/////////
|
||||
//ZIPPO//
|
||||
/////////
|
||||
/obj/item/lighter
|
||||
name = "\improper Zippo lighter"
|
||||
desc = "The zippo."
|
||||
icon = 'icons/obj/cigarettes.dmi'
|
||||
icon_state = "zippo"
|
||||
item_state = "zippo"
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
flags_1 = CONDUCT_1
|
||||
slot_flags = ITEM_SLOT_BELT
|
||||
var/lit = 0
|
||||
var/fancy = TRUE
|
||||
var/overlay_state
|
||||
var/overlay_list = list(
|
||||
"plain",
|
||||
"dame",
|
||||
"thirteen",
|
||||
"snake"
|
||||
)
|
||||
heat = 1500
|
||||
resistance_flags = FIRE_PROOF
|
||||
light_color = LIGHT_COLOR_FIRE
|
||||
grind_results = list("iron" = 1, "welding_fuel" = 5, "oil" = 5)
|
||||
|
||||
/obj/item/lighter/Initialize()
|
||||
. = ..()
|
||||
if(!overlay_state)
|
||||
overlay_state = pick(overlay_list)
|
||||
update_icon()
|
||||
|
||||
/obj/item/lighter/suicide_act(mob/living/carbon/user)
|
||||
if (lit)
|
||||
user.visible_message("<span class='suicide'>[user] begins holding \the [src]'s flame up to [user.p_their()] face! It looks like [user.p_theyre()] trying to commit suicide!</span>")
|
||||
playsound(src, 'sound/items/welder.ogg', 50, 1)
|
||||
return FIRELOSS
|
||||
else
|
||||
user.visible_message("<span class='suicide'>[user] begins whacking [user.p_them()]self with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!</span>")
|
||||
return BRUTELOSS
|
||||
|
||||
/obj/item/lighter/update_icon()
|
||||
cut_overlays()
|
||||
var/mutable_appearance/lighter_overlay = mutable_appearance(icon,"lighter_overlay_[overlay_state][lit ? "-on" : ""]")
|
||||
icon_state = "[initial(icon_state)][lit ? "-on" : ""]"
|
||||
add_overlay(lighter_overlay)
|
||||
|
||||
/obj/item/lighter/ignition_effect(atom/A, mob/user)
|
||||
if(is_hot())
|
||||
. = "<span class='rose'>With a single flick of [user.p_their()] wrist, [user] smoothly lights [A] with [src]. Damn [user.p_theyre()] cool.</span>"
|
||||
|
||||
/obj/item/lighter/proc/set_lit(new_lit)
|
||||
lit = new_lit
|
||||
if(lit)
|
||||
force = 5
|
||||
damtype = "fire"
|
||||
hitsound = 'sound/items/welder.ogg'
|
||||
attack_verb = list("burnt", "singed")
|
||||
set_light(2, 0.6, LIGHT_COLOR_FIRE)
|
||||
START_PROCESSING(SSobj, src)
|
||||
else
|
||||
hitsound = "swing_hit"
|
||||
force = 0
|
||||
attack_verb = null //human_defense.dm takes care of it
|
||||
set_light(0)
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
update_icon()
|
||||
|
||||
/obj/item/lighter/attack_self(mob/living/user)
|
||||
if(user.is_holding(src))
|
||||
if(!lit)
|
||||
set_lit(TRUE)
|
||||
if(fancy)
|
||||
user.visible_message("Without even breaking stride, [user] flips open and lights [src] in one smooth movement.", "<span class='notice'>Without even breaking stride, you flip open and light [src] in one smooth movement.</span>")
|
||||
else
|
||||
var/prot = FALSE
|
||||
var/mob/living/carbon/human/H = user
|
||||
|
||||
if(istype(H) && H.gloves)
|
||||
var/obj/item/clothing/gloves/G = H.gloves
|
||||
if(G.max_heat_protection_temperature)
|
||||
prot = (G.max_heat_protection_temperature > 360)
|
||||
else
|
||||
prot = TRUE
|
||||
|
||||
if(prot || prob(75))
|
||||
user.visible_message("After a few attempts, [user] manages to light [src].", "<span class='notice'>After a few attempts, you manage to light [src].</span>")
|
||||
else
|
||||
var/hitzone = user.held_index_to_dir(user.active_hand_index) == "r" ? BODY_ZONE_PRECISE_R_HAND : BODY_ZONE_PRECISE_L_HAND
|
||||
user.apply_damage(5, BURN, hitzone)
|
||||
user.visible_message("<span class='warning'>After a few attempts, [user] manages to light [src] - however, [user.p_they()] burn [user.p_their()] finger in the process.</span>", "<span class='warning'>You burn yourself while lighting the lighter!</span>")
|
||||
SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "burnt_thumb", /datum/mood_event/burnt_thumb)
|
||||
|
||||
else
|
||||
set_lit(FALSE)
|
||||
if(fancy)
|
||||
user.visible_message("You hear a quiet click, as [user] shuts off [src] without even looking at what [user.p_theyre()] doing. Wow.", "<span class='notice'>You quietly shut off [src] without even looking at what you're doing. Wow.</span>")
|
||||
else
|
||||
user.visible_message("[user] quietly shuts off [src].", "<span class='notice'>You quietly shut off [src].</span>")
|
||||
else
|
||||
. = ..()
|
||||
|
||||
/obj/item/lighter/attack(mob/living/carbon/M, mob/living/carbon/user)
|
||||
if(lit && M.IgniteMob())
|
||||
message_admins("[ADMIN_LOOKUPFLW(user)] set [key_name_admin(M)] on fire with [src] at [AREACOORD(user)]")
|
||||
log_game("[key_name(user)] set [key_name(M)] on fire with [src] at [AREACOORD(user)]")
|
||||
var/obj/item/clothing/mask/cigarette/cig = help_light_cig(M)
|
||||
if(lit && cig && user.a_intent == INTENT_HELP)
|
||||
if(cig.lit)
|
||||
to_chat(user, "<span class='notice'>The [cig.name] is already lit.</span>")
|
||||
if(M == user)
|
||||
cig.attackby(src, user)
|
||||
else
|
||||
if(fancy)
|
||||
cig.light("<span class='rose'>[user] whips the [name] out and holds it for [M]. [user.p_their(TRUE)] arm is as steady as the unflickering flame [user.p_they()] light[user.p_s()] \the [cig] with.</span>")
|
||||
else
|
||||
cig.light("<span class='notice'>[user] holds the [name] out for [M], and lights [M.p_their()] [cig.name].</span>")
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/item/lighter/process()
|
||||
open_flame()
|
||||
|
||||
/obj/item/lighter/is_hot()
|
||||
return lit * heat
|
||||
|
||||
|
||||
/obj/item/lighter/greyscale
|
||||
name = "cheap lighter"
|
||||
desc = "A cheap-as-free lighter."
|
||||
icon_state = "lighter"
|
||||
fancy = FALSE
|
||||
overlay_list = list(
|
||||
"transp",
|
||||
"tall",
|
||||
"matte",
|
||||
"zoppo" //u cant stoppo th zoppo
|
||||
)
|
||||
var/lighter_color
|
||||
var/list/color_list = list( //Same 16 color selection as electronic assemblies
|
||||
COLOR_ASSEMBLY_BLACK,
|
||||
COLOR_FLOORTILE_GRAY,
|
||||
COLOR_ASSEMBLY_BGRAY,
|
||||
COLOR_ASSEMBLY_WHITE,
|
||||
COLOR_ASSEMBLY_RED,
|
||||
COLOR_ASSEMBLY_ORANGE,
|
||||
COLOR_ASSEMBLY_BEIGE,
|
||||
COLOR_ASSEMBLY_BROWN,
|
||||
COLOR_ASSEMBLY_GOLD,
|
||||
COLOR_ASSEMBLY_YELLOW,
|
||||
COLOR_ASSEMBLY_GURKHA,
|
||||
COLOR_ASSEMBLY_LGREEN,
|
||||
COLOR_ASSEMBLY_GREEN,
|
||||
COLOR_ASSEMBLY_LBLUE,
|
||||
COLOR_ASSEMBLY_BLUE,
|
||||
COLOR_ASSEMBLY_PURPLE
|
||||
)
|
||||
|
||||
/obj/item/lighter/greyscale/Initialize()
|
||||
. = ..()
|
||||
if(!lighter_color)
|
||||
lighter_color = pick(color_list)
|
||||
update_icon()
|
||||
|
||||
/obj/item/lighter/greyscale/update_icon()
|
||||
cut_overlays()
|
||||
var/mutable_appearance/lighter_overlay = mutable_appearance(icon,"lighter_overlay_[overlay_state][lit ? "-on" : ""]")
|
||||
icon_state = "[initial(icon_state)][lit ? "-on" : ""]"
|
||||
lighter_overlay.color = lighter_color
|
||||
add_overlay(lighter_overlay)
|
||||
|
||||
/obj/item/lighter/greyscale/ignition_effect(atom/A, mob/user)
|
||||
if(is_hot())
|
||||
. = "<span class='notice'>After some fiddling, [user] manages to light [A] with [src].</span>"
|
||||
|
||||
|
||||
/obj/item/lighter/slime
|
||||
name = "slime zippo"
|
||||
desc = "A specialty zippo made from slimes and industry. Has a much hotter flame than normal."
|
||||
icon_state = "slighter"
|
||||
heat = 3000 //Blue flame!
|
||||
light_color = LIGHT_COLOR_CYAN
|
||||
overlay_state = "slime"
|
||||
grind_results = list("iron" = 1, "welding_fuel" = 5, "pyroxadone" = 5)
|
||||
|
||||
|
||||
///////////
|
||||
//ROLLING//
|
||||
///////////
|
||||
/obj/item/rollingpaper
|
||||
name = "rolling paper"
|
||||
desc = "A thin piece of paper used to make fine smokeables."
|
||||
icon = 'icons/obj/cigarettes.dmi'
|
||||
icon_state = "cig_paper"
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
|
||||
/obj/item/rollingpaper/afterattack(atom/target, mob/user, proximity)
|
||||
. = ..()
|
||||
if(!proximity)
|
||||
return
|
||||
if(istype(target, /obj/item/reagent_containers/food/snacks/grown))
|
||||
var/obj/item/reagent_containers/food/snacks/grown/O = target
|
||||
if(O.dry)
|
||||
var/obj/item/clothing/mask/cigarette/rollie/R = new /obj/item/clothing/mask/cigarette/rollie(user.loc)
|
||||
R.chem_volume = target.reagents.total_volume
|
||||
target.reagents.trans_to(R, R.chem_volume)
|
||||
qdel(target)
|
||||
qdel(src)
|
||||
user.put_in_active_hand(R)
|
||||
to_chat(user, "<span class='notice'>You roll the [target.name] into a rolling paper.</span>")
|
||||
R.desc = "Dried [target.name] rolled up in a thin piece of paper."
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You need to dry this first!</span>")
|
||||
|
||||
///////////////
|
||||
//VAPE NATION//
|
||||
///////////////
|
||||
/obj/item/clothing/mask/vape
|
||||
name = "\improper E-Cigarette"
|
||||
desc = "A classy and highly sophisticated electronic cigarette, for classy and dignified gentlemen. A warning label reads \"Warning: Do not fill with flammable materials.\""//<<< i'd vape to that.
|
||||
icon = 'icons/obj/clothing/masks.dmi'
|
||||
icon_state = null
|
||||
item_state = null
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
var/chem_volume = 100
|
||||
var/vapetime = FALSE //this so it won't puff out clouds every tick
|
||||
var/screw = FALSE // kinky
|
||||
var/super = FALSE //for the fattest vapes dude.
|
||||
|
||||
/obj/item/clothing/mask/vape/suicide_act(mob/user)
|
||||
user.visible_message("<span class='suicide'>[user] is puffin hard on dat vape, [user.p_they()] trying to join the vape life on a whole notha plane!</span>")//it doesn't give you cancer, it is cancer
|
||||
return (TOXLOSS|OXYLOSS)
|
||||
|
||||
|
||||
/obj/item/clothing/mask/vape/Initialize(mapload, param_color)
|
||||
. = ..()
|
||||
create_reagents(chem_volume, NO_REACT) // so it doesn't react until you light it
|
||||
reagents.add_reagent("nicotine", 50)
|
||||
if(!icon_state)
|
||||
if(!param_color)
|
||||
param_color = pick("red","blue","black","white","green","purple","yellow","orange")
|
||||
icon_state = "[param_color]_vape"
|
||||
item_state = "[param_color]_vape"
|
||||
|
||||
/obj/item/clothing/mask/vape/attackby(obj/item/O, mob/user, params)
|
||||
if(O.tool_behaviour == TOOL_SCREWDRIVER)
|
||||
if(!screw)
|
||||
screw = TRUE
|
||||
to_chat(user, "<span class='notice'>You open the cap on [src].</span>")
|
||||
ENABLE_BITFIELD(reagents.reagents_holder_flags, OPENCONTAINER)
|
||||
if(obj_flags & EMAGGED)
|
||||
add_overlay("vapeopen_high")
|
||||
else if(super)
|
||||
add_overlay("vapeopen_med")
|
||||
else
|
||||
add_overlay("vapeopen_low")
|
||||
else
|
||||
screw = FALSE
|
||||
to_chat(user, "<span class='notice'>You close the cap on [src].</span>")
|
||||
DISABLE_BITFIELD(reagents.reagents_holder_flags, OPENCONTAINER)
|
||||
cut_overlays()
|
||||
|
||||
if(O.tool_behaviour == TOOL_MULTITOOL)
|
||||
if(screw && !(obj_flags & EMAGGED))//also kinky
|
||||
if(!super)
|
||||
cut_overlays()
|
||||
super = TRUE
|
||||
to_chat(user, "<span class='notice'>You increase the voltage of [src].</span>")
|
||||
add_overlay("vapeopen_med")
|
||||
else
|
||||
cut_overlays()
|
||||
super = FALSE
|
||||
to_chat(user, "<span class='notice'>You decrease the voltage of [src].</span>")
|
||||
add_overlay("vapeopen_low")
|
||||
|
||||
if(screw && (obj_flags & EMAGGED))
|
||||
to_chat(user, "<span class='notice'>[src] can't be modified!</span>")
|
||||
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/item/clothing/mask/vape/emag_act(mob/user)// I WON'T REGRET WRITTING THIS, SURLY.
|
||||
if(screw)
|
||||
if(!(obj_flags & EMAGGED))
|
||||
cut_overlays()
|
||||
obj_flags |= EMAGGED
|
||||
super = FALSE
|
||||
to_chat(user, "<span class='warning'>You maximize the voltage of [src].</span>")
|
||||
add_overlay("vapeopen_high")
|
||||
var/datum/effect_system/spark_spread/sp = new /datum/effect_system/spark_spread //for effect
|
||||
sp.set_up(5, 1, src)
|
||||
sp.start()
|
||||
else
|
||||
to_chat(user, "<span class='warning'>[src] is already emagged!</span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You need to open the cap to do that.</span>")
|
||||
|
||||
/obj/item/clothing/mask/vape/attack_self(mob/user)
|
||||
if(reagents.total_volume > 0)
|
||||
to_chat(user, "<span class='notice'>You empty [src] of all reagents.</span>")
|
||||
reagents.clear_reagents()
|
||||
|
||||
/obj/item/clothing/mask/vape/equipped(mob/user, slot)
|
||||
if(slot == SLOT_WEAR_MASK)
|
||||
if(!screw)
|
||||
to_chat(user, "<span class='notice'>You start puffing on the vape.</span>")
|
||||
DISABLE_BITFIELD(reagents.reagents_holder_flags, NO_REACT)
|
||||
START_PROCESSING(SSobj, src)
|
||||
else //it will not start if the vape is opened.
|
||||
to_chat(user, "<span class='warning'>You need to close the cap first!</span>")
|
||||
|
||||
/obj/item/clothing/mask/vape/dropped(mob/user)
|
||||
var/mob/living/carbon/C = user
|
||||
if(C.get_item_by_slot(SLOT_WEAR_MASK) == src)
|
||||
ENABLE_BITFIELD(reagents.reagents_holder_flags, NO_REACT)
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/clothing/mask/vape/proc/hand_reagents()//had to rename to avoid duplicate error
|
||||
if(reagents.total_volume)
|
||||
if(iscarbon(loc))
|
||||
var/mob/living/carbon/C = loc
|
||||
if (src == C.wear_mask) // if it's in the human/monkey mouth, transfer reagents to the mob
|
||||
var/fraction = min(REAGENTS_METABOLISM/reagents.total_volume, 1) //this will react instantly, making them a little more dangerous than cigarettes
|
||||
reagents.reaction(C, INGEST, fraction)
|
||||
if(!reagents.trans_to(C, REAGENTS_METABOLISM))
|
||||
reagents.remove_any(REAGENTS_METABOLISM)
|
||||
if(reagents.get_reagent_amount("welding_fuel"))
|
||||
//HOT STUFF
|
||||
C.fire_stacks = 2
|
||||
C.IgniteMob()
|
||||
|
||||
if(reagents.get_reagent_amount("plasma")) // the plasma explodes when exposed to fire
|
||||
var/datum/effect_system/reagents_explosion/e = new()
|
||||
e.set_up(round(reagents.get_reagent_amount("plasma") / 2.5, 1), get_turf(src), 0, 0)
|
||||
e.start()
|
||||
qdel(src)
|
||||
return
|
||||
reagents.remove_any(REAGENTS_METABOLISM)
|
||||
|
||||
/obj/item/clothing/mask/vape/process()
|
||||
var/mob/living/M = loc
|
||||
|
||||
if(isliving(loc))
|
||||
M.IgniteMob()
|
||||
|
||||
vapetime++
|
||||
|
||||
if(!reagents.total_volume)
|
||||
if(ismob(loc))
|
||||
to_chat(M, "<span class='notice'>[src] is empty!</span>")
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
//it's reusable so it won't unequip when empty
|
||||
return
|
||||
//open flame removed because vapes are a closed system, they wont light anything on fire
|
||||
|
||||
if(super && vapetime > 3)//Time to start puffing those fat vapes, yo.
|
||||
var/datum/effect_system/smoke_spread/chem/smoke_machine/s = new
|
||||
s.set_up(reagents, 1, 24, loc)
|
||||
s.start()
|
||||
vapetime = 0
|
||||
|
||||
if((obj_flags & EMAGGED) && vapetime > 3)
|
||||
var/datum/effect_system/smoke_spread/chem/smoke_machine/s = new
|
||||
s.set_up(reagents, 4, 24, loc)
|
||||
s.start()
|
||||
vapetime = 0
|
||||
if(prob(5))//small chance for the vape to break and deal damage if it's emagged
|
||||
playsound(get_turf(src), 'sound/effects/pop_expl.ogg', 50, 0)
|
||||
M.apply_damage(20, BURN, BODY_ZONE_HEAD)
|
||||
M.Knockdown(300, 1, 0)
|
||||
var/datum/effect_system/spark_spread/sp = new /datum/effect_system/spark_spread
|
||||
sp.set_up(5, 1, src)
|
||||
sp.start()
|
||||
to_chat(M, "<span class='userdanger'>[src] suddenly explodes in your mouth!</span>")
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
if(reagents && reagents.total_volume)
|
||||
hand_reagents()
|
||||
@@ -0,0 +1,67 @@
|
||||
//File with the circuitboard and circuitboard/machine class definitions and procs
|
||||
|
||||
|
||||
// Circuitboard
|
||||
|
||||
/obj/item/circuitboard
|
||||
name = "circuit board"
|
||||
icon = 'icons/obj/module.dmi'
|
||||
icon_state = "id_mod"
|
||||
item_state = "electronic"
|
||||
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
|
||||
materials = list(MAT_GLASS=1000)
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
grind_results = list("silicon" = 20)
|
||||
var/build_path = null
|
||||
|
||||
/obj/item/circuitboard/proc/apply_default_parts(obj/machinery/M)
|
||||
return
|
||||
|
||||
// Circuitboard/machine
|
||||
/*Common Parts: Parts List: Ignitor, Timer, Infra-red laser, Infra-red sensor, t_scanner, Capacitor, Valve, sensor unit,
|
||||
micro-manipulator, console screen, beaker, Microlaser, matter bin, power cells.
|
||||
*/
|
||||
|
||||
/obj/item/circuitboard/machine
|
||||
var/needs_anchored = TRUE // Whether this machine must be anchored to be constructed.
|
||||
var/list/req_components // Components required by the machine.
|
||||
// Example: list(/obj/item/stock_parts/matter_bin = 5)
|
||||
|
||||
var/list/def_components // Default replacements for req_components, to be used in apply_default_parts instead of req_components types
|
||||
// Example: list(/obj/item/stock_parts/matter_bin = /obj/item/stock_parts/matter_bin/super)
|
||||
|
||||
// Applies the default parts defined by the circuit board when the machine is created
|
||||
/obj/item/circuitboard/machine/apply_default_parts(obj/machinery/M)
|
||||
if(!req_components)
|
||||
return
|
||||
|
||||
M.component_parts = list(src) // List of components always contains a board
|
||||
moveToNullspace()
|
||||
|
||||
for(var/comp_path in req_components)
|
||||
var/comp_amt = req_components[comp_path]
|
||||
if(!comp_amt)
|
||||
continue
|
||||
|
||||
if(def_components && def_components[comp_path])
|
||||
comp_path = def_components[comp_path]
|
||||
|
||||
if(ispath(comp_path, /obj/item/stack))
|
||||
M.component_parts += new comp_path(null, comp_amt)
|
||||
else
|
||||
for(var/i in 1 to comp_amt)
|
||||
M.component_parts += new comp_path(null)
|
||||
|
||||
M.RefreshParts()
|
||||
|
||||
/obj/item/circuitboard/machine/examine(mob/user)
|
||||
..()
|
||||
if(LAZYLEN(req_components))
|
||||
var/list/nice_list = list()
|
||||
for(var/B in req_components)
|
||||
var/atom/A = B
|
||||
if(!ispath(A))
|
||||
continue
|
||||
nice_list += list("[req_components[A]] [initial(A.name)]")
|
||||
to_chat(user,"<span class='notice'>Required components: [english_list(nice_list)].</span>")
|
||||
@@ -0,0 +1,369 @@
|
||||
/obj/item/circuitboard/computer/turbine_computer
|
||||
name = "Turbine Computer (Computer Board)"
|
||||
build_path = /obj/machinery/computer/turbine_computer
|
||||
|
||||
/obj/item/circuitboard/computer/launchpad_console
|
||||
name = "Launchpad Control Console (Computer Board)"
|
||||
build_path = /obj/machinery/computer/launchpad
|
||||
|
||||
/obj/item/circuitboard/computer/message_monitor
|
||||
name = "Message Monitor (Computer Board)"
|
||||
build_path = /obj/machinery/computer/message_monitor
|
||||
|
||||
/obj/item/circuitboard/computer/security
|
||||
name = "Security Cameras (Computer Board)"
|
||||
build_path = /obj/machinery/computer/security
|
||||
|
||||
/obj/item/circuitboard/computer/xenobiology
|
||||
name = "circuit board (Xenobiology Console)"
|
||||
build_path = /obj/machinery/computer/camera_advanced/xenobio
|
||||
|
||||
/obj/item/circuitboard/computer/base_construction
|
||||
name = "circuit board (Aux Mining Base Construction Console)"
|
||||
build_path = /obj/machinery/computer/camera_advanced/base_construction
|
||||
|
||||
/obj/item/circuitboard/computer/aiupload
|
||||
name = "AI Upload (Computer Board)"
|
||||
build_path = /obj/machinery/computer/upload/ai
|
||||
|
||||
/obj/item/circuitboard/computer/borgupload
|
||||
name = "Cyborg Upload (Computer Board)"
|
||||
build_path = /obj/machinery/computer/upload/borg
|
||||
|
||||
/obj/item/circuitboard/computer/med_data
|
||||
name = "Medical Records Console (Computer Board)"
|
||||
build_path = /obj/machinery/computer/med_data
|
||||
|
||||
/obj/item/circuitboard/computer/pandemic
|
||||
name = "PanD.E.M.I.C. 2200 (Computer Board)"
|
||||
build_path = /obj/machinery/computer/pandemic
|
||||
|
||||
/obj/item/circuitboard/computer/scan_consolenew
|
||||
name = "DNA Machine (Computer Board)"
|
||||
build_path = /obj/machinery/computer/scan_consolenew
|
||||
|
||||
/obj/item/circuitboard/computer/communications
|
||||
name = "Communications (Computer Board)"
|
||||
build_path = /obj/machinery/computer/communications
|
||||
var/lastTimeUsed = 0
|
||||
|
||||
/obj/item/circuitboard/computer/card
|
||||
name = "ID Console (Computer Board)"
|
||||
build_path = /obj/machinery/computer/card
|
||||
|
||||
/obj/item/circuitboard/computer/card/centcom
|
||||
name = "CentCom ID Console (Computer Board)"
|
||||
build_path = /obj/machinery/computer/card/centcom
|
||||
|
||||
/obj/item/circuitboard/computer/card/minor
|
||||
name = "Department Management Console (Computer Board)"
|
||||
build_path = /obj/machinery/computer/card/minor
|
||||
var/target_dept = 1
|
||||
var/list/dept_list = list("General","Security","Medical","Science","Engineering")
|
||||
|
||||
/obj/item/circuitboard/computer/card/minor/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/screwdriver))
|
||||
target_dept = (target_dept == dept_list.len) ? 1 : (target_dept + 1)
|
||||
to_chat(user, "<span class='notice'>You set the board to \"[dept_list[target_dept]]\".</span>")
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/circuitboard/computer/card/minor/examine(user)
|
||||
..()
|
||||
to_chat(user, "Currently set to \"[dept_list[target_dept]]\".")
|
||||
|
||||
//obj/item/circuitboard/computer/shield
|
||||
// name = "Shield Control (Computer Board)"
|
||||
// build_path = /obj/machinery/computer/stationshield
|
||||
/obj/item/circuitboard/computer/teleporter
|
||||
name = "Teleporter (Computer Board)"
|
||||
build_path = /obj/machinery/computer/teleporter
|
||||
|
||||
/obj/item/circuitboard/computer/secure_data
|
||||
name = "Security Records Console (Computer Board)"
|
||||
build_path = /obj/machinery/computer/secure_data
|
||||
|
||||
/obj/item/circuitboard/computer/stationalert
|
||||
name = "Station Alerts (Computer Board)"
|
||||
build_path = /obj/machinery/computer/station_alert
|
||||
|
||||
/obj/item/circuitboard/computer/atmos_control
|
||||
name = "Atmospheric Monitor (Computer Board)"
|
||||
build_path = /obj/machinery/computer/atmos_control
|
||||
|
||||
/obj/item/circuitboard/computer/atmos_control/tank
|
||||
name = "Tank Control (Computer Board)"
|
||||
build_path = /obj/machinery/computer/atmos_control/tank
|
||||
|
||||
/obj/item/circuitboard/computer/atmos_alert
|
||||
name = "Atmospheric Alert (Computer Board)"
|
||||
build_path = /obj/machinery/computer/atmos_alert
|
||||
|
||||
/obj/item/circuitboard/computer/pod
|
||||
name = "Massdriver control (Computer Board)"
|
||||
build_path = /obj/machinery/computer/pod
|
||||
|
||||
/obj/item/circuitboard/computer/robotics
|
||||
name = "Robotics Control (Computer Board)"
|
||||
build_path = /obj/machinery/computer/robotics
|
||||
|
||||
/obj/item/circuitboard/computer/cloning
|
||||
name = "Cloning (Computer Board)"
|
||||
build_path = /obj/machinery/computer/cloning
|
||||
var/list/records = list()
|
||||
|
||||
/obj/item/circuitboard/computer/prototype_cloning
|
||||
name = "Prototype Cloning (Computer Board)"
|
||||
build_path = /obj/machinery/computer/prototype_cloning
|
||||
|
||||
/obj/item/circuitboard/computer/arcade/battle
|
||||
name = "Arcade Battle (Computer Board)"
|
||||
build_path = /obj/machinery/computer/arcade/battle
|
||||
|
||||
/obj/item/circuitboard/computer/arcade/orion_trail
|
||||
name = "Orion Trail (Computer Board)"
|
||||
build_path = /obj/machinery/computer/arcade/orion_trail
|
||||
|
||||
/obj/item/circuitboard/computer/arcade/minesweeper
|
||||
name = "Minesweeper (Computer Board)"
|
||||
build_path = /obj/machinery/computer/arcade/minesweeper
|
||||
|
||||
/obj/item/circuitboard/computer/arcade/amputation
|
||||
name = "Mediborg's Amputation Adventure (Computer Board)"
|
||||
build_path = /obj/machinery/computer/arcade/amputation
|
||||
|
||||
/obj/item/circuitboard/computer/turbine_control
|
||||
name = "Turbine control (Computer Board)"
|
||||
build_path = /obj/machinery/computer/turbine_computer
|
||||
|
||||
/obj/item/circuitboard/computer/solar_control
|
||||
name = "Solar Control (Computer Board)" //name fixed 250810
|
||||
build_path = /obj/machinery/power/solar_control
|
||||
|
||||
/obj/item/circuitboard/computer/powermonitor
|
||||
name = "Power Monitor (Computer Board)" //name fixed 250810
|
||||
build_path = /obj/machinery/computer/monitor
|
||||
|
||||
/obj/item/circuitboard/computer/powermonitor/secret
|
||||
name = "Outdated Power Monitor (Computer Board)" //Variant used on ruins to prevent them from showing up on PDA's.
|
||||
build_path = /obj/machinery/computer/monitor/secret
|
||||
|
||||
/obj/item/circuitboard/computer/olddoor
|
||||
name = "DoorMex (Computer Board)"
|
||||
build_path = /obj/machinery/computer/pod/old
|
||||
|
||||
/obj/item/circuitboard/computer/syndicatedoor
|
||||
name = "ProComp Executive (Computer Board)"
|
||||
build_path = /obj/machinery/computer/pod/old/syndicate
|
||||
|
||||
/obj/item/circuitboard/computer/swfdoor
|
||||
name = "Magix (Computer Board)"
|
||||
build_path = /obj/machinery/computer/pod/old/swf
|
||||
|
||||
/obj/item/circuitboard/computer/prisoner
|
||||
name = "Prisoner Management Console (Computer Board)"
|
||||
build_path = /obj/machinery/computer/prisoner
|
||||
/obj/item/circuitboard/computer/gulag_teleporter_console
|
||||
name = "Labor Camp teleporter console (Computer Board)"
|
||||
build_path = /obj/machinery/computer/gulag_teleporter_computer
|
||||
|
||||
/obj/item/circuitboard/computer/rdconsole/production
|
||||
name = "R&D Console Production Only (Computer Board)"
|
||||
build_path = /obj/machinery/computer/rdconsole/production
|
||||
|
||||
/obj/item/circuitboard/computer/rdconsole
|
||||
name = "R&D Console (Computer Board)"
|
||||
build_path = /obj/machinery/computer/rdconsole/core
|
||||
|
||||
/obj/item/circuitboard/computer/rdconsole/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/screwdriver))
|
||||
if(build_path == /obj/machinery/computer/rdconsole/core)
|
||||
name = "R&D Console - Robotics (Computer Board)"
|
||||
build_path = /obj/machinery/computer/rdconsole/robotics
|
||||
to_chat(user, "<span class='notice'>Access protocols successfully updated.</span>")
|
||||
else
|
||||
name = "R&D Console (Computer Board)"
|
||||
build_path = /obj/machinery/computer/rdconsole/core
|
||||
to_chat(user, "<span class='notice'>Defaulting access protocols.</span>")
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/circuitboard/computer/mecha_control
|
||||
name = "Exosuit Control Console (Computer Board)"
|
||||
build_path = /obj/machinery/computer/mecha
|
||||
|
||||
/obj/item/circuitboard/computer/rdservercontrol
|
||||
name = "R&D Server Control (Computer Board)"
|
||||
build_path = /obj/machinery/computer/rdservercontrol
|
||||
|
||||
/obj/item/circuitboard/computer/crew
|
||||
name = "Crew Monitoring Console (Computer Board)"
|
||||
build_path = /obj/machinery/computer/crew
|
||||
|
||||
/obj/item/circuitboard/computer/mech_bay_power_console
|
||||
name = "Mech Bay Power Control Console (Computer Board)"
|
||||
build_path = /obj/machinery/computer/mech_bay_power_console
|
||||
|
||||
/obj/item/circuitboard/computer/cargo
|
||||
name = "Supply Console (Computer Board)"
|
||||
build_path = /obj/machinery/computer/cargo
|
||||
var/contraband = FALSE
|
||||
|
||||
/obj/item/circuitboard/computer/cargo/multitool_act(mob/living/user)
|
||||
if(!(obj_flags & EMAGGED))
|
||||
contraband = !contraband
|
||||
to_chat(user, "<span class='notice'>Receiver spectrum set to [contraband ? "Broad" : "Standard"].</span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>The spectrum chip is unresponsive.</span>")
|
||||
|
||||
/obj/item/circuitboard/computer/cargo/emag_act(mob/living/user)
|
||||
if(!(obj_flags & EMAGGED))
|
||||
contraband = TRUE
|
||||
obj_flags |= EMAGGED
|
||||
to_chat(user, "<span class='notice'>You adjust [src]'s routing and receiver spectrum, unlocking special supplies and contraband.</span>")
|
||||
|
||||
/obj/item/circuitboard/computer/cargo/express
|
||||
name = "Express Supply Console (Computer Board)"
|
||||
build_path = /obj/machinery/computer/cargo/express
|
||||
|
||||
/obj/item/circuitboard/computer/cargo/express/multitool_act(mob/living/user)
|
||||
if (!(obj_flags & EMAGGED))
|
||||
to_chat(user, "<span class='notice'>Routing protocols are already set to: \"factory defaults\".</span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You reset the routing protocols to: \"factory defaults\".</span>")
|
||||
obj_flags &= ~EMAGGED
|
||||
|
||||
/obj/item/circuitboard/computer/cargo/express/emag_act(mob/living/user)
|
||||
to_chat(user, "<span class='notice'>You change the routing protocols, allowing the Drop Pod to land anywhere on the station.</span>")
|
||||
obj_flags |= EMAGGED
|
||||
|
||||
/obj/item/circuitboard/computer/cargo/request
|
||||
name = "Supply Request Console (Computer Board)"
|
||||
build_path = /obj/machinery/computer/cargo/request
|
||||
|
||||
/obj/item/circuitboard/computer/bounty
|
||||
name = "Nanotrasen Bounty Console (Computer Board)"
|
||||
build_path = /obj/machinery/computer/bounty
|
||||
|
||||
/obj/item/circuitboard/computer/operating
|
||||
name = "Operating Computer (Computer Board)"
|
||||
build_path = /obj/machinery/computer/operating
|
||||
|
||||
/obj/item/circuitboard/computer/mining
|
||||
name = "Outpost Status Display (Computer Board)"
|
||||
build_path = /obj/machinery/computer/security/mining
|
||||
|
||||
/obj/item/circuitboard/computer/research
|
||||
name = "Research Monitor (Computer Board)"
|
||||
build_path = /obj/machinery/computer/security/research
|
||||
|
||||
/obj/item/circuitboard/computer/comm_monitor
|
||||
name = "Telecommunications Monitor (Computer Board)"
|
||||
build_path = /obj/machinery/computer/telecomms/monitor
|
||||
|
||||
/obj/item/circuitboard/computer/comm_server
|
||||
name = "Telecommunications Server Monitor (Computer Board)"
|
||||
build_path = /obj/machinery/computer/telecomms/server
|
||||
|
||||
/obj/item/circuitboard/computer/labor_shuttle
|
||||
name = "Labor Shuttle (Computer Board)"
|
||||
build_path = /obj/machinery/computer/shuttle/labor
|
||||
|
||||
/obj/item/circuitboard/computer/labor_shuttle/one_way
|
||||
name = "Prisoner Shuttle Console (Computer Board)"
|
||||
build_path = /obj/machinery/computer/shuttle/labor/one_way
|
||||
|
||||
/obj/item/circuitboard/computer/ferry
|
||||
name = "Transport Ferry (Computer Board)"
|
||||
build_path = /obj/machinery/computer/shuttle/ferry
|
||||
|
||||
/obj/item/circuitboard/computer/ferry/request
|
||||
name = "Transport Ferry Console (Computer Board)"
|
||||
build_path = /obj/machinery/computer/shuttle/ferry/request
|
||||
|
||||
/obj/item/circuitboard/computer/mining_shuttle
|
||||
name = "Mining Shuttle (Computer Board)"
|
||||
build_path = /obj/machinery/computer/shuttle/mining
|
||||
|
||||
/obj/item/circuitboard/computer/white_ship
|
||||
name = "White Ship (Computer Board)"
|
||||
build_path = /obj/machinery/computer/shuttle/white_ship
|
||||
|
||||
/obj/item/circuitboard/computer/white_ship/pod
|
||||
name = "Salvage Pod (Computer Board)"
|
||||
build_path = /obj/machinery/computer/shuttle/white_ship/pod
|
||||
|
||||
/obj/item/circuitboard/computer/white_ship/pod/recall
|
||||
name = "Salvage Pod Recall (Computer Board)"
|
||||
build_path = /obj/machinery/computer/shuttle/white_ship/pod/recall
|
||||
|
||||
/obj/item/circuitboard/computer/auxillary_base
|
||||
name = "Auxillary Base Management Console (Computer Board)"
|
||||
build_path = /obj/machinery/computer/auxillary_base
|
||||
|
||||
/obj/item/circuitboard/computer/holodeck// Not going to let people get this, but it's just here for future
|
||||
name = "Holodeck Control (Computer Board)"
|
||||
build_path = /obj/machinery/computer/holodeck
|
||||
|
||||
/obj/item/circuitboard/computer/aifixer
|
||||
name = "AI Integrity Restorer (Computer Board)"
|
||||
build_path = /obj/machinery/computer/aifixer
|
||||
|
||||
/obj/item/circuitboard/computer/slot_machine
|
||||
name = "Slot Machine (Computer Board)"
|
||||
build_path = /obj/machinery/computer/slot_machine
|
||||
|
||||
/obj/item/circuitboard/computer/libraryconsole
|
||||
name = "Library Visitor Console (Computer Board)"
|
||||
build_path = /obj/machinery/computer/libraryconsole
|
||||
|
||||
/obj/item/circuitboard/computer/libraryconsole/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/screwdriver))
|
||||
if(build_path == /obj/machinery/computer/libraryconsole/bookmanagement)
|
||||
name = "Library Visitor Console (Computer Board)"
|
||||
build_path = /obj/machinery/computer/libraryconsole
|
||||
to_chat(user, "<span class='notice'>Defaulting access protocols.</span>")
|
||||
else
|
||||
name = "Book Inventory Management Console (Computer Board)"
|
||||
build_path = /obj/machinery/computer/libraryconsole/bookmanagement
|
||||
to_chat(user, "<span class='notice'>Access protocols successfully updated.</span>")
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/circuitboard/computer/apc_control
|
||||
name = "\improper Power Flow Control Console (Computer Board)"
|
||||
build_path = /obj/machinery/computer/apc_control
|
||||
|
||||
/obj/item/circuitboard/computer/monastery_shuttle
|
||||
name = "Monastery Shuttle (Computer Board)"
|
||||
build_path = /obj/machinery/computer/shuttle/monastery_shuttle
|
||||
|
||||
/obj/item/circuitboard/computer/syndicate_shuttle
|
||||
name = "Syndicate Shuttle (Computer Board)"
|
||||
build_path = /obj/machinery/computer/shuttle/syndicate
|
||||
var/challenge = FALSE
|
||||
var/moved = FALSE
|
||||
|
||||
/obj/item/circuitboard/computer/syndicate_shuttle/Initialize()
|
||||
. = ..()
|
||||
GLOB.syndicate_shuttle_boards += src
|
||||
|
||||
/obj/item/circuitboard/computer/syndicate_shuttle/Destroy()
|
||||
GLOB.syndicate_shuttle_boards -= src
|
||||
return ..()
|
||||
|
||||
/obj/item/circuitboard/computer/bsa_control
|
||||
name = "Bluespace Artillery Controls (Computer Board)"
|
||||
build_path = /obj/machinery/computer/bsa_control
|
||||
|
||||
/obj/item/circuitboard/computer/sat_control
|
||||
name = "Satellite Network Control (Computer Board)"
|
||||
build_path = /obj/machinery/computer/sat_control
|
||||
|
||||
/obj/item/circuitboard/computer/nanite_chamber_control
|
||||
name = "Nanite Chamber Control (Computer Board)"
|
||||
build_path = /obj/machinery/computer/nanite_chamber_control
|
||||
|
||||
/obj/item/circuitboard/computer/nanite_cloud_controller
|
||||
name = "Nanite Cloud Control (Computer Board)"
|
||||
build_path = /obj/machinery/computer/nanite_cloud_controller
|
||||
@@ -0,0 +1,975 @@
|
||||
/obj/item/circuitboard/machine/sleeper
|
||||
name = "Sleeper (Machine Board)"
|
||||
build_path = /obj/machinery/sleeper
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/matter_bin = 1,
|
||||
/obj/item/stock_parts/manipulator = 1,
|
||||
/obj/item/stack/cable_coil = 1,
|
||||
/obj/item/stack/sheet/glass = 2)
|
||||
|
||||
/obj/item/circuitboard/machine/vr_sleeper
|
||||
name = "VR Sleeper (Machine Board)"
|
||||
build_path = /obj/machinery/vr_sleeper
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/manipulator = 1,
|
||||
/obj/item/stack/cable_coil = 1,
|
||||
/obj/item/stock_parts/scanning_module = 2,
|
||||
/obj/item/stack/sheet/glass = 2)
|
||||
|
||||
/obj/item/circuitboard/machine/announcement_system
|
||||
name = "Announcement System (Machine Board)"
|
||||
build_path = /obj/machinery/announcement_system
|
||||
req_components = list(
|
||||
/obj/item/stack/cable_coil = 2,
|
||||
/obj/item/stack/sheet/glass = 1)
|
||||
|
||||
/obj/item/circuitboard/machine/autolathe
|
||||
name = "Autolathe (Machine Board)"
|
||||
build_path = /obj/machinery/autolathe
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/matter_bin = 3,
|
||||
/obj/item/stock_parts/manipulator = 1,
|
||||
/obj/item/stack/sheet/glass = 1)
|
||||
|
||||
/obj/item/circuitboard/machine/clonepod
|
||||
name = "Clone Pod (Machine Board)"
|
||||
build_path = /obj/machinery/clonepod
|
||||
req_components = list(
|
||||
/obj/item/stack/cable_coil = 2,
|
||||
/obj/item/stock_parts/scanning_module = 2,
|
||||
/obj/item/stock_parts/manipulator = 2,
|
||||
/obj/item/stack/sheet/glass = 1)
|
||||
|
||||
/obj/item/circuitboard/machine/clonepod/experimental
|
||||
name = "Experimental Clone Pod (Machine Board)"
|
||||
build_path = /obj/machinery/clonepod/experimental
|
||||
|
||||
/obj/item/circuitboard/machine/abductor
|
||||
name = "alien board (Report This)"
|
||||
icon_state = "abductor_mod"
|
||||
|
||||
/obj/item/circuitboard/machine/clockwork
|
||||
name = "clockwork board (Report This)"
|
||||
icon_state = "clock_mod"
|
||||
|
||||
/obj/item/circuitboard/machine/clonescanner
|
||||
name = "Cloning Scanner (Machine Board)"
|
||||
build_path = /obj/machinery/dna_scannernew
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/scanning_module = 1,
|
||||
/obj/item/stock_parts/manipulator = 1,
|
||||
/obj/item/stock_parts/micro_laser = 1,
|
||||
/obj/item/stack/sheet/glass = 1,
|
||||
/obj/item/stack/cable_coil = 2)
|
||||
|
||||
/obj/item/circuitboard/machine/holopad
|
||||
name = "AI Holopad (Machine Board)"
|
||||
build_path = /obj/machinery/holopad
|
||||
req_components = list(/obj/item/stock_parts/capacitor = 1)
|
||||
needs_anchored = FALSE //wew lad
|
||||
|
||||
/obj/item/circuitboard/machine/launchpad
|
||||
name = "Bluespace Launchpad (Machine Board)"
|
||||
build_path = /obj/machinery/launchpad
|
||||
req_components = list(
|
||||
/obj/item/stack/ore/bluespace_crystal = 1,
|
||||
/obj/item/stock_parts/manipulator = 1)
|
||||
def_components = list(/obj/item/stack/ore/bluespace_crystal = /obj/item/stack/ore/bluespace_crystal/artificial)
|
||||
|
||||
/obj/item/circuitboard/machine/limbgrower
|
||||
name = "Limb Grower (Machine Board)"
|
||||
build_path = /obj/machinery/limbgrower
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/manipulator = 1,
|
||||
/obj/item/reagent_containers/glass/beaker = 2,
|
||||
/obj/item/stack/sheet/glass = 1)
|
||||
|
||||
/obj/item/circuitboard/machine/quantumpad
|
||||
name = "Quantum Pad (Machine Board)"
|
||||
build_path = /obj/machinery/quantumpad
|
||||
req_components = list(
|
||||
/obj/item/stack/ore/bluespace_crystal = 1,
|
||||
/obj/item/stock_parts/capacitor = 1,
|
||||
/obj/item/stock_parts/manipulator = 1,
|
||||
/obj/item/stack/cable_coil = 1)
|
||||
def_components = list(/obj/item/stack/ore/bluespace_crystal = /obj/item/stack/ore/bluespace_crystal/artificial)
|
||||
|
||||
/obj/item/circuitboard/machine/recharger
|
||||
name = "Weapon Recharger (Machine Board)"
|
||||
build_path = /obj/machinery/recharger
|
||||
req_components = list(/obj/item/stock_parts/capacitor = 1)
|
||||
needs_anchored = FALSE
|
||||
|
||||
/obj/item/circuitboard/machine/cell_charger
|
||||
name = "Cell Charger (Machine Board)"
|
||||
build_path = /obj/machinery/cell_charger
|
||||
req_components = list(/obj/item/stock_parts/capacitor = 1)
|
||||
needs_anchored = FALSE
|
||||
|
||||
/obj/item/circuitboard/machine/cyborgrecharger
|
||||
name = "Cyborg Recharger (Machine Board)"
|
||||
build_path = /obj/machinery/recharge_station
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/capacitor = 2,
|
||||
/obj/item/stock_parts/cell = 1,
|
||||
/obj/item/stock_parts/manipulator = 1)
|
||||
def_components = list(/obj/item/stock_parts/cell = /obj/item/stock_parts/cell/high)
|
||||
|
||||
/obj/item/circuitboard/machine/recycler
|
||||
name = "Recycler (Machine Board)"
|
||||
build_path = /obj/machinery/recycler
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/matter_bin = 1,
|
||||
/obj/item/stock_parts/manipulator = 1)
|
||||
needs_anchored = FALSE
|
||||
|
||||
/obj/item/circuitboard/machine/space_heater
|
||||
name = "Space Heater (Machine Board)"
|
||||
build_path = /obj/machinery/space_heater
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/micro_laser = 1,
|
||||
/obj/item/stock_parts/capacitor = 1,
|
||||
/obj/item/stack/cable_coil = 3)
|
||||
needs_anchored = FALSE
|
||||
|
||||
/obj/item/circuitboard/machine/telecomms/broadcaster
|
||||
name = "Subspace Broadcaster (Machine Board)"
|
||||
build_path = /obj/machinery/telecomms/broadcaster
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/manipulator = 2,
|
||||
/obj/item/stack/cable_coil = 1,
|
||||
/obj/item/stock_parts/subspace/filter = 1,
|
||||
/obj/item/stock_parts/subspace/crystal = 1,
|
||||
/obj/item/stock_parts/micro_laser = 2)
|
||||
|
||||
/obj/item/circuitboard/machine/telecomms/bus
|
||||
name = "Bus Mainframe (Machine Board)"
|
||||
build_path = /obj/machinery/telecomms/bus
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/manipulator = 2,
|
||||
/obj/item/stack/cable_coil = 1,
|
||||
/obj/item/stock_parts/subspace/filter = 1)
|
||||
|
||||
/obj/item/circuitboard/machine/telecomms/hub
|
||||
name = "Hub Mainframe (Machine Board)"
|
||||
build_path = /obj/machinery/telecomms/hub
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/manipulator = 2,
|
||||
/obj/item/stack/cable_coil = 2,
|
||||
/obj/item/stock_parts/subspace/filter = 2)
|
||||
|
||||
/obj/item/circuitboard/machine/telecomms/processor
|
||||
name = "Processor Unit (Machine Board)"
|
||||
build_path = /obj/machinery/telecomms/processor
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/manipulator = 3,
|
||||
/obj/item/stock_parts/subspace/filter = 1,
|
||||
/obj/item/stock_parts/subspace/treatment = 2,
|
||||
/obj/item/stock_parts/subspace/analyzer = 1,
|
||||
/obj/item/stack/cable_coil = 2,
|
||||
/obj/item/stock_parts/subspace/amplifier = 1)
|
||||
|
||||
/obj/item/circuitboard/machine/telecomms/receiver
|
||||
name = "Subspace Receiver (Machine Board)"
|
||||
build_path = /obj/machinery/telecomms/receiver
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/subspace/ansible = 1,
|
||||
/obj/item/stock_parts/subspace/filter = 1,
|
||||
/obj/item/stock_parts/manipulator = 2,
|
||||
/obj/item/stock_parts/micro_laser = 1)
|
||||
|
||||
/obj/item/circuitboard/machine/telecomms/relay
|
||||
name = "Relay Mainframe (Machine Board)"
|
||||
build_path = /obj/machinery/telecomms/relay
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/manipulator = 2,
|
||||
/obj/item/stack/cable_coil = 2,
|
||||
/obj/item/stock_parts/subspace/filter = 2)
|
||||
|
||||
/obj/item/circuitboard/machine/telecomms/server
|
||||
name = "Telecommunication Server (Machine Board)"
|
||||
build_path = /obj/machinery/telecomms/server
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/manipulator = 2,
|
||||
/obj/item/stack/cable_coil = 1,
|
||||
/obj/item/stock_parts/subspace/filter = 1)
|
||||
|
||||
/obj/item/circuitboard/machine/teleporter_hub
|
||||
name = "Teleporter Hub (Machine Board)"
|
||||
build_path = /obj/machinery/teleport/hub
|
||||
req_components = list(
|
||||
/obj/item/stack/ore/bluespace_crystal = 3,
|
||||
/obj/item/stock_parts/matter_bin = 1)
|
||||
def_components = list(/obj/item/stack/ore/bluespace_crystal = /obj/item/stack/ore/bluespace_crystal/artificial)
|
||||
|
||||
/obj/item/circuitboard/machine/teleporter_station
|
||||
name = "Teleporter Station (Machine Board)"
|
||||
build_path = /obj/machinery/teleport/station
|
||||
req_components = list(
|
||||
/obj/item/stack/ore/bluespace_crystal = 2,
|
||||
/obj/item/stock_parts/capacitor = 2,
|
||||
/obj/item/stack/sheet/glass = 1)
|
||||
def_components = list(/obj/item/stack/ore/bluespace_crystal = /obj/item/stack/ore/bluespace_crystal/artificial)
|
||||
|
||||
/obj/item/circuitboard/machine/vendor
|
||||
name = "Booze-O-Mat Vendor (Machine Board)"
|
||||
desc = "You can turn the \"brand selection\" dial using a screwdriver."
|
||||
build_path = /obj/machinery/vending/boozeomat
|
||||
req_components = list(/obj/item/vending_refill/boozeomat = 1)
|
||||
|
||||
var/static/list/vending_names_paths = list(
|
||||
/obj/machinery/vending/boozeomat = "Booze-O-Mat",
|
||||
/obj/machinery/vending/coffee = "Solar's Best Hot Drinks",
|
||||
/obj/machinery/vending/snack = "Getmore Chocolate Corp",
|
||||
/obj/machinery/vending/cola = "Robust Softdrinks",
|
||||
/obj/machinery/vending/cigarette = "ShadyCigs Deluxe",
|
||||
/obj/machinery/vending/games = "\improper Good Clean Fun",
|
||||
/obj/machinery/vending/autodrobe = "AutoDrobe",
|
||||
/obj/machinery/vending/wardrobe/sec_wardrobe = "SecDrobe",
|
||||
/obj/machinery/vending/wardrobe/medi_wardrobe = "MediDrobe",
|
||||
/obj/machinery/vending/wardrobe/engi_wardrobe = "EngiDrobe",
|
||||
/obj/machinery/vending/wardrobe/atmos_wardrobe = "AtmosDrobe",
|
||||
/obj/machinery/vending/wardrobe/cargo_wardrobe = "CargoDrobe",
|
||||
/obj/machinery/vending/wardrobe/robo_wardrobe = "RoboDrobe",
|
||||
/obj/machinery/vending/wardrobe/science_wardrobe = "SciDrobe",
|
||||
/obj/machinery/vending/wardrobe/hydro_wardrobe = "HyDrobe",
|
||||
/obj/machinery/vending/wardrobe/curator_wardrobe = "CuraDrobe",
|
||||
/obj/machinery/vending/wardrobe/bar_wardrobe = "BarDrobe",
|
||||
/obj/machinery/vending/wardrobe/chef_wardrobe = "ChefDrobe",
|
||||
/obj/machinery/vending/wardrobe/jani_wardrobe = "JaniDrobe",
|
||||
/obj/machinery/vending/wardrobe/law_wardrobe = "LawDrobe",
|
||||
/obj/machinery/vending/wardrobe/chap_wardrobe = "ChapDrobe",
|
||||
/obj/machinery/vending/wardrobe/chem_wardrobe = "ChemDrobe",
|
||||
/obj/machinery/vending/wardrobe/gene_wardrobe = "GeneDrobe",
|
||||
/obj/machinery/vending/wardrobe/viro_wardrobe = "ViroDrobe",
|
||||
/obj/machinery/vending/clothing = "ClothesMate",
|
||||
/obj/machinery/vending/medical = "NanoMed Plus",
|
||||
/obj/machinery/vending/wallmed = "NanoMed")
|
||||
|
||||
/obj/item/circuitboard/machine/vendor/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/screwdriver))
|
||||
var/position = vending_names_paths.Find(build_path)
|
||||
position = (position == vending_names_paths.len) ? 1 : (position + 1)
|
||||
var/typepath = vending_names_paths[position]
|
||||
|
||||
to_chat(user, "<span class='notice'>You set the board to \"[vending_names_paths[typepath]]\".</span>")
|
||||
set_type(typepath)
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/circuitboard/machine/vendor/proc/set_type(obj/machinery/vending/typepath)
|
||||
build_path = typepath
|
||||
name = "[vending_names_paths[build_path]] Vendor (Machine Board)"
|
||||
req_components = list(initial(typepath.refill_canister) = 1)
|
||||
|
||||
/obj/item/circuitboard/machine/vendor/apply_default_parts(obj/machinery/M)
|
||||
for(var/typepath in vending_names_paths)
|
||||
if(istype(M, typepath))
|
||||
set_type(typepath)
|
||||
break
|
||||
return ..()
|
||||
|
||||
/obj/item/circuitboard/machine/mech_recharger
|
||||
name = "Mechbay Recharger (Machine Board)"
|
||||
build_path = /obj/machinery/mech_bay_recharge_port
|
||||
req_components = list(
|
||||
/obj/item/stack/cable_coil = 2,
|
||||
/obj/item/stock_parts/capacitor = 5)
|
||||
|
||||
/obj/item/circuitboard/machine/mechfab
|
||||
name = "Exosuit Fabricator (Machine Board)"
|
||||
build_path = /obj/machinery/mecha_part_fabricator
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/matter_bin = 2,
|
||||
/obj/item/stock_parts/manipulator = 1,
|
||||
/obj/item/stock_parts/micro_laser = 1,
|
||||
/obj/item/stack/sheet/glass = 1)
|
||||
|
||||
/obj/item/circuitboard/machine/cryo_tube
|
||||
name = "Cryotube (Machine Board)"
|
||||
build_path = /obj/machinery/atmospherics/components/unary/cryo_cell
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/matter_bin = 1,
|
||||
/obj/item/stack/cable_coil = 1,
|
||||
/obj/item/stack/sheet/glass = 4)
|
||||
|
||||
/obj/item/circuitboard/machine/thermomachine
|
||||
name = "Thermomachine (Machine Board)"
|
||||
desc = "You can use a screwdriver to switch between heater and freezer."
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/matter_bin = 2,
|
||||
/obj/item/stock_parts/micro_laser = 2,
|
||||
/obj/item/stack/cable_coil = 1,
|
||||
/obj/item/stack/sheet/glass = 1)
|
||||
|
||||
#define PATH_FREEZER /obj/machinery/atmospherics/components/unary/thermomachine/freezer
|
||||
#define PATH_HEATER /obj/machinery/atmospherics/components/unary/thermomachine/heater
|
||||
|
||||
/obj/item/circuitboard/machine/thermomachine/Initialize()
|
||||
. = ..()
|
||||
if(!build_path)
|
||||
if(prob(50))
|
||||
name = "Freezer (Machine Board)"
|
||||
build_path = PATH_FREEZER
|
||||
else
|
||||
name = "Heater (Machine Board)"
|
||||
build_path = PATH_HEATER
|
||||
|
||||
/obj/item/circuitboard/machine/thermomachine/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/screwdriver))
|
||||
var/obj/item/circuitboard/new_type
|
||||
var/new_setting
|
||||
switch(build_path)
|
||||
if(PATH_FREEZER)
|
||||
new_type = /obj/item/circuitboard/machine/thermomachine/heater
|
||||
new_setting = "Heater"
|
||||
if(PATH_HEATER)
|
||||
new_type = /obj/item/circuitboard/machine/thermomachine/freezer
|
||||
new_setting = "Freezer"
|
||||
name = initial(new_type.name)
|
||||
build_path = initial(new_type.build_path)
|
||||
I.play_tool_sound(src)
|
||||
to_chat(user, "<span class='notice'>You change the circuitboard setting to \"[new_setting]\".</span>")
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/circuitboard/machine/thermomachine/heater
|
||||
name = "Heater (Machine Board)"
|
||||
build_path = PATH_HEATER
|
||||
|
||||
/obj/item/circuitboard/machine/thermomachine/freezer
|
||||
name = "Freezer (Machine Board)"
|
||||
build_path = PATH_FREEZER
|
||||
|
||||
#undef PATH_FREEZER
|
||||
#undef PATH_HEATER
|
||||
|
||||
/obj/item/circuitboard/machine/deep_fryer
|
||||
name = "circuit board (Deep Fryer)"
|
||||
build_path = /obj/machinery/deepfryer
|
||||
req_components = list(/obj/item/stock_parts/micro_laser = 1)
|
||||
needs_anchored = FALSE
|
||||
|
||||
/obj/item/circuitboard/machine/gibber
|
||||
name = "Gibber (Machine Board)"
|
||||
build_path = /obj/machinery/gibber
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/matter_bin = 1,
|
||||
/obj/item/stock_parts/manipulator = 1)
|
||||
needs_anchored = FALSE
|
||||
|
||||
/obj/item/circuitboard/machine/monkey_recycler
|
||||
name = "Monkey Recycler (Machine Board)"
|
||||
build_path = /obj/machinery/monkey_recycler
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/matter_bin = 1,
|
||||
/obj/item/stock_parts/manipulator = 1)
|
||||
needs_anchored = FALSE
|
||||
|
||||
/obj/item/circuitboard/machine/processor
|
||||
name = "Food Processor (Machine Board)"
|
||||
build_path = /obj/machinery/processor
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/matter_bin = 1,
|
||||
/obj/item/stock_parts/manipulator = 1)
|
||||
needs_anchored = FALSE
|
||||
|
||||
/obj/item/circuitboard/machine/processor/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/screwdriver))
|
||||
if(build_path == /obj/machinery/processor)
|
||||
name = "Slime Processor (Machine Board)"
|
||||
build_path = /obj/machinery/processor/slime
|
||||
to_chat(user, "<span class='notice'>Name protocols successfully updated.</span>")
|
||||
else
|
||||
name = "Food Processor (Machine Board)"
|
||||
build_path = /obj/machinery/processor
|
||||
to_chat(user, "<span class='notice'>Defaulting name protocols.</span>")
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/circuitboard/machine/processor/slime
|
||||
name = "Slime Processor (Machine Board)"
|
||||
build_path = /obj/machinery/processor/slime
|
||||
|
||||
/obj/item/circuitboard/machine/smartfridge
|
||||
name = "Smartfridge (Machine Board)"
|
||||
build_path = /obj/machinery/smartfridge
|
||||
req_components = list(/obj/item/stock_parts/matter_bin = 1)
|
||||
var/static/list/fridges_name_paths = list(/obj/machinery/smartfridge = "plant produce",
|
||||
/obj/machinery/smartfridge/food = "food",
|
||||
/obj/machinery/smartfridge/drinks = "drinks",
|
||||
/obj/machinery/smartfridge/extract = "slimes",
|
||||
/obj/machinery/smartfridge/chemistry = "chems",
|
||||
/obj/machinery/smartfridge/chemistry/virology = "viruses",
|
||||
/obj/machinery/smartfridge/disks = "disks")
|
||||
needs_anchored = FALSE
|
||||
|
||||
/obj/item/circuitboard/machine/smartfridge/Initialize(mapload, new_type)
|
||||
if(new_type)
|
||||
build_path = new_type
|
||||
return ..()
|
||||
|
||||
/obj/item/circuitboard/machine/smartfridge/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/screwdriver))
|
||||
var/position = fridges_name_paths.Find(build_path, fridges_name_paths)
|
||||
position = (position == fridges_name_paths.len) ? 1 : (position + 1)
|
||||
build_path = fridges_name_paths[position]
|
||||
to_chat(user, "<span class='notice'>You set the board to [fridges_name_paths[build_path]].</span>")
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/circuitboard/machine/smartfridge/examine(mob/user)
|
||||
..()
|
||||
to_chat(user, "<span class='info'>[src] is set to [fridges_name_paths[build_path]]. You can use a screwdriver to reconfigure it.</span>")
|
||||
|
||||
/obj/item/circuitboard/machine/biogenerator
|
||||
name = "Biogenerator (Machine Board)"
|
||||
build_path = /obj/machinery/biogenerator
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/matter_bin = 1,
|
||||
/obj/item/stock_parts/manipulator = 1,
|
||||
/obj/item/stack/cable_coil = 1,
|
||||
/obj/item/stack/sheet/glass = 1)
|
||||
|
||||
/obj/item/circuitboard/machine/plantgenes
|
||||
name = "Plant DNA Manipulator (Machine Board)"
|
||||
build_path = /obj/machinery/plantgenes
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/manipulator = 1,
|
||||
/obj/item/stock_parts/micro_laser = 1,
|
||||
/obj/item/stack/sheet/glass = 1,
|
||||
/obj/item/stock_parts/scanning_module = 1)
|
||||
|
||||
/obj/item/circuitboard/machine/plantgenes/vault
|
||||
name = "alien board (Plant DNA Manipulator)"
|
||||
icon_state = "abductor_mod"
|
||||
// It wasn't made by actual abductors race, so no abductor tech here.
|
||||
def_components = list(
|
||||
/obj/item/stock_parts/manipulator = /obj/item/stock_parts/manipulator/femto,
|
||||
/obj/item/stock_parts/micro_laser = /obj/item/stock_parts/micro_laser/quadultra,
|
||||
/obj/item/stock_parts/scanning_module = /obj/item/stock_parts/scanning_module/triphasic)
|
||||
|
||||
|
||||
/obj/item/circuitboard/machine/hydroponics
|
||||
name = "Hydroponics Tray (Machine Board)"
|
||||
build_path = /obj/machinery/hydroponics/constructable
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/matter_bin = 2,
|
||||
/obj/item/stock_parts/manipulator = 1,
|
||||
/obj/item/stack/sheet/glass = 1)
|
||||
needs_anchored = FALSE
|
||||
|
||||
/obj/item/circuitboard/machine/seed_extractor
|
||||
name = "Seed Extractor (Machine Board)"
|
||||
build_path = /obj/machinery/seed_extractor
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/matter_bin = 1,
|
||||
/obj/item/stock_parts/manipulator = 1)
|
||||
needs_anchored = FALSE
|
||||
|
||||
/obj/item/circuitboard/machine/ore_redemption
|
||||
name = "Ore Redemption (Machine Board)"
|
||||
build_path = /obj/machinery/mineral/ore_redemption
|
||||
req_components = list(
|
||||
/obj/item/stack/sheet/glass = 1,
|
||||
/obj/item/stock_parts/matter_bin = 1,
|
||||
/obj/item/stock_parts/micro_laser = 1,
|
||||
/obj/item/stock_parts/manipulator = 1,
|
||||
/obj/item/assembly/igniter = 1)
|
||||
needs_anchored = FALSE
|
||||
|
||||
/obj/item/circuitboard/machine/mining_equipment_vendor
|
||||
name = "Mining Equipment Vendor (Machine Board)"
|
||||
build_path = /obj/machinery/mineral/equipment_vendor
|
||||
req_components = list(
|
||||
/obj/item/stack/sheet/glass = 1,
|
||||
/obj/item/stock_parts/matter_bin = 3)
|
||||
|
||||
/obj/item/circuitboard/machine/mining_equipment_vendor/golem
|
||||
name = "Golem Ship Equipment Vendor (Machine Board)"
|
||||
build_path = /obj/machinery/mineral/equipment_vendor/golem
|
||||
|
||||
/obj/item/circuitboard/machine/ntnet_relay
|
||||
name = "NTNet Relay (Machine Board)"
|
||||
build_path = /obj/machinery/ntnet_relay
|
||||
req_components = list(
|
||||
/obj/item/stack/cable_coil = 2,
|
||||
/obj/item/stock_parts/subspace/filter = 1)
|
||||
|
||||
/obj/item/circuitboard/machine/pacman
|
||||
name = "PACMAN-type Generator (Machine Board)"
|
||||
build_path = /obj/machinery/power/port_gen/pacman
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/matter_bin = 1,
|
||||
/obj/item/stock_parts/micro_laser = 1,
|
||||
/obj/item/stack/cable_coil = 2,
|
||||
/obj/item/stock_parts/capacitor = 1)
|
||||
needs_anchored = FALSE
|
||||
|
||||
/obj/item/circuitboard/machine/pacman/super
|
||||
name = "SUPERPACMAN-type Generator (Machine Board)"
|
||||
build_path = /obj/machinery/power/port_gen/pacman/super
|
||||
|
||||
/obj/item/circuitboard/machine/pacman/mrs
|
||||
name = "MRSPACMAN-type Generator (Machine Board)"
|
||||
build_path = /obj/machinery/power/port_gen/pacman/mrs
|
||||
|
||||
/obj/item/circuitboard/machine/rtg
|
||||
name = "RTG (Machine Board)"
|
||||
build_path = /obj/machinery/power/rtg
|
||||
req_components = list(
|
||||
/obj/item/stack/cable_coil = 5,
|
||||
/obj/item/stock_parts/capacitor = 1,
|
||||
/obj/item/stack/sheet/mineral/uranium = 10) // We have no Pu-238, and this is the closest thing to it.
|
||||
|
||||
/obj/item/circuitboard/machine/rtg/advanced
|
||||
name = "Advanced RTG (Machine Board)"
|
||||
build_path = /obj/machinery/power/rtg/advanced
|
||||
req_components = list(
|
||||
/obj/item/stack/cable_coil = 5,
|
||||
/obj/item/stock_parts/capacitor = 1,
|
||||
/obj/item/stock_parts/micro_laser = 1,
|
||||
/obj/item/stack/sheet/mineral/uranium = 10,
|
||||
/obj/item/stack/sheet/mineral/plasma = 5)
|
||||
|
||||
/obj/item/circuitboard/machine/abductor/core
|
||||
name = "alien board (Void Core)"
|
||||
build_path = /obj/machinery/power/rtg/abductor
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/capacitor = 1,
|
||||
/obj/item/stock_parts/micro_laser = 1,
|
||||
/obj/item/stock_parts/cell/infinite/abductor = 1)
|
||||
def_components = list(
|
||||
/obj/item/stock_parts/capacitor = /obj/item/stock_parts/capacitor/quadratic,
|
||||
/obj/item/stock_parts/micro_laser = /obj/item/stock_parts/micro_laser/quadultra)
|
||||
|
||||
/obj/item/circuitboard/machine/emitter
|
||||
name = "Emitter (Machine Board)"
|
||||
build_path = /obj/machinery/power/emitter
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/micro_laser = 1,
|
||||
/obj/item/stock_parts/manipulator = 1)
|
||||
needs_anchored = FALSE
|
||||
|
||||
/obj/item/circuitboard/machine/smes
|
||||
name = "SMES (Machine Board)"
|
||||
build_path = /obj/machinery/power/smes
|
||||
req_components = list(
|
||||
/obj/item/stack/cable_coil = 5,
|
||||
/obj/item/stock_parts/cell = 5,
|
||||
/obj/item/stock_parts/capacitor = 1)
|
||||
def_components = list(/obj/item/stock_parts/cell = /obj/item/stock_parts/cell/high/empty)
|
||||
|
||||
/obj/item/circuitboard/machine/rad_collector
|
||||
name = "Radiation Collector (Machine Board)"
|
||||
build_path = /obj/machinery/power/rad_collector
|
||||
req_components = list(
|
||||
/obj/item/stack/cable_coil = 5,
|
||||
/obj/item/stock_parts/matter_bin = 1,
|
||||
/obj/item/stack/sheet/plasmarglass = 2,
|
||||
/obj/item/stock_parts/capacitor = 1,
|
||||
/obj/item/stock_parts/manipulator = 1)
|
||||
needs_anchored = FALSE
|
||||
|
||||
/obj/item/circuitboard/machine/tesla_coil
|
||||
name = "Tesla Controller (Machine Board)"
|
||||
desc = "You can use a screwdriver to switch between Research and Power Generation."
|
||||
build_path = /obj/machinery/power/tesla_coil
|
||||
req_components = list(/obj/item/stock_parts/capacitor = 1)
|
||||
needs_anchored = FALSE
|
||||
|
||||
#define PATH_POWERCOIL /obj/machinery/power/tesla_coil/power
|
||||
#define PATH_RPCOIL /obj/machinery/power/tesla_coil/research
|
||||
|
||||
/obj/item/circuitboard/machine/tesla_coil/Initialize()
|
||||
. = ..()
|
||||
if(build_path)
|
||||
build_path = PATH_POWERCOIL
|
||||
|
||||
/obj/item/circuitboard/machine/tesla_coil/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/screwdriver))
|
||||
var/obj/item/circuitboard/new_type
|
||||
var/new_setting
|
||||
switch(build_path)
|
||||
if(PATH_POWERCOIL)
|
||||
new_type = /obj/item/circuitboard/machine/tesla_coil/research
|
||||
new_setting = "Research"
|
||||
if(PATH_RPCOIL)
|
||||
new_type = /obj/item/circuitboard/machine/tesla_coil/power
|
||||
new_setting = "Power"
|
||||
name = initial(new_type.name)
|
||||
build_path = initial(new_type.build_path)
|
||||
I.play_tool_sound(src)
|
||||
to_chat(user, "<span class='notice'>You change the circuitboard setting to \"[new_setting]\".</span>")
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/circuitboard/machine/tesla_coil/power
|
||||
name = "Tesla Coil (Machine Board)"
|
||||
build_path = PATH_POWERCOIL
|
||||
|
||||
/obj/item/circuitboard/machine/tesla_coil/research
|
||||
name = "Tesla Corona Researcher (Machine Board)"
|
||||
build_path = PATH_RPCOIL
|
||||
|
||||
#undef PATH_POWERCOIL
|
||||
#undef PATH_RPCOIL
|
||||
|
||||
/obj/item/circuitboard/machine/grounding_rod
|
||||
name = "Grounding Rod (Machine Board)"
|
||||
build_path = /obj/machinery/power/grounding_rod
|
||||
req_components = list(/obj/item/stock_parts/capacitor = 1)
|
||||
needs_anchored = FALSE
|
||||
|
||||
/obj/item/circuitboard/machine/power_compressor
|
||||
name = "Power Compressor (Machine Board)"
|
||||
build_path = /obj/machinery/power/compressor
|
||||
req_components = list(
|
||||
/obj/item/stack/cable_coil = 5,
|
||||
/obj/item/stock_parts/manipulator = 6)
|
||||
|
||||
/obj/item/circuitboard/machine/power_turbine
|
||||
name = "Power Turbine (Machine Board)"
|
||||
build_path = /obj/machinery/power/turbine
|
||||
req_components = list(
|
||||
/obj/item/stack/cable_coil = 5,
|
||||
/obj/item/stock_parts/capacitor = 6)
|
||||
|
||||
/obj/item/circuitboard/machine/chem_dispenser
|
||||
name = "Chem Dispenser (Machine Board)"
|
||||
build_path = /obj/machinery/chem_dispenser
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/matter_bin = 2,
|
||||
/obj/item/stock_parts/capacitor = 1,
|
||||
/obj/item/stock_parts/manipulator = 1,
|
||||
/obj/item/stack/sheet/glass = 1,
|
||||
/obj/item/stock_parts/cell = 1)
|
||||
def_components = list(/obj/item/stock_parts/cell = /obj/item/stock_parts/cell/high)
|
||||
needs_anchored = FALSE
|
||||
|
||||
/obj/item/circuitboard/machine/chem_dispenser/drinks
|
||||
name = "Soda Dispenser (Machine Board)"
|
||||
build_path = /obj/machinery/chem_dispenser/drinks
|
||||
|
||||
/obj/item/circuitboard/machine/chem_dispenser/drinks/beer
|
||||
name = "Booze Dispenser (Machine Board)"
|
||||
build_path = /obj/machinery/chem_dispenser/drinks/beer
|
||||
|
||||
/obj/item/circuitboard/machine/smoke_machine
|
||||
name = "Smoke Machine (Machine Board)"
|
||||
build_path = /obj/machinery/smoke_machine
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/matter_bin = 2,
|
||||
/obj/item/stock_parts/capacitor = 1,
|
||||
/obj/item/stock_parts/manipulator = 1,
|
||||
/obj/item/stack/sheet/glass = 1,
|
||||
/obj/item/stock_parts/cell = 1)
|
||||
needs_anchored = FALSE
|
||||
|
||||
/obj/item/circuitboard/machine/chem_heater
|
||||
name = "Chemical Heater (Machine Board)"
|
||||
build_path = /obj/machinery/chem_heater
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/micro_laser = 1,
|
||||
/obj/item/stack/sheet/glass = 1)
|
||||
|
||||
/obj/item/circuitboard/machine/chem_master
|
||||
name = "ChemMaster 3000 (Machine Board)"
|
||||
build_path = /obj/machinery/chem_master
|
||||
desc = "You can turn the \"mode selection\" dial using a screwdriver."
|
||||
req_components = list(
|
||||
/obj/item/reagent_containers/glass/beaker = 2,
|
||||
/obj/item/stock_parts/manipulator = 1,
|
||||
/obj/item/stack/sheet/glass = 1)
|
||||
needs_anchored = FALSE
|
||||
|
||||
/obj/item/circuitboard/machine/chem_master/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/screwdriver))
|
||||
var/new_name = "ChemMaster"
|
||||
var/new_path = /obj/machinery/chem_master
|
||||
|
||||
if(build_path == /obj/machinery/chem_master)
|
||||
new_name = "CondiMaster"
|
||||
new_path = /obj/machinery/chem_master/condimaster
|
||||
|
||||
build_path = new_path
|
||||
name = "[new_name] 3000 (Machine Board)"
|
||||
to_chat(user, "<span class='notice'>You change the circuit board setting to \"[new_name]\".</span>")
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/circuitboard/machine/reagentgrinder
|
||||
name = "Machine Design (All-In-One Grinder)"
|
||||
build_path = /obj/machinery/reagentgrinder/constructed
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/manipulator = 1)
|
||||
needs_anchored = FALSE
|
||||
|
||||
/obj/item/circuitboard/machine/chem_master/condi
|
||||
name = "CondiMaster 3000 (Machine Board)"
|
||||
build_path = /obj/machinery/chem_master/condimaster
|
||||
|
||||
/obj/item/circuitboard/machine/circuit_imprinter
|
||||
name = "Circuit Imprinter (Machine Board)"
|
||||
build_path = /obj/machinery/rnd/production/circuit_imprinter
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/matter_bin = 1,
|
||||
/obj/item/stock_parts/manipulator = 1,
|
||||
/obj/item/reagent_containers/glass/beaker = 2)
|
||||
|
||||
/obj/item/circuitboard/machine/circuit_imprinter/department
|
||||
name = "Departmental Circuit Imprinter (Machine Board)"
|
||||
build_path = /obj/machinery/rnd/production/circuit_imprinter/department
|
||||
|
||||
/obj/item/circuitboard/machine/circuit_imprinter/department/science
|
||||
name = "Departmental Circuit Imprinter - Science (Machine Board)"
|
||||
build_path = /obj/machinery/rnd/production/circuit_imprinter/department/science
|
||||
|
||||
/obj/item/circuitboard/machine/destructive_analyzer
|
||||
name = "Destructive Analyzer (Machine Board)"
|
||||
build_path = /obj/machinery/rnd/destructive_analyzer
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/scanning_module = 1,
|
||||
/obj/item/stock_parts/manipulator = 1,
|
||||
/obj/item/stock_parts/micro_laser = 1)
|
||||
|
||||
/obj/item/circuitboard/machine/experimentor
|
||||
name = "E.X.P.E.R.I-MENTOR (Machine Board)"
|
||||
build_path = /obj/machinery/rnd/experimentor
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/scanning_module = 1,
|
||||
/obj/item/stock_parts/manipulator = 2,
|
||||
/obj/item/stock_parts/micro_laser = 2)
|
||||
|
||||
/obj/item/circuitboard/machine/nanite_chamber
|
||||
name = "Nanite Chamber (Machine Board)"
|
||||
build_path = /obj/machinery/nanite_chamber
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/scanning_module = 2,
|
||||
/obj/item/stock_parts/micro_laser = 2,
|
||||
/obj/item/stock_parts/manipulator = 1)
|
||||
|
||||
/obj/item/circuitboard/machine/public_nanite_chamber
|
||||
name = "Public Nanite Chamber (Machine Board)"
|
||||
build_path = /obj/machinery/public_nanite_chamber
|
||||
var/cloud_id = 1
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/micro_laser = 2,
|
||||
/obj/item/stock_parts/manipulator = 1)
|
||||
|
||||
/obj/item/circuitboard/machine/public_nanite_chamber/multitool_act(mob/living/user)
|
||||
var/new_cloud = input("Set the public nanite chamber's Cloud ID (1-100).", "Cloud ID", cloud_id) as num|null
|
||||
if(new_cloud == null)
|
||||
return
|
||||
cloud_id = CLAMP(round(new_cloud, 1), 1, 100)
|
||||
|
||||
/obj/item/circuitboard/machine/public_nanite_chamber/examine(mob/user)
|
||||
. = ..()
|
||||
to_chat(user, "Cloud ID is currently set to [cloud_id].")
|
||||
|
||||
/obj/item/circuitboard/machine/nanite_program_hub
|
||||
name = "Nanite Program Hub (Machine Board)"
|
||||
build_path = /obj/machinery/nanite_program_hub
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/matter_bin = 1,
|
||||
/obj/item/stock_parts/manipulator = 1)
|
||||
|
||||
/obj/item/circuitboard/machine/nanite_programmer
|
||||
name = "Nanite Programmer (Machine Board)"
|
||||
build_path = /obj/machinery/nanite_programmer
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/manipulator = 2,
|
||||
/obj/item/stock_parts/micro_laser = 2,
|
||||
/obj/item/stock_parts/scanning_module = 1)
|
||||
|
||||
/obj/item/circuitboard/machine/protolathe
|
||||
name = "Protolathe (Machine Board)"
|
||||
build_path = /obj/machinery/rnd/production/protolathe
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/matter_bin = 2,
|
||||
/obj/item/stock_parts/manipulator = 2,
|
||||
/obj/item/reagent_containers/glass/beaker = 2)
|
||||
|
||||
/obj/item/circuitboard/machine/protolathe/department
|
||||
name = "Departmental Protolathe (Machine Board)"
|
||||
build_path = /obj/machinery/rnd/production/protolathe/department
|
||||
|
||||
/obj/item/circuitboard/machine/protolathe/department/cargo
|
||||
name = "Departmental Protolathe (Machine Board) - Cargo"
|
||||
build_path = /obj/machinery/rnd/production/protolathe/department/cargo
|
||||
|
||||
/obj/item/circuitboard/machine/protolathe/department/engineering
|
||||
name = "Departmental Protolathe (Machine Board) - Engineering"
|
||||
build_path = /obj/machinery/rnd/production/protolathe/department/engineering
|
||||
|
||||
/obj/item/circuitboard/machine/protolathe/department/medical
|
||||
name = "Departmental Protolathe (Machine Board) - Medical"
|
||||
build_path = /obj/machinery/rnd/production/protolathe/department/medical
|
||||
|
||||
/obj/item/circuitboard/machine/protolathe/department/science
|
||||
name = "Departmental Protolathe (Machine Board) - Science"
|
||||
build_path = /obj/machinery/rnd/production/protolathe/department/science
|
||||
|
||||
/obj/item/circuitboard/machine/protolathe/department/security
|
||||
name = "Departmental Protolathe (Machine Board) - Security"
|
||||
build_path = /obj/machinery/rnd/production/protolathe/department/security
|
||||
|
||||
/obj/item/circuitboard/machine/protolathe/department/service
|
||||
name = "Departmental Protolathe - Service (Machine Board)"
|
||||
build_path = /obj/machinery/rnd/production/protolathe/department/service
|
||||
|
||||
/obj/item/circuitboard/machine/techfab
|
||||
name = "\improper Techfab (Machine Board)"
|
||||
build_path = /obj/machinery/rnd/production/techfab
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/matter_bin = 2,
|
||||
/obj/item/stock_parts/manipulator = 2,
|
||||
/obj/item/reagent_containers/glass/beaker = 2)
|
||||
|
||||
/obj/item/circuitboard/machine/techfab/department
|
||||
name = "\improper Departmental Techfab (Machine Board)"
|
||||
build_path = /obj/machinery/rnd/production/techfab/department
|
||||
|
||||
/obj/item/circuitboard/machine/techfab/department/cargo
|
||||
name = "\improper Departmental Techfab (Machine Board) - Cargo"
|
||||
build_path = /obj/machinery/rnd/production/techfab/department/cargo
|
||||
|
||||
/obj/item/circuitboard/machine/techfab/department/engineering
|
||||
name = "\improper Departmental Techfab (Machine Board) - Engineering"
|
||||
build_path = /obj/machinery/rnd/production/techfab/department/engineering
|
||||
|
||||
/obj/item/circuitboard/machine/techfab/department/medical
|
||||
name = "\improper Departmental Techfab (Machine Board) - Medical"
|
||||
build_path = /obj/machinery/rnd/production/techfab/department/medical
|
||||
|
||||
/obj/item/circuitboard/machine/techfab/department/science
|
||||
name = "\improper Departmental Techfab (Machine Board) - Science"
|
||||
build_path = /obj/machinery/rnd/production/techfab/department/science
|
||||
|
||||
/obj/item/circuitboard/machine/techfab/department/security
|
||||
name = "\improper Departmental Techfab (Machine Board) - Security"
|
||||
build_path = /obj/machinery/rnd/production/techfab/department/security
|
||||
|
||||
/obj/item/circuitboard/machine/techfab/department/service
|
||||
name = "\improper Departmental Techfab - Service (Machine Board)"
|
||||
build_path = /obj/machinery/rnd/production/techfab/department/service
|
||||
|
||||
/obj/item/circuitboard/machine/rdserver
|
||||
name = "R&D Server (Machine Board)"
|
||||
build_path = /obj/machinery/rnd/server
|
||||
req_components = list(
|
||||
/obj/item/stack/cable_coil = 2,
|
||||
/obj/item/stock_parts/scanning_module = 1)
|
||||
|
||||
/obj/item/circuitboard/machine/bsa/back
|
||||
name = "Bluespace Artillery Generator (Machine Board)"
|
||||
build_path = /obj/machinery/bsa/back //No freebies!
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/capacitor/quadratic = 5,
|
||||
/obj/item/stack/cable_coil = 2)
|
||||
|
||||
/obj/item/circuitboard/machine/bsa/middle
|
||||
name = "Bluespace Artillery Fusor (Machine Board)"
|
||||
build_path = /obj/machinery/bsa/middle
|
||||
req_components = list(
|
||||
/obj/item/stack/ore/bluespace_crystal = 20,
|
||||
/obj/item/stack/cable_coil = 2)
|
||||
|
||||
/obj/item/circuitboard/machine/bsa/front
|
||||
name = "Bluespace Artillery Bore (Machine Board)"
|
||||
build_path = /obj/machinery/bsa/front
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/manipulator/femto = 5,
|
||||
/obj/item/stack/cable_coil = 2)
|
||||
|
||||
/obj/item/circuitboard/machine/dna_vault
|
||||
name = "DNA Vault (Machine Board)"
|
||||
build_path = /obj/machinery/dna_vault //No freebies!
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/capacitor/super = 5,
|
||||
/obj/item/stock_parts/manipulator/pico = 5,
|
||||
/obj/item/stack/cable_coil = 2)
|
||||
|
||||
/obj/item/circuitboard/machine/microwave
|
||||
name = "Microwave (Machine Board)"
|
||||
build_path = /obj/machinery/microwave
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/micro_laser = 1,
|
||||
/obj/item/stock_parts/matter_bin = 1,
|
||||
/obj/item/stack/cable_coil = 2,
|
||||
/obj/item/stack/sheet/glass = 2)
|
||||
needs_anchored = FALSE
|
||||
|
||||
/obj/item/circuitboard/machine/vending/donksofttoyvendor
|
||||
name = "Donksoft Toy Vendor (Machine Board)"
|
||||
build_path = /obj/machinery/vending/donksofttoyvendor
|
||||
req_components = list(
|
||||
/obj/item/stack/sheet/glass = 1,
|
||||
/obj/item/vending_refill/donksoft = 1)
|
||||
|
||||
/obj/item/circuitboard/machine/vending/syndicatedonksofttoyvendor
|
||||
name = "Syndicate Donksoft Toy Vendor (Machine Board)"
|
||||
build_path = /obj/machinery/vending/toyliberationstation
|
||||
req_components = list(
|
||||
/obj/item/stack/sheet/glass = 1,
|
||||
/obj/item/vending_refill/donksoft = 1)
|
||||
|
||||
/obj/item/circuitboard/machine/dish_drive
|
||||
name = "Dish Drive (Machine Board)"
|
||||
build_path = /obj/machinery/dish_drive
|
||||
req_components = list(
|
||||
/obj/item/stack/sheet/glass = 1,
|
||||
/obj/item/stock_parts/manipulator = 1,
|
||||
/obj/item/stock_parts/matter_bin = 2)
|
||||
var/suction = TRUE
|
||||
var/transmit = TRUE
|
||||
needs_anchored = FALSE
|
||||
|
||||
/obj/item/circuitboard/machine/dish_drive/examine(mob/user)
|
||||
..()
|
||||
to_chat(user, "<span class='notice'>Its suction function is [suction ? "enabled" : "disabled"]. Use it in-hand to switch.</span>")
|
||||
to_chat(user, "<span class='notice'>Its disposal auto-transmit function is [transmit ? "enabled" : "disabled"]. Alt-click it to switch.</span>")
|
||||
|
||||
/obj/item/circuitboard/machine/dish_drive/attack_self(mob/living/user)
|
||||
suction = !suction
|
||||
to_chat(user, "<span class='notice'>You [suction ? "enable" : "disable"] the board's suction function.</span>")
|
||||
|
||||
/obj/item/circuitboard/machine/dish_drive/AltClick(mob/living/user)
|
||||
if(!user.Adjacent(src))
|
||||
return
|
||||
transmit = !transmit
|
||||
to_chat(user, "<span class='notice'>You [transmit ? "enable" : "disable"] the board's automatic disposal transmission.</span>")
|
||||
|
||||
/obj/item/circuitboard/machine/stacking_unit_console
|
||||
name = "Stacking Machine Console (Machine Board)"
|
||||
build_path = /obj/machinery/mineral/stacking_unit_console
|
||||
req_components = list(
|
||||
/obj/item/stack/sheet/glass = 2,
|
||||
/obj/item/stack/cable_coil = 5)
|
||||
|
||||
/obj/item/circuitboard/machine/stacking_machine
|
||||
name = "Stacking Machine (Machine Board)"
|
||||
build_path = /obj/machinery/mineral/stacking_machine
|
||||
req_components = list(
|
||||
/obj/item/stock_parts/manipulator = 2,
|
||||
/obj/item/stock_parts/matter_bin = 2)
|
||||
|
||||
/obj/item/circuitboard/machine/generator
|
||||
name = "Thermo-Electric Generator (Machine Board)"
|
||||
build_path = /obj/machinery/power/generator
|
||||
req_components = list()
|
||||
|
||||
/obj/item/circuitboard/machine/circulator
|
||||
name = "Circulator/Heat Exchanger (Machine Board)"
|
||||
build_path = /obj/machinery/atmospherics/components/binary/circulator
|
||||
req_components = list()
|
||||
|
||||
/obj/item/circuitboard/machine/harvester
|
||||
name = "Harvester (Machine Board)"
|
||||
build_path = /obj/machinery/harvester
|
||||
req_components = list(/obj/item/stock_parts/micro_laser = 4)
|
||||
|
||||
/obj/item/circuitboard/machine/ore_silo
|
||||
name = "Ore Silo (Machine Board)"
|
||||
build_path = /obj/machinery/ore_silo
|
||||
req_components = list()
|
||||
@@ -0,0 +1,171 @@
|
||||
/* Clown Items
|
||||
* Contains:
|
||||
* Soap
|
||||
* Bike Horns
|
||||
* Air Horns
|
||||
* Canned Laughter
|
||||
*/
|
||||
|
||||
/*
|
||||
* Soap
|
||||
*/
|
||||
|
||||
/obj/item/soap
|
||||
name = "soap"
|
||||
desc = "A cheap bar of soap. Doesn't smell."
|
||||
gender = PLURAL
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "soap"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/custodial_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/custodial_righthand.dmi'
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
item_flags = NOBLUDGEON
|
||||
throwforce = 0
|
||||
throw_speed = 3
|
||||
throw_range = 7
|
||||
grind_results = list("lye" = 10)
|
||||
var/cleanspeed = 50 //slower than mop
|
||||
force_string = "robust... against germs"
|
||||
|
||||
/obj/item/soap/Initialize()
|
||||
. = ..()
|
||||
AddComponent(/datum/component/slippery, 80)
|
||||
|
||||
/obj/item/soap/nanotrasen
|
||||
desc = "A Nanotrasen brand bar of soap. Smells of plasma."
|
||||
icon_state = "soapnt"
|
||||
|
||||
/obj/item/soap/homemade
|
||||
desc = "A homemade bar of soap. Smells of... well...."
|
||||
icon_state = "soapgibs"
|
||||
cleanspeed = 45 // a little faster to reward chemists for going to the effort
|
||||
|
||||
/obj/item/soap/deluxe
|
||||
desc = "A deluxe Waffle Co. brand bar of soap. Smells of high-class luxury."
|
||||
icon_state = "soapdeluxe"
|
||||
cleanspeed = 40 //same speed as mop because deluxe -- captain gets one of these
|
||||
|
||||
/obj/item/soap/syndie
|
||||
desc = "An untrustworthy bar of soap made of strong chemical agents that dissolve blood faster."
|
||||
icon_state = "soapsyndie"
|
||||
cleanspeed = 10 //much faster than mop so it is useful for traitors who want to clean crime scenes
|
||||
|
||||
/obj/item/soap/suicide_act(mob/user)
|
||||
user.say(";FFFFFFFFFFFFFFFFUUUUUUUDGE!!", forced="soap suicide")
|
||||
user.visible_message("<span class='suicide'>[user] lifts [src] to [user.p_their()] mouth and gnaws on it furiously, producing a thick froth! [user.p_they(TRUE)]'ll never get that BB gun now!</span>")
|
||||
new /obj/effect/particle_effect/foam(loc)
|
||||
return (TOXLOSS)
|
||||
|
||||
/obj/item/soap/afterattack(atom/target, mob/user, proximity)
|
||||
. = ..()
|
||||
if(!proximity || !check_allowed_items(target))
|
||||
return
|
||||
//I couldn't feasibly fix the overlay bugs caused by cleaning items we are wearing.
|
||||
//So this is a workaround. This also makes more sense from an IC standpoint. ~Carn
|
||||
if(user.client && ((target in user.client.screen) && !user.is_holding(target)))
|
||||
to_chat(user, "<span class='warning'>You need to take that [target.name] off before cleaning it!</span>")
|
||||
else if(istype(target, /obj/effect/decal/cleanable))
|
||||
user.visible_message("[user] begins to scrub \the [target.name] out with [src].", "<span class='warning'>You begin to scrub \the [target.name] out with [src]...</span>")
|
||||
if(do_after(user, src.cleanspeed, target = target))
|
||||
to_chat(user, "<span class='notice'>You scrub \the [target.name] out.</span>")
|
||||
qdel(target)
|
||||
else if(ishuman(target) && user.zone_selected == BODY_ZONE_PRECISE_MOUTH)
|
||||
var/mob/living/carbon/human/H = user
|
||||
user.visible_message("<span class='warning'>\the [user] washes \the [target]'s mouth out with [src.name]!</span>", "<span class='notice'>You wash \the [target]'s mouth out with [src.name]!</span>") //washes mouth out with soap sounds better than 'the soap' here
|
||||
H.lip_style = null //removes lipstick
|
||||
H.update_body()
|
||||
return
|
||||
else if(istype(target, /obj/structure/window))
|
||||
user.visible_message("[user] begins to clean \the [target.name] with [src]...", "<span class='notice'>You begin to clean \the [target.name] with [src]...</span>")
|
||||
if(do_after(user, src.cleanspeed, target = target))
|
||||
to_chat(user, "<span class='notice'>You clean \the [target.name].</span>")
|
||||
target.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
|
||||
target.set_opacity(initial(target.opacity))
|
||||
else
|
||||
user.visible_message("[user] begins to clean \the [target.name] with [src]...", "<span class='notice'>You begin to clean \the [target.name] with [src]...</span>")
|
||||
if(do_after(user, src.cleanspeed, target = target))
|
||||
to_chat(user, "<span class='notice'>You clean \the [target.name].</span>")
|
||||
var/obj/effect/decal/cleanable/C = locate() in target
|
||||
qdel(C)
|
||||
target.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
|
||||
SEND_SIGNAL(target, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_MEDIUM)
|
||||
target.wash_cream()
|
||||
return
|
||||
|
||||
|
||||
/*
|
||||
* Bike Horns
|
||||
*/
|
||||
|
||||
/obj/item/bikehorn
|
||||
name = "bike horn"
|
||||
desc = "A horn off of a bicycle."
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "bike_horn"
|
||||
item_state = "bike_horn"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/horns_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/horns_righthand.dmi'
|
||||
throwforce = 0
|
||||
hitsound = null //To prevent tap.ogg playing, as the item lacks of force
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
throw_speed = 3
|
||||
throw_range = 7
|
||||
attack_verb = list("HONKED")
|
||||
|
||||
/obj/item/bikehorn/Initialize()
|
||||
. = ..()
|
||||
AddComponent(/datum/component/squeak, list('sound/items/bikehorn.ogg'=1), 50)
|
||||
|
||||
/obj/item/bikehorn/attack(mob/living/carbon/M, mob/living/carbon/user)
|
||||
SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "honk", /datum/mood_event/honk)
|
||||
return ..()
|
||||
|
||||
/obj/item/bikehorn/suicide_act(mob/user)
|
||||
user.visible_message("<span class='suicide'>[user] solemnly points the horn at [user.p_their()] temple! It looks like [user.p_theyre()] trying to commit suicide!</span>")
|
||||
playsound(src, 'sound/items/bikehorn.ogg', 50, 1)
|
||||
return (BRUTELOSS)
|
||||
|
||||
//air horn
|
||||
/obj/item/bikehorn/airhorn
|
||||
name = "air horn"
|
||||
desc = "Damn son, where'd you find this?"
|
||||
icon_state = "air_horn"
|
||||
|
||||
/obj/item/bikehorn/airhorn/Initialize()
|
||||
. = ..()
|
||||
AddComponent(/datum/component/squeak, list('sound/items/airhorn2.ogg'=1), 50)
|
||||
|
||||
//golden bikehorn
|
||||
/obj/item/bikehorn/golden
|
||||
name = "golden bike horn"
|
||||
desc = "Golden? Clearly, it's made with bananium! Honk!"
|
||||
icon_state = "gold_horn"
|
||||
item_state = "gold_horn"
|
||||
var/flip_cooldown = 0
|
||||
|
||||
/obj/item/bikehorn/golden/attack()
|
||||
if(flip_cooldown < world.time)
|
||||
flip_mobs()
|
||||
return ..()
|
||||
|
||||
/obj/item/bikehorn/golden/attack_self(mob/user)
|
||||
if(flip_cooldown < world.time)
|
||||
flip_mobs()
|
||||
..()
|
||||
|
||||
/obj/item/bikehorn/golden/proc/flip_mobs(mob/living/carbon/M, mob/user)
|
||||
var/turf/T = get_turf(src)
|
||||
for(M in ohearers(7, T))
|
||||
if(ishuman(M) && M.can_hear())
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(istype(H.ears, /obj/item/clothing/ears/earmuffs))
|
||||
continue
|
||||
M.emote("flip")
|
||||
flip_cooldown = world.time + 7
|
||||
|
||||
//canned laughter
|
||||
/obj/item/reagent_containers/food/drinks/soda_cans/canned_laughter
|
||||
name = "Canned Laughter"
|
||||
desc = "Just looking at this makes you want to giggle."
|
||||
icon_state = "laughter"
|
||||
list_reagents = list("laughter" = 50)
|
||||
@@ -0,0 +1,103 @@
|
||||
#define WAND_OPEN "Open Door"
|
||||
#define WAND_BOLT "Toggle Bolts"
|
||||
#define WAND_EMERGENCY "Toggle Emergency Access"
|
||||
|
||||
/obj/item/door_remote
|
||||
icon_state = "gangtool-white"
|
||||
item_state = "electronic"
|
||||
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
|
||||
icon = 'icons/obj/device.dmi'
|
||||
name = "control wand"
|
||||
desc = "Remotely controls airlocks."
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
var/mode = WAND_OPEN
|
||||
var/region_access = 1 //See access.dm
|
||||
var/list/access_list
|
||||
|
||||
/obj/item/door_remote/Initialize()
|
||||
. = ..()
|
||||
access_list = get_region_accesses(region_access)
|
||||
AddComponent(/datum/component/ntnet_interface)
|
||||
|
||||
/obj/item/door_remote/attack_self(mob/user)
|
||||
switch(mode)
|
||||
if(WAND_OPEN)
|
||||
mode = WAND_BOLT
|
||||
if(WAND_BOLT)
|
||||
mode = WAND_EMERGENCY
|
||||
if(WAND_EMERGENCY)
|
||||
mode = WAND_OPEN
|
||||
to_chat(user, "Now in mode: [mode].")
|
||||
|
||||
// Airlock remote works by sending NTNet packets to whatever it's pointed at.
|
||||
/obj/item/door_remote/afterattack(atom/A, mob/user)
|
||||
. = ..()
|
||||
GET_COMPONENT_FROM(target_interface, /datum/component/ntnet_interface, A)
|
||||
|
||||
if(!target_interface)
|
||||
return
|
||||
|
||||
// Generate a control packet.
|
||||
var/datum/netdata/data = new
|
||||
data.recipient_ids = list(target_interface.hardware_id)
|
||||
|
||||
switch(mode)
|
||||
if(WAND_OPEN)
|
||||
data.data["data"] = "open"
|
||||
if(WAND_BOLT)
|
||||
data.data["data"] = "bolt"
|
||||
if(WAND_EMERGENCY)
|
||||
data.data["data"] = "emergency"
|
||||
|
||||
data.data["data_secondary"] = "toggle"
|
||||
data.passkey = access_list
|
||||
|
||||
ntnet_send(data)
|
||||
|
||||
|
||||
/obj/item/door_remote/omni
|
||||
name = "omni door remote"
|
||||
desc = "This control wand can access any door on the station."
|
||||
icon_state = "gangtool-yellow"
|
||||
region_access = 0
|
||||
|
||||
/obj/item/door_remote/captain
|
||||
name = "command door remote"
|
||||
icon_state = "gangtool-yellow"
|
||||
region_access = 7
|
||||
|
||||
/obj/item/door_remote/chief_engineer
|
||||
name = "engineering door remote"
|
||||
icon_state = "gangtool-orange"
|
||||
region_access = 5
|
||||
|
||||
/obj/item/door_remote/research_director
|
||||
name = "research door remote"
|
||||
icon_state = "gangtool-purple"
|
||||
region_access = 4
|
||||
|
||||
/obj/item/door_remote/head_of_security
|
||||
name = "security door remote"
|
||||
icon_state = "gangtool-red"
|
||||
region_access = 2
|
||||
|
||||
/obj/item/door_remote/quartermaster
|
||||
name = "supply door remote"
|
||||
desc = "Remotely controls airlocks. This remote has additional Vault access."
|
||||
icon_state = "gangtool-green"
|
||||
region_access = 6
|
||||
|
||||
/obj/item/door_remote/chief_medical_officer
|
||||
name = "medical door remote"
|
||||
icon_state = "gangtool-blue"
|
||||
region_access = 3
|
||||
|
||||
/obj/item/door_remote/civillian
|
||||
name = "civilian door remote"
|
||||
icon_state = "gangtool-white"
|
||||
region_access = 1
|
||||
|
||||
#undef WAND_OPEN
|
||||
#undef WAND_BOLT
|
||||
#undef WAND_EMERGENCY
|
||||
@@ -0,0 +1,191 @@
|
||||
/obj/item/lipstick
|
||||
gender = PLURAL
|
||||
name = "red lipstick"
|
||||
desc = "A generic brand of lipstick."
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "lipstick"
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
var/colour = "red"
|
||||
var/open = FALSE
|
||||
|
||||
/obj/item/lipstick/purple
|
||||
name = "purple lipstick"
|
||||
colour = "purple"
|
||||
|
||||
/obj/item/lipstick/jade
|
||||
//It's still called Jade, but theres no HTML color for jade, so we use lime.
|
||||
name = "jade lipstick"
|
||||
colour = "lime"
|
||||
|
||||
/obj/item/lipstick/black
|
||||
name = "black lipstick"
|
||||
colour = "black"
|
||||
|
||||
/obj/item/lipstick/random
|
||||
name = "lipstick"
|
||||
icon_state = "random_lipstick"
|
||||
|
||||
/obj/item/lipstick/random/New()
|
||||
..()
|
||||
icon_state = "lipstick"
|
||||
colour = pick("red","purple","lime","black","green","blue","white")
|
||||
name = "[colour] lipstick"
|
||||
|
||||
/obj/item/lipstick/attack_self(mob/user)
|
||||
cut_overlays()
|
||||
to_chat(user, "<span class='notice'>You twist \the [src] [open ? "closed" : "open"].</span>")
|
||||
open = !open
|
||||
if(open)
|
||||
var/mutable_appearance/colored_overlay = mutable_appearance(icon, "lipstick_uncap_color")
|
||||
colored_overlay.color = colour
|
||||
icon_state = "lipstick_uncap"
|
||||
add_overlay(colored_overlay)
|
||||
else
|
||||
icon_state = "lipstick"
|
||||
|
||||
/obj/item/lipstick/attack(mob/M, mob/user)
|
||||
if(!open)
|
||||
return
|
||||
|
||||
if(!ismob(M))
|
||||
return
|
||||
|
||||
if(ishuman(M))
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(H.is_mouth_covered())
|
||||
to_chat(user, "<span class='warning'>Remove [ H == user ? "your" : "[H.p_their()]" ] mask!</span>")
|
||||
return
|
||||
if(H.lip_style) //if they already have lipstick on
|
||||
to_chat(user, "<span class='warning'>You need to wipe off the old lipstick first!</span>")
|
||||
return
|
||||
if(H == user)
|
||||
user.visible_message("<span class='notice'>[user] does [user.p_their()] lips with \the [src].</span>", \
|
||||
"<span class='notice'>You take a moment to apply \the [src]. Perfect!</span>")
|
||||
H.lip_style = "lipstick"
|
||||
H.lip_color = colour
|
||||
H.update_body()
|
||||
else
|
||||
user.visible_message("<span class='warning'>[user] begins to do [H]'s lips with \the [src].</span>", \
|
||||
"<span class='notice'>You begin to apply \the [src] on [H]'s lips...</span>")
|
||||
if(do_after(user, 20, target = H))
|
||||
user.visible_message("[user] does [H]'s lips with \the [src].", \
|
||||
"<span class='notice'>You apply \the [src] on [H]'s lips.</span>")
|
||||
H.lip_style = "lipstick"
|
||||
H.lip_color = colour
|
||||
H.update_body()
|
||||
else
|
||||
to_chat(user, "<span class='warning'>Where are the lips on that?</span>")
|
||||
|
||||
//you can wipe off lipstick with paper!
|
||||
/obj/item/paper/attack(mob/M, mob/user)
|
||||
if(user.zone_selected == BODY_ZONE_PRECISE_MOUTH)
|
||||
if(!ismob(M))
|
||||
return
|
||||
|
||||
if(ishuman(M))
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(H == user)
|
||||
to_chat(user, "<span class='notice'>You wipe off the lipstick with [src].</span>")
|
||||
H.lip_style = null
|
||||
H.update_body()
|
||||
else
|
||||
user.visible_message("<span class='warning'>[user] begins to wipe [H]'s lipstick off with \the [src].</span>", \
|
||||
"<span class='notice'>You begin to wipe off [H]'s lipstick...</span>")
|
||||
if(do_after(user, 10, target = H))
|
||||
user.visible_message("[user] wipes [H]'s lipstick off with \the [src].", \
|
||||
"<span class='notice'>You wipe off [H]'s lipstick.</span>")
|
||||
H.lip_style = null
|
||||
H.update_body()
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/item/razor
|
||||
name = "electric razor"
|
||||
desc = "The latest and greatest power razor born from the science of shaving."
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "razor"
|
||||
flags_1 = CONDUCT_1
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
|
||||
/obj/item/razor/suicide_act(mob/living/carbon/user)
|
||||
user.visible_message("<span class='suicide'>[user] begins shaving [user.p_them()]self without the razor guard! It looks like [user.p_theyre()] trying to commit suicide!</span>")
|
||||
shave(user, BODY_ZONE_PRECISE_MOUTH)
|
||||
shave(user, BODY_ZONE_HEAD)//doesnt need to be BODY_ZONE_HEAD specifically, but whatever
|
||||
return BRUTELOSS
|
||||
|
||||
/obj/item/razor/proc/shave(mob/living/carbon/human/H, location = BODY_ZONE_PRECISE_MOUTH)
|
||||
if(location == BODY_ZONE_PRECISE_MOUTH)
|
||||
H.facial_hair_style = "Shaved"
|
||||
else
|
||||
H.hair_style = "Skinhead"
|
||||
|
||||
H.update_hair()
|
||||
playsound(loc, 'sound/items/welder2.ogg', 20, 1)
|
||||
|
||||
|
||||
/obj/item/razor/attack(mob/M, mob/user)
|
||||
if(ishuman(M))
|
||||
var/mob/living/carbon/human/H = M
|
||||
var/location = user.zone_selected
|
||||
if((location in list(BODY_ZONE_PRECISE_EYES, BODY_ZONE_PRECISE_MOUTH, BODY_ZONE_HEAD)) && !H.get_bodypart(BODY_ZONE_HEAD))
|
||||
to_chat(user, "<span class='warning'>[H] doesn't have a head!</span>")
|
||||
return
|
||||
if(location == BODY_ZONE_PRECISE_MOUTH)
|
||||
if(!(FACEHAIR in H.dna.species.species_traits))
|
||||
to_chat(user, "<span class='warning'>There is no facial hair to shave!</span>")
|
||||
return
|
||||
if(!get_location_accessible(H, location))
|
||||
to_chat(user, "<span class='warning'>The mask is in the way!</span>")
|
||||
return
|
||||
if(H.facial_hair_style == "Shaved")
|
||||
to_chat(user, "<span class='warning'>Already clean-shaven!</span>")
|
||||
return
|
||||
|
||||
if(H == user) //shaving yourself
|
||||
user.visible_message("[user] starts to shave [user.p_their()] facial hair with [src].", \
|
||||
"<span class='notice'>You take a moment to shave your facial hair with [src]...</span>")
|
||||
if(do_after(user, 50, target = H))
|
||||
user.visible_message("[user] shaves [user.p_their()] facial hair clean with [src].", \
|
||||
"<span class='notice'>You finish shaving with [src]. Fast and clean!</span>")
|
||||
shave(H, location)
|
||||
else
|
||||
var/turf/H_loc = H.loc
|
||||
user.visible_message("<span class='warning'>[user] tries to shave [H]'s facial hair with [src].</span>", \
|
||||
"<span class='notice'>You start shaving [H]'s facial hair...</span>")
|
||||
if(do_after(user, 50, target = H))
|
||||
if(H_loc == H.loc)
|
||||
user.visible_message("<span class='warning'>[user] shaves off [H]'s facial hair with [src].</span>", \
|
||||
"<span class='notice'>You shave [H]'s facial hair clean off.</span>")
|
||||
shave(H, location)
|
||||
|
||||
else if(location == BODY_ZONE_HEAD)
|
||||
if(!(HAIR in H.dna.species.species_traits))
|
||||
to_chat(user, "<span class='warning'>There is no hair to shave!</span>")
|
||||
return
|
||||
if(!get_location_accessible(H, location))
|
||||
to_chat(user, "<span class='warning'>The headgear is in the way!</span>")
|
||||
return
|
||||
if(H.hair_style == "Bald" || H.hair_style == "Balding Hair" || H.hair_style == "Skinhead")
|
||||
to_chat(user, "<span class='warning'>There is not enough hair left to shave!</span>")
|
||||
return
|
||||
|
||||
if(H == user) //shaving yourself
|
||||
user.visible_message("[user] starts to shave [user.p_their()] head with [src].", \
|
||||
"<span class='notice'>You start to shave your head with [src]...</span>")
|
||||
if(do_after(user, 5, target = H))
|
||||
user.visible_message("[user] shaves [user.p_their()] head with [src].", \
|
||||
"<span class='notice'>You finish shaving with [src].</span>")
|
||||
shave(H, location)
|
||||
else
|
||||
var/turf/H_loc = H.loc
|
||||
user.visible_message("<span class='warning'>[user] tries to shave [H]'s head with [src]!</span>", \
|
||||
"<span class='notice'>You start shaving [H]'s head...</span>")
|
||||
if(do_after(user, 50, target = H))
|
||||
if(H_loc == H.loc)
|
||||
user.visible_message("<span class='warning'>[user] shaves [H]'s head bald with [src]!</span>", \
|
||||
"<span class='notice'>You shave [H]'s head bald.</span>")
|
||||
shave(H, location)
|
||||
else
|
||||
..()
|
||||
else
|
||||
..()
|
||||
@@ -0,0 +1,37 @@
|
||||
// Contains:
|
||||
// Gavel Hammer
|
||||
// Gavel Block
|
||||
|
||||
/obj/item/gavelhammer
|
||||
name = "gavel hammer"
|
||||
desc = "Order, order! No bombs in my courthouse."
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "gavelhammer"
|
||||
force = 5
|
||||
throwforce = 6
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
attack_verb = list("bashed", "battered", "judged", "whacked")
|
||||
resistance_flags = FLAMMABLE
|
||||
|
||||
/obj/item/gavelhammer/suicide_act(mob/user)
|
||||
user.visible_message("<span class='suicide'>[user] has sentenced [user.p_them()]self to death with [src]! It looks like [user.p_theyre()] trying to commit suicide!</span>")
|
||||
playsound(loc, 'sound/items/gavel.ogg', 50, 1, -1)
|
||||
return (BRUTELOSS)
|
||||
|
||||
/obj/item/gavelblock
|
||||
name = "gavel block"
|
||||
desc = "Smack it with a gavel hammer when the assistants get rowdy."
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "gavelblock"
|
||||
force = 2
|
||||
throwforce = 2
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
resistance_flags = FLAMMABLE
|
||||
|
||||
/obj/item/gavelblock/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/gavelhammer))
|
||||
playsound(loc, 'sound/items/gavel.ogg', 100, 1)
|
||||
user.visible_message("<span class='warning'>[user] strikes [src] with [I].</span>")
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
else
|
||||
return ..()
|
||||
@@ -0,0 +1,800 @@
|
||||
#define RANDOM_GRAFFITI "Random Graffiti"
|
||||
#define RANDOM_LETTER "Random Letter"
|
||||
#define RANDOM_NUMBER "Random Number"
|
||||
#define RANDOM_ORIENTED "Random Oriented"
|
||||
#define RANDOM_RUNE "Random Rune"
|
||||
#define RANDOM_ANY "Random Anything"
|
||||
|
||||
#define PAINT_NORMAL 1
|
||||
#define PAINT_LARGE_HORIZONTAL 2
|
||||
#define PAINT_LARGE_HORIZONTAL_ICON 'icons/effects/96x32.dmi'
|
||||
|
||||
/*
|
||||
* Crayons
|
||||
*/
|
||||
|
||||
/obj/item/toy/crayon
|
||||
name = "crayon"
|
||||
desc = "A colourful crayon. Looks tasty. Mmmm..."
|
||||
icon = 'icons/obj/crayons.dmi'
|
||||
icon_state = "crayonred"
|
||||
|
||||
var/icon_capped
|
||||
var/icon_uncapped
|
||||
var/use_overlays = FALSE
|
||||
|
||||
item_color = "red"
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
attack_verb = list("attacked", "coloured")
|
||||
grind_results = list()
|
||||
var/paint_color = "#FF0000" //RGB
|
||||
|
||||
var/drawtype
|
||||
var/text_buffer = ""
|
||||
|
||||
var/list/graffiti = list("amyjon","face","matt","revolution","engie","guy","end","dwarf","uboa","body","cyka","arrow","star","poseur tag","prolizard","antilizard", "tile") //cit edit
|
||||
var/list/letters = list("a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z")
|
||||
var/list/numerals = list("0","1","2","3","4","5","6","7","8","9")
|
||||
var/list/oriented = list("arrow","body") // These turn to face the same way as the drawer
|
||||
var/list/runes = list("rune1","rune2","rune3","rune4","rune5","rune6")
|
||||
var/list/randoms = list(RANDOM_ANY, RANDOM_RUNE, RANDOM_ORIENTED,
|
||||
RANDOM_NUMBER, RANDOM_GRAFFITI, RANDOM_LETTER)
|
||||
var/list/graffiti_large_h = list("yiffhell", "secborg", "paint")
|
||||
|
||||
var/list/all_drawables
|
||||
|
||||
var/paint_mode = PAINT_NORMAL
|
||||
|
||||
var/charges = 30 //-1 or less for unlimited uses
|
||||
var/charges_left
|
||||
var/volume_multiplier = 1 // Increases reagent effect
|
||||
|
||||
var/actually_paints = TRUE
|
||||
|
||||
var/instant = FALSE
|
||||
var/self_contained = TRUE // If it deletes itself when it is empty
|
||||
|
||||
var/list/validSurfaces = list(/turf/open/floor)
|
||||
|
||||
var/edible = TRUE // That doesn't mean eating it is a good idea
|
||||
|
||||
var/list/reagent_contents = list("nutriment" = 1)
|
||||
// If the user can toggle the colour, a la vanilla spraycan
|
||||
var/can_change_colour = FALSE
|
||||
|
||||
var/has_cap = FALSE
|
||||
var/is_capped = FALSE
|
||||
|
||||
var/pre_noise = FALSE
|
||||
var/post_noise = FALSE
|
||||
|
||||
var/datum/team/gang/gang //For marking territory.
|
||||
var/gang_tag_delay = 30 //this is the delay for gang mode tag applications on anything that gang = true on.
|
||||
|
||||
/obj/item/toy/crayon/suicide_act(mob/user)
|
||||
user.visible_message("<span class='suicide'>[user] is jamming [src] up [user.p_their()] nose and into [user.p_their()] brain. It looks like [user.p_theyre()] trying to commit suicide!</span>")
|
||||
return (BRUTELOSS|OXYLOSS)
|
||||
|
||||
/obj/item/toy/crayon/Initialize()
|
||||
. = ..()
|
||||
// Makes crayons identifiable in things like grinders
|
||||
if(name == "crayon")
|
||||
name = "[item_color] crayon"
|
||||
|
||||
all_drawables = graffiti + letters + numerals + oriented + runes + graffiti_large_h
|
||||
drawtype = pick(all_drawables)
|
||||
|
||||
refill()
|
||||
|
||||
/obj/item/toy/crayon/proc/refill()
|
||||
if(charges == -1)
|
||||
charges_left = 100
|
||||
else
|
||||
charges_left = charges
|
||||
|
||||
if(!reagents)
|
||||
create_reagents(charges_left * volume_multiplier)
|
||||
reagents.clear_reagents()
|
||||
|
||||
var/total_weight = 0
|
||||
for(var/key in reagent_contents)
|
||||
total_weight += reagent_contents[key]
|
||||
|
||||
var/units_per_weight = reagents.maximum_volume / total_weight
|
||||
for(var/reagent in reagent_contents)
|
||||
var/weight = reagent_contents[reagent]
|
||||
var/amount = weight * units_per_weight
|
||||
reagents.add_reagent(reagent, amount)
|
||||
|
||||
/obj/item/toy/crayon/proc/use_charges(mob/user, amount = 1, requires_full = TRUE)
|
||||
// Returns number of charges actually used
|
||||
if(charges == -1)
|
||||
. = amount
|
||||
refill()
|
||||
else
|
||||
if(check_empty(user, amount, requires_full))
|
||||
return 0
|
||||
else
|
||||
. = min(charges_left, amount)
|
||||
charges_left -= .
|
||||
|
||||
/obj/item/toy/crayon/proc/check_empty(mob/user, amount = 1, requires_full = TRUE)
|
||||
// When eating a crayon, check_empty() can be called twice producing
|
||||
// two messages unless we check for being deleted first
|
||||
if(QDELETED(src))
|
||||
return TRUE
|
||||
|
||||
. = FALSE
|
||||
// -1 is unlimited charges
|
||||
if(charges == -1)
|
||||
. = FALSE
|
||||
else if(!charges_left)
|
||||
to_chat(user, "<span class='warning'>There is no more of [src] left!</span>")
|
||||
if(self_contained)
|
||||
qdel(src)
|
||||
. = TRUE
|
||||
else if(charges_left < amount && requires_full)
|
||||
to_chat(user, "<span class='warning'>There is not enough of [src] left!</span>")
|
||||
. = TRUE
|
||||
|
||||
/obj/item/toy/crayon/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)
|
||||
// tgui is a plague upon this codebase
|
||||
|
||||
SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "crayon", name, 600, 600,
|
||||
master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/item/toy/crayon/spraycan/AltClick(mob/user)
|
||||
if(user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
|
||||
if(has_cap)
|
||||
is_capped = !is_capped
|
||||
to_chat(user, "<span class='notice'>The cap on [src] is now [is_capped ? "on" : "off"].</span>")
|
||||
update_icon()
|
||||
|
||||
/obj/item/toy/crayon/ui_data()
|
||||
var/list/data = list()
|
||||
data["drawables"] = list()
|
||||
var/list/D = data["drawables"]
|
||||
|
||||
var/list/g_items = list()
|
||||
D += list(list("name" = "Graffiti", "items" = g_items))
|
||||
for(var/g in graffiti)
|
||||
g_items += list(list("item" = g))
|
||||
|
||||
var/list/glh_items = list()
|
||||
D += list(list("name" = "Graffiti Large Horizontal", "items" = glh_items))
|
||||
for(var/glh in graffiti_large_h)
|
||||
glh_items += list(list("item" = glh))
|
||||
|
||||
var/list/L_items = list()
|
||||
D += list(list("name" = "Letters", "items" = L_items))
|
||||
for(var/L in letters)
|
||||
L_items += list(list("item" = L))
|
||||
|
||||
var/list/N_items = list()
|
||||
D += list(list(name = "Numerals", "items" = N_items))
|
||||
for(var/N in numerals)
|
||||
N_items += list(list("item" = N))
|
||||
|
||||
var/list/O_items = list()
|
||||
D += list(list(name = "Oriented", "items" = O_items))
|
||||
for(var/O in oriented)
|
||||
O_items += list(list("item" = O))
|
||||
|
||||
var/list/R_items = list()
|
||||
D += list(list(name = "Runes", "items" = R_items))
|
||||
for(var/R in runes)
|
||||
R_items += list(list("item" = R))
|
||||
|
||||
var/list/rand_items = list()
|
||||
D += list(list(name = "Random", "items" = rand_items))
|
||||
for(var/i in randoms)
|
||||
rand_items += list(list("item" = i))
|
||||
|
||||
data["selected_stencil"] = drawtype
|
||||
data["text_buffer"] = text_buffer
|
||||
|
||||
data["has_cap"] = has_cap
|
||||
data["is_capped"] = is_capped
|
||||
data["can_change_colour"] = can_change_colour
|
||||
data["current_colour"] = paint_color
|
||||
|
||||
return data
|
||||
|
||||
/obj/item/toy/crayon/ui_act(action, list/params)
|
||||
if(..())
|
||||
return
|
||||
switch(action)
|
||||
if("toggle_cap")
|
||||
if(has_cap)
|
||||
is_capped = !is_capped
|
||||
. = TRUE
|
||||
if("select_stencil")
|
||||
var/stencil = params["item"]
|
||||
if(stencil in all_drawables + randoms)
|
||||
drawtype = stencil
|
||||
. = TRUE
|
||||
if(stencil in graffiti_large_h)
|
||||
paint_mode = PAINT_LARGE_HORIZONTAL
|
||||
text_buffer = ""
|
||||
else
|
||||
paint_mode = PAINT_NORMAL
|
||||
if("select_colour")
|
||||
if(can_change_colour)
|
||||
paint_color = input(usr,"","Choose Color",paint_color) as color|null
|
||||
. = TRUE
|
||||
if("enter_text")
|
||||
var/txt = stripped_input(usr,"Choose what to write.",
|
||||
"Scribbles",default = text_buffer)
|
||||
text_buffer = crayon_text_strip(txt)
|
||||
. = TRUE
|
||||
paint_mode = PAINT_NORMAL
|
||||
drawtype = "a"
|
||||
update_icon()
|
||||
|
||||
/obj/item/toy/crayon/proc/crayon_text_strip(text)
|
||||
var/list/base = string2charlist(lowertext(text))
|
||||
var/list/out = list()
|
||||
for(var/a in base)
|
||||
if(a in (letters|numerals))
|
||||
out += a
|
||||
return jointext(out,"")
|
||||
|
||||
/obj/item/toy/crayon/afterattack(atom/target, mob/user, proximity, params)
|
||||
. = ..()
|
||||
if(!proximity || !check_allowed_items(target))
|
||||
return
|
||||
|
||||
var/cost = 1
|
||||
if(paint_mode == PAINT_LARGE_HORIZONTAL)
|
||||
cost = 5
|
||||
if(istype(target, /obj/item/canvas))
|
||||
cost = 0
|
||||
if(ishuman(user))
|
||||
var/mob/living/carbon/human/H = user
|
||||
if (HAS_TRAIT(H, TRAIT_TAGGER))
|
||||
cost *= 0.5
|
||||
var/charges_used = use_charges(user, cost)
|
||||
if(!charges_used)
|
||||
return
|
||||
. = charges_used
|
||||
|
||||
if(istype(target, /obj/effect/decal/cleanable))
|
||||
target = target.loc
|
||||
|
||||
if(!is_type_in_list(target,validSurfaces))
|
||||
return
|
||||
|
||||
var/drawing = drawtype
|
||||
switch(drawtype)
|
||||
if(RANDOM_LETTER)
|
||||
drawing = pick(letters)
|
||||
if(RANDOM_GRAFFITI)
|
||||
drawing = pick(graffiti)
|
||||
if(RANDOM_RUNE)
|
||||
drawing = pick(runes)
|
||||
if(RANDOM_ORIENTED)
|
||||
drawing = pick(oriented)
|
||||
if(RANDOM_NUMBER)
|
||||
drawing = pick(numerals)
|
||||
if(RANDOM_ANY)
|
||||
drawing = pick(all_drawables)
|
||||
|
||||
var/temp = "rune"
|
||||
if(drawing in letters)
|
||||
temp = "letter"
|
||||
else if(drawing in graffiti)
|
||||
temp = "graffiti"
|
||||
else if(drawing in numerals)
|
||||
temp = "number"
|
||||
|
||||
// If a gang member is using a gang spraycan, it'll behave differently
|
||||
var/gang_mode = FALSE
|
||||
if(gang && user.mind && user.mind.has_antag_datum(/datum/antagonist/gang)) //Heres a check.
|
||||
gang_mode = TRUE // No more runtimes if a non-gang member sprays a gang can, it just works like normal cans.
|
||||
// discontinue if the area isn't valid for tagging because gang "honour"
|
||||
if(gang_mode && (!can_claim_for_gang(user, target)))
|
||||
return
|
||||
|
||||
var/graf_rot
|
||||
if(drawing in oriented)
|
||||
switch(user.dir)
|
||||
if(EAST)
|
||||
graf_rot = 90
|
||||
if(SOUTH)
|
||||
graf_rot = 180
|
||||
if(WEST)
|
||||
graf_rot = 270
|
||||
else
|
||||
graf_rot = 0
|
||||
|
||||
var/list/click_params = params2list(params)
|
||||
var/clickx
|
||||
var/clicky
|
||||
|
||||
if(click_params && click_params["icon-x"] && click_params["icon-y"])
|
||||
clickx = CLAMP(text2num(click_params["icon-x"]) - 16, -(world.icon_size/2), world.icon_size/2)
|
||||
clicky = CLAMP(text2num(click_params["icon-y"]) - 16, -(world.icon_size/2), world.icon_size/2)
|
||||
|
||||
if(!instant)
|
||||
to_chat(user, "<span class='notice'>You start drawing a [temp] on the [target.name]...</span>")
|
||||
|
||||
if(pre_noise)
|
||||
audible_message("<span class='notice'>You hear spraying.</span>")
|
||||
playsound(user.loc, 'sound/effects/spray.ogg', 5, 1, 5)
|
||||
|
||||
var/takes_time = !instant //For order purposes, since I'm maximum bad.
|
||||
if(gang_mode)
|
||||
takes_time = TRUE
|
||||
|
||||
var/wait_time = 50
|
||||
if(paint_mode == PAINT_LARGE_HORIZONTAL)
|
||||
wait_time *= 3
|
||||
|
||||
if(takes_time) //This is what deteremines the time it takes to spray a tag in gang mode. 50 is Default.
|
||||
if(!do_after(user, gang_tag_delay, target = target)) //25 is a good number, but we have gang_tag_delay var now.
|
||||
return
|
||||
|
||||
if(length(text_buffer))
|
||||
drawing = copytext(text_buffer,1,2)
|
||||
|
||||
|
||||
var/list/turf/affected_turfs = list()
|
||||
|
||||
|
||||
if(actually_paints)
|
||||
if(gang_mode)
|
||||
// Double check it wasn't tagged in the meanwhile.
|
||||
if(!can_claim_for_gang(user, target))
|
||||
return
|
||||
tag_for_gang(user, target)
|
||||
affected_turfs += target
|
||||
else
|
||||
switch(paint_mode)
|
||||
if(PAINT_NORMAL)
|
||||
var/obj/effect/decal/cleanable/crayon/C = new(target, paint_color, drawing, temp, graf_rot)
|
||||
C.add_hiddenprint(user)
|
||||
C.pixel_x = clickx
|
||||
C.pixel_y = clicky
|
||||
affected_turfs += target
|
||||
if(PAINT_LARGE_HORIZONTAL)
|
||||
var/turf/left = locate(target.x-1,target.y,target.z)
|
||||
var/turf/right = locate(target.x+1,target.y,target.z)
|
||||
if(is_type_in_list(left, validSurfaces) && is_type_in_list(right, validSurfaces))
|
||||
var/obj/effect/decal/cleanable/crayon/C = new(left, paint_color, drawing, temp, graf_rot, PAINT_LARGE_HORIZONTAL_ICON)
|
||||
C.add_hiddenprint(user)
|
||||
affected_turfs += left
|
||||
affected_turfs += right
|
||||
affected_turfs += target
|
||||
else
|
||||
to_chat(user, "<span class='warning'>There isn't enough space to paint!</span>")
|
||||
return
|
||||
|
||||
if(!instant)
|
||||
to_chat(user, "<span class='notice'>You finish drawing \the [temp].</span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You spray a [temp] on \the [target.name]</span>")
|
||||
|
||||
if(length(text_buffer))
|
||||
text_buffer = copytext(text_buffer,2)
|
||||
|
||||
if(post_noise)
|
||||
audible_message("<span class='notice'>You hear spraying.</span>")
|
||||
playsound(user.loc, 'sound/effects/spray.ogg', 5, 1, 5)
|
||||
|
||||
var/fraction = min(1, . / reagents.maximum_volume)
|
||||
if(affected_turfs.len)
|
||||
fraction /= affected_turfs.len
|
||||
for(var/t in affected_turfs)
|
||||
reagents.reaction(t, TOUCH, fraction * volume_multiplier)
|
||||
reagents.trans_to(t, ., volume_multiplier)
|
||||
check_empty(user)
|
||||
|
||||
|
||||
//////////////Gang mode stuff/////////////////
|
||||
/obj/item/toy/crayon/proc/can_claim_for_gang(mob/user, atom/target)
|
||||
// Check area validity.
|
||||
// Reject space, player-created areas, and non-station z-levels.
|
||||
var/area/A = get_area(target)
|
||||
if(!A || (!is_station_level(A.z)) || !A.valid_territory)
|
||||
to_chat(user, "<span class='warning'>[A] is unsuitable for tagging.</span>")
|
||||
return FALSE
|
||||
|
||||
var/spraying_over = FALSE
|
||||
for(var/G in target)
|
||||
var/obj/effect/decal/cleanable/crayon/gang/gangtag = G
|
||||
if(istype(gangtag))
|
||||
var/datum/antagonist/gang/GA = user.mind.has_antag_datum(/datum/antagonist/gang)
|
||||
if(gangtag.gang != GA.gang)
|
||||
spraying_over = TRUE
|
||||
break
|
||||
|
||||
var/occupying_gang = territory_claimed(A, user)
|
||||
if(occupying_gang && !spraying_over)
|
||||
to_chat(user, "<span class='danger'>[A] has already been tagged by the [occupying_gang] gang! You must get rid of or spray over the old tag first!</span>")
|
||||
return FALSE
|
||||
|
||||
// If you pass the gauntlet of checks, you're good to proceed
|
||||
return TRUE
|
||||
|
||||
/obj/item/toy/crayon/proc/territory_claimed(area/territory, mob/user)
|
||||
for(var/datum/team/gang/G in GLOB.gangs)
|
||||
if(territory.type in (G.territories|G.new_territories))
|
||||
. = G.name
|
||||
break
|
||||
|
||||
/obj/item/toy/crayon/proc/tag_for_gang(mob/user, atom/target)
|
||||
//Delete any old markings on this tile, including other gang tags
|
||||
for(var/obj/effect/decal/cleanable/crayon/old_marking in target)
|
||||
qdel(old_marking)
|
||||
|
||||
var/datum/antagonist/gang/G = user.mind.has_antag_datum(/datum/antagonist/gang)
|
||||
var/area/territory = get_area(target)
|
||||
|
||||
new /obj/effect/decal/cleanable/crayon/gang(target,G.gang,"graffiti",0,user) // Heres the gang tag.
|
||||
to_chat(user, "<span class='notice'>You tagged [territory] for your gang!</span>")
|
||||
/////////////////Gang end////////////////////
|
||||
|
||||
|
||||
/obj/item/toy/crayon/attack(mob/M, mob/user)
|
||||
if(edible && (M == user))
|
||||
to_chat(user, "You take a bite of the [src.name]. Delicious!")
|
||||
var/eaten = use_charges(user, 5, FALSE)
|
||||
if(check_empty(user)) //Prevents divsion by zero
|
||||
return
|
||||
var/fraction = min(eaten / reagents.total_volume, 1)
|
||||
reagents.reaction(M, INGEST, fraction * volume_multiplier)
|
||||
reagents.trans_to(M, eaten, volume_multiplier)
|
||||
// check_empty() is called during afterattack
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/item/toy/crayon/red
|
||||
icon_state = "crayonred"
|
||||
paint_color = "#DA0000"
|
||||
item_color = "red"
|
||||
reagent_contents = list("nutriment" = 1, "redcrayonpowder" = 1)
|
||||
|
||||
/obj/item/toy/crayon/orange
|
||||
icon_state = "crayonorange"
|
||||
paint_color = "#FF9300"
|
||||
item_color = "orange"
|
||||
reagent_contents = list("nutriment" = 1, "orangecrayonpowder" = 1)
|
||||
|
||||
/obj/item/toy/crayon/yellow
|
||||
icon_state = "crayonyellow"
|
||||
paint_color = "#FFF200"
|
||||
item_color = "yellow"
|
||||
reagent_contents = list("nutriment" = 1, "yellowcrayonpowder" = 1)
|
||||
|
||||
/obj/item/toy/crayon/green
|
||||
icon_state = "crayongreen"
|
||||
paint_color = "#A8E61D"
|
||||
item_color = "green"
|
||||
reagent_contents = list("nutriment" = 1, "greencrayonpowder" = 1)
|
||||
|
||||
/obj/item/toy/crayon/blue
|
||||
icon_state = "crayonblue"
|
||||
paint_color = "#00B7EF"
|
||||
item_color = "blue"
|
||||
reagent_contents = list("nutriment" = 1, "bluecrayonpowder" = 1)
|
||||
|
||||
/obj/item/toy/crayon/purple
|
||||
icon_state = "crayonpurple"
|
||||
paint_color = "#DA00FF"
|
||||
item_color = "purple"
|
||||
reagent_contents = list("nutriment" = 1, "purplecrayonpowder" = 1)
|
||||
|
||||
/obj/item/toy/crayon/black
|
||||
icon_state = "crayonblack"
|
||||
paint_color = "#1C1C1C" //Not completely black because total black looks bad. So Mostly Black.
|
||||
item_color = "black"
|
||||
reagent_contents = list("nutriment" = 1, "blackcrayonpowder" = 1)
|
||||
|
||||
/obj/item/toy/crayon/white
|
||||
icon_state = "crayonwhite"
|
||||
paint_color = "#FFFFFF"
|
||||
item_color = "white"
|
||||
reagent_contents = list("nutriment" = 1, "whitecrayonpowder" = 1)
|
||||
|
||||
/obj/item/toy/crayon/mime
|
||||
icon_state = "crayonmime"
|
||||
desc = "A very sad-looking crayon."
|
||||
paint_color = "#FFFFFF"
|
||||
item_color = "mime"
|
||||
reagent_contents = list("nutriment" = 1, "invisiblecrayonpowder" = 1)
|
||||
charges = -1
|
||||
|
||||
/obj/item/toy/crayon/rainbow
|
||||
icon_state = "crayonrainbow"
|
||||
paint_color = "#FFF000"
|
||||
item_color = "rainbow"
|
||||
reagent_contents = list("nutriment" = 1, "colorful_reagent" = 1)
|
||||
drawtype = RANDOM_ANY // just the default starter.
|
||||
|
||||
charges = -1
|
||||
|
||||
/obj/item/toy/crayon/rainbow/afterattack(atom/target, mob/user, proximity)
|
||||
paint_color = rgb(rand(0,255), rand(0,255), rand(0,255))
|
||||
. = ..()
|
||||
|
||||
/*
|
||||
* Crayon Box
|
||||
*/
|
||||
|
||||
/obj/item/storage/crayons
|
||||
name = "box of crayons"
|
||||
desc = "A box of crayons for all your rune drawing needs."
|
||||
icon = 'icons/obj/crayons.dmi'
|
||||
icon_state = "crayonbox"
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
|
||||
/obj/item/storage/crayons/Initialize()
|
||||
. = ..()
|
||||
GET_COMPONENT(STR, /datum/component/storage)
|
||||
STR.max_items = 7
|
||||
STR.can_hold = typecacheof(list(/obj/item/toy/crayon))
|
||||
|
||||
/obj/item/storage/crayons/PopulateContents()
|
||||
new /obj/item/toy/crayon/red(src)
|
||||
new /obj/item/toy/crayon/orange(src)
|
||||
new /obj/item/toy/crayon/yellow(src)
|
||||
new /obj/item/toy/crayon/green(src)
|
||||
new /obj/item/toy/crayon/blue(src)
|
||||
new /obj/item/toy/crayon/purple(src)
|
||||
new /obj/item/toy/crayon/black(src)
|
||||
update_icon()
|
||||
|
||||
/obj/item/storage/crayons/update_icon()
|
||||
cut_overlays()
|
||||
for(var/obj/item/toy/crayon/crayon in contents)
|
||||
add_overlay(mutable_appearance('icons/obj/crayons.dmi', crayon.item_color))
|
||||
|
||||
/obj/item/storage/crayons/attackby(obj/item/W, mob/user, params)
|
||||
if(istype(W, /obj/item/toy/crayon))
|
||||
var/obj/item/toy/crayon/C = W
|
||||
switch(C.item_color)
|
||||
if("mime")
|
||||
to_chat(usr, "This crayon is too sad to be contained in this box.")
|
||||
return
|
||||
if("rainbow")
|
||||
to_chat(usr, "This crayon is too powerful to be contained in this box.")
|
||||
return
|
||||
if(istype(W, /obj/item/toy/crayon/spraycan))
|
||||
to_chat(user, "Spraycans are not crayons.")
|
||||
return
|
||||
return ..()
|
||||
|
||||
//Spraycan stuff
|
||||
|
||||
/obj/item/toy/crayon/spraycan
|
||||
name = "spray can"
|
||||
icon_state = "spraycan"
|
||||
|
||||
icon_capped = "spraycan_cap"
|
||||
icon_uncapped = "spraycan"
|
||||
use_overlays = TRUE
|
||||
paint_color = null
|
||||
|
||||
item_state = "spraycan"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/hydroponics_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/hydroponics_righthand.dmi'
|
||||
desc = "A metallic container containing tasty paint."
|
||||
|
||||
instant = TRUE
|
||||
edible = FALSE
|
||||
has_cap = TRUE
|
||||
is_capped = TRUE
|
||||
self_contained = FALSE // Don't disappear when they're empty
|
||||
can_change_colour = TRUE
|
||||
gang = TRUE //Gang check is true for all things upon the honored hierarchy of spraycans, except those that are FALSE.
|
||||
|
||||
validSurfaces = list(/turf/open/floor, /turf/closed/wall)
|
||||
reagent_contents = list("welding_fuel" = 1, "ethanol" = 1)
|
||||
|
||||
pre_noise = TRUE
|
||||
post_noise = FALSE
|
||||
|
||||
/obj/item/toy/crayon/spraycan/suicide_act(mob/user)
|
||||
var/mob/living/carbon/human/H = user
|
||||
if(is_capped || !actually_paints)
|
||||
user.visible_message("<span class='suicide'>[user] shakes up [src] with a rattle and lifts it to [user.p_their()] mouth, but nothing happens!</span>")
|
||||
user.say("MEDIOCRE!!", forced="spraycan suicide")
|
||||
return SHAME
|
||||
else
|
||||
user.visible_message("<span class='suicide'>[user] shakes up [src] with a rattle and lifts it to [user.p_their()] mouth, spraying paint across [user.p_their()] teeth!</span>")
|
||||
user.say("WITNESS ME!!", forced="spraycan suicide")
|
||||
if(pre_noise || post_noise)
|
||||
playsound(loc, 'sound/effects/spray.ogg', 5, 1, 5)
|
||||
if(can_change_colour)
|
||||
paint_color = "#C0C0C0"
|
||||
update_icon()
|
||||
if(actually_paints)
|
||||
H.lip_style = "spray_face"
|
||||
H.lip_color = paint_color
|
||||
H.update_body()
|
||||
var/used = use_charges(user, 10, FALSE)
|
||||
var/fraction = min(1, used / reagents.maximum_volume)
|
||||
reagents.reaction(user, VAPOR, fraction * volume_multiplier)
|
||||
reagents.trans_to(user, used, volume_multiplier)
|
||||
|
||||
return (OXYLOSS)
|
||||
|
||||
/obj/item/toy/crayon/spraycan/New()
|
||||
..()
|
||||
// If default crayon red colour, pick a more fun spraycan colour
|
||||
if(!paint_color)
|
||||
paint_color = pick("#DA0000","#FF9300","#FFF200","#A8E61D","#00B7EF",
|
||||
"#DA00FF")
|
||||
refill()
|
||||
update_icon()
|
||||
|
||||
|
||||
/obj/item/toy/crayon/spraycan/examine(mob/user)
|
||||
. = ..()
|
||||
if(charges_left)
|
||||
to_chat(user, "It has [charges_left] use\s left.")
|
||||
else
|
||||
to_chat(user, "It is empty.")
|
||||
to_chat(user, "<span class='notice'>Alt-click [src] to [ is_capped ? "take the cap off" : "put the cap on"].</span>")
|
||||
|
||||
/obj/item/toy/crayon/spraycan/afterattack(atom/target, mob/user, proximity)
|
||||
if(!proximity)
|
||||
return
|
||||
|
||||
if(is_capped)
|
||||
to_chat(user, "<span class='warning'>Take the cap off first!</span>")
|
||||
return
|
||||
|
||||
if(check_empty(user))
|
||||
return
|
||||
|
||||
if(iscarbon(target))
|
||||
if(pre_noise || post_noise)
|
||||
playsound(user.loc, 'sound/effects/spray.ogg', 25, 1, 5)
|
||||
|
||||
var/mob/living/carbon/C = target
|
||||
user.visible_message("<span class='danger'>[user] sprays [src] into the face of [target]!</span>")
|
||||
to_chat(target, "<span class='userdanger'>[user] sprays [src] into your face!</span>")
|
||||
|
||||
if(C.client)
|
||||
C.blur_eyes(3)
|
||||
C.blind_eyes(1)
|
||||
if(C.get_eye_protection() <= 0) // no eye protection? ARGH IT BURNS.
|
||||
C.confused = max(C.confused, 3)
|
||||
C.Knockdown(60)
|
||||
if(ishuman(C) && actually_paints)
|
||||
var/mob/living/carbon/human/H = C
|
||||
H.lip_style = "spray_face"
|
||||
H.lip_color = paint_color
|
||||
H.update_body()
|
||||
|
||||
// Caution, spray cans contain inflammable substances
|
||||
. = use_charges(user, 10, FALSE)
|
||||
var/fraction = min(1, . / reagents.maximum_volume)
|
||||
reagents.reaction(C, VAPOR, fraction * volume_multiplier)
|
||||
|
||||
return
|
||||
|
||||
if(istype(target, /obj/structure/window))
|
||||
if(actually_paints)
|
||||
target.add_atom_colour(paint_color, WASHABLE_COLOUR_PRIORITY)
|
||||
if(color_hex2num(paint_color) < 255)
|
||||
target.set_opacity(255)
|
||||
else
|
||||
target.set_opacity(initial(target.opacity))
|
||||
. = use_charges(user, 2)
|
||||
var/fraction = min(1, . / reagents.maximum_volume)
|
||||
reagents.reaction(target, TOUCH, fraction * volume_multiplier)
|
||||
reagents.trans_to(target, ., volume_multiplier)
|
||||
|
||||
if(pre_noise || post_noise)
|
||||
playsound(user.loc, 'sound/effects/spray.ogg', 5, 1, 5)
|
||||
return
|
||||
|
||||
. = ..()
|
||||
|
||||
/obj/item/toy/crayon/spraycan/update_icon()
|
||||
icon_state = is_capped ? icon_capped : icon_uncapped
|
||||
if(use_overlays)
|
||||
cut_overlays()
|
||||
var/mutable_appearance/spray_overlay = mutable_appearance('icons/obj/crayons.dmi', "[is_capped ? "spraycan_cap_colors" : "spraycan_colors"]")
|
||||
spray_overlay.color = paint_color
|
||||
add_overlay(spray_overlay)
|
||||
|
||||
/obj/item/toy/crayon/spraycan/borg
|
||||
name = "cyborg spraycan"
|
||||
desc = "A metallic container containing shiny synthesised paint."
|
||||
charges = -1
|
||||
|
||||
/obj/item/toy/crayon/spraycan/borg/afterattack(atom/target,mob/user,proximity)
|
||||
var/diff = ..()
|
||||
if(!iscyborg(user))
|
||||
to_chat(user, "<span class='notice'>How did you get this?</span>")
|
||||
qdel(src)
|
||||
return FALSE
|
||||
|
||||
var/mob/living/silicon/robot/borgy = user
|
||||
|
||||
if(!diff)
|
||||
return
|
||||
// 25 is our cost per unit of paint, making it cost 25 energy per
|
||||
// normal tag, 50 per window, and 250 per attack
|
||||
var/cost = diff * 25
|
||||
// Cyborgs shouldn't be able to use modules without a cell. But if they do
|
||||
// it's free.
|
||||
if(borgy.cell)
|
||||
borgy.cell.use(cost)
|
||||
|
||||
/obj/item/toy/crayon/spraycan/hellcan
|
||||
name = "hellcan"
|
||||
desc = "This spraycan doesn't seem to be filled with paint..."
|
||||
icon_state = "deathcan2_cap"
|
||||
icon_capped = "deathcan2_cap"
|
||||
icon_uncapped = "deathcan2"
|
||||
use_overlays = FALSE
|
||||
gang = FALSE
|
||||
|
||||
volume_multiplier = 25
|
||||
charges = 100
|
||||
reagent_contents = list("clf3" = 1)
|
||||
actually_paints = FALSE
|
||||
paint_color = "#000000"
|
||||
|
||||
/obj/item/toy/crayon/spraycan/lubecan
|
||||
name = "slippery spraycan"
|
||||
desc = "You can barely keep hold of this thing."
|
||||
icon_state = "clowncan2_cap"
|
||||
icon_capped = "clowncan2_cap"
|
||||
icon_uncapped = "clowncan2"
|
||||
use_overlays = FALSE
|
||||
gang = FALSE
|
||||
|
||||
reagent_contents = list("lube" = 1, "banana" = 1)
|
||||
volume_multiplier = 5
|
||||
validSurfaces = list(/turf/open/floor)
|
||||
|
||||
/obj/item/toy/crayon/spraycan/mimecan
|
||||
name = "silent spraycan"
|
||||
desc = "Art is best seen, not heard."
|
||||
icon_state = "mimecan_cap"
|
||||
icon_capped = "mimecan_cap"
|
||||
icon_uncapped = "mimecan"
|
||||
use_overlays = FALSE
|
||||
gang = FALSE
|
||||
|
||||
can_change_colour = FALSE
|
||||
paint_color = "#FFFFFF" //RGB
|
||||
|
||||
pre_noise = FALSE
|
||||
post_noise = FALSE
|
||||
reagent_contents = list("nothing" = 1, "mutetoxin" = 1)
|
||||
|
||||
/obj/item/toy/crayon/spraycan/gang
|
||||
charges = 20 // Charges back to 20, which is the default value for them.
|
||||
gang = TRUE
|
||||
gang_tag_delay = 15 //Its 50% faster than a regular spraycan, for tagging. After-all they did spend points/meet the boss.
|
||||
|
||||
pre_noise = FALSE
|
||||
post_noise = TRUE // Its even more stealthy just a tad.
|
||||
|
||||
/obj/item/toy/crayon/spraycan/gang/Initialize(loc, datum/team/gang/G)
|
||||
..()
|
||||
if(G)
|
||||
gang = G
|
||||
paint_color = G.color
|
||||
update_icon()
|
||||
|
||||
/obj/item/toy/crayon/spraycan/gang/examine(mob/user)
|
||||
. = ..()
|
||||
if(user.mind && user.mind.has_antag_datum(/datum/antagonist/gang) || isobserver(user))
|
||||
to_chat(user, "This spraycan has been specially modified with a stage 2 nozzle kit, making it faster.")
|
||||
|
||||
#undef RANDOM_GRAFFITI
|
||||
#undef RANDOM_LETTER
|
||||
#undef RANDOM_NUMBER
|
||||
#undef RANDOM_ORIENTED
|
||||
#undef RANDOM_RUNE
|
||||
#undef RANDOM_ANY
|
||||
@@ -0,0 +1,751 @@
|
||||
//backpack item
|
||||
#define HALFWAYCRITDEATH ((HEALTH_THRESHOLD_CRIT + HEALTH_THRESHOLD_DEAD) * 0.5)
|
||||
|
||||
/obj/item/defibrillator
|
||||
name = "defibrillator"
|
||||
desc = "A device that delivers powerful shocks to detachable paddles that resuscitate incapacitated patients."
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "defibunit"
|
||||
item_state = "defibunit"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
|
||||
slot_flags = ITEM_SLOT_BACK
|
||||
force = 5
|
||||
throwforce = 6
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
actions_types = list(/datum/action/item_action/toggle_paddles)
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50)
|
||||
|
||||
var/on = FALSE //if the paddles are equipped (1) or on the defib (0)
|
||||
var/safety = TRUE //if you can zap people with the defibs on harm mode
|
||||
var/powered = FALSE //if there's a cell in the defib with enough power for a revive, blocks paddles from reviving otherwise
|
||||
var/obj/item/twohanded/shockpaddles/paddles
|
||||
var/obj/item/stock_parts/cell/high/cell
|
||||
var/combat = FALSE //can we revive through space suits?
|
||||
var/grab_ghost = FALSE // Do we pull the ghost back into their body?
|
||||
var/healdisk = FALSE // Will we shock people dragging the body?
|
||||
var/pullshocksafely = FALSE //Dose the unit have the healdisk upgrade?
|
||||
var/primetime = 0 // is the defib faster
|
||||
var/timedeath = 10
|
||||
|
||||
/obj/item/defibrillator/get_cell()
|
||||
return cell
|
||||
|
||||
/obj/item/defibrillator/Initialize() //starts without a cell for rnd
|
||||
. = ..()
|
||||
paddles = make_paddles()
|
||||
update_icon()
|
||||
return
|
||||
|
||||
/obj/item/defibrillator/loaded/Initialize() //starts with hicap
|
||||
. = ..()
|
||||
paddles = make_paddles()
|
||||
cell = new(src)
|
||||
update_icon()
|
||||
return
|
||||
|
||||
/obj/item/defibrillator/update_icon()
|
||||
update_power()
|
||||
update_overlays()
|
||||
update_charge()
|
||||
|
||||
/obj/item/defibrillator/proc/update_power()
|
||||
if(!QDELETED(cell))
|
||||
if(QDELETED(paddles) || cell.charge < paddles.revivecost)
|
||||
powered = FALSE
|
||||
else
|
||||
powered = TRUE
|
||||
else
|
||||
powered = FALSE
|
||||
|
||||
/obj/item/defibrillator/proc/update_overlays()
|
||||
cut_overlays()
|
||||
if(!on)
|
||||
add_overlay("[initial(icon_state)]-paddles")
|
||||
if(powered)
|
||||
add_overlay("[initial(icon_state)]-powered")
|
||||
if(!cell)
|
||||
add_overlay("[initial(icon_state)]-nocell")
|
||||
if(!safety)
|
||||
add_overlay("[initial(icon_state)]-emagged")
|
||||
|
||||
/obj/item/defibrillator/proc/update_charge()
|
||||
if(powered) //so it doesn't show charge if it's unpowered
|
||||
if(!QDELETED(cell))
|
||||
var/ratio = cell.charge / cell.maxcharge
|
||||
ratio = CEILING(ratio*4, 1) * 25
|
||||
add_overlay("[initial(icon_state)]-charge[ratio]")
|
||||
|
||||
/obj/item/defibrillator/CheckParts(list/parts_list)
|
||||
..()
|
||||
cell = locate(/obj/item/stock_parts/cell) in contents
|
||||
update_icon()
|
||||
|
||||
/obj/item/defibrillator/ui_action_click()
|
||||
toggle_paddles()
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/obj/item/defibrillator/attack_hand(mob/user)
|
||||
if(loc == user)
|
||||
if(slot_flags == ITEM_SLOT_BACK)
|
||||
if(user.get_item_by_slot(SLOT_BACK) == src)
|
||||
ui_action_click()
|
||||
else
|
||||
to_chat(user, "<span class='warning'>Put the defibrillator on your back first!</span>")
|
||||
|
||||
else if(slot_flags == ITEM_SLOT_BELT)
|
||||
if(user.get_item_by_slot(SLOT_BELT) == src)
|
||||
ui_action_click()
|
||||
else
|
||||
to_chat(user, "<span class='warning'>Strap the defibrillator's belt on first!</span>")
|
||||
return
|
||||
else if(istype(loc, /obj/machinery/defibrillator_mount))
|
||||
ui_action_click() //checks for this are handled in defibrillator.mount.dm
|
||||
return ..()
|
||||
|
||||
/obj/item/defibrillator/MouseDrop(obj/over_object)
|
||||
. = ..()
|
||||
if(ismob(loc))
|
||||
var/mob/M = loc
|
||||
if(!M.incapacitated() && istype(over_object, /obj/screen/inventory/hand))
|
||||
var/obj/screen/inventory/hand/H = over_object
|
||||
M.putItemFromInventoryInHandIfPossible(src, H.held_index)
|
||||
|
||||
/obj/item/defibrillator/attackby(obj/item/W, mob/user, params)
|
||||
if(W == paddles)
|
||||
paddles.unwield()
|
||||
toggle_paddles()
|
||||
else if(istype(W, /obj/item/stock_parts/cell))
|
||||
var/obj/item/stock_parts/cell/C = W
|
||||
if(cell)
|
||||
to_chat(user, "<span class='notice'>[src] already has a cell.</span>")
|
||||
else
|
||||
if(C.maxcharge < paddles.revivecost)
|
||||
to_chat(user, "<span class='notice'>[src] requires a higher capacity cell.</span>")
|
||||
return
|
||||
if(!user.transferItemToLoc(W, src))
|
||||
return
|
||||
cell = W
|
||||
to_chat(user, "<span class='notice'>You install a cell in [src].</span>")
|
||||
update_icon()
|
||||
|
||||
else if(istype(W, /obj/item/screwdriver))
|
||||
if(cell)
|
||||
cell.update_icon()
|
||||
cell.forceMove(get_turf(src))
|
||||
cell = null
|
||||
to_chat(user, "<span class='notice'>You remove the cell from [src].</span>")
|
||||
update_icon()
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/defibrillator/emag_act(mob/user)
|
||||
if(safety)
|
||||
safety = FALSE
|
||||
to_chat(user, "<span class='warning'>You silently disable [src]'s safety protocols with the cryptographic sequencer.</span>")
|
||||
else
|
||||
safety = TRUE
|
||||
to_chat(user, "<span class='notice'>You silently enable [src]'s safety protocols with the cryptographic sequencer.</span>")
|
||||
|
||||
/obj/item/defibrillator/emp_act(severity)
|
||||
. = ..()
|
||||
if(cell && !(. & EMP_PROTECT_CONTENTS))
|
||||
deductcharge(1000 / severity)
|
||||
if (. & EMP_PROTECT_SELF)
|
||||
return
|
||||
if(safety)
|
||||
safety = FALSE
|
||||
visible_message("<span class='notice'>[src] beeps: Safety protocols disabled!</span>")
|
||||
playsound(src, 'sound/machines/defib_saftyOff.ogg', 50, 0)
|
||||
else
|
||||
safety = TRUE
|
||||
visible_message("<span class='notice'>[src] beeps: Safety protocols enabled!</span>")
|
||||
playsound(src, 'sound/machines/defib_saftyOn.ogg', 50, 0)
|
||||
update_icon()
|
||||
|
||||
/obj/item/defibrillator/proc/toggle_paddles()
|
||||
set name = "Toggle Paddles"
|
||||
set category = "Object"
|
||||
on = !on
|
||||
|
||||
var/mob/living/carbon/user = usr
|
||||
if(on)
|
||||
//Detach the paddles into the user's hands
|
||||
if(!usr.put_in_hands(paddles))
|
||||
on = FALSE
|
||||
to_chat(user, "<span class='warning'>You need a free hand to hold the paddles!</span>")
|
||||
update_icon()
|
||||
return
|
||||
else
|
||||
//Remove from their hands and back onto the defib unit
|
||||
paddles.unwield()
|
||||
remove_paddles(user)
|
||||
|
||||
update_icon()
|
||||
for(var/X in actions)
|
||||
var/datum/action/A = X
|
||||
A.UpdateButtonIcon()
|
||||
|
||||
/obj/item/defibrillator/proc/make_paddles()
|
||||
return new /obj/item/twohanded/shockpaddles(src)
|
||||
|
||||
/obj/item/defibrillator/equipped(mob/user, slot)
|
||||
..()
|
||||
if((slot_flags == ITEM_SLOT_BACK && slot != SLOT_BACK) || (slot_flags == ITEM_SLOT_BELT && slot != SLOT_BELT))
|
||||
remove_paddles(user)
|
||||
update_icon()
|
||||
|
||||
/obj/item/defibrillator/item_action_slot_check(slot, mob/user)
|
||||
if(slot == user.getBackSlot())
|
||||
return 1
|
||||
|
||||
/obj/item/defibrillator/proc/remove_paddles(mob/user) //this fox the bug with the paddles when other player stole you the defib when you have the paddles equiped
|
||||
if(ismob(paddles.loc))
|
||||
var/mob/M = paddles.loc
|
||||
M.dropItemToGround(paddles, TRUE)
|
||||
return
|
||||
|
||||
/obj/item/defibrillator/Destroy()
|
||||
if(on)
|
||||
var/M = get(paddles, /mob)
|
||||
remove_paddles(M)
|
||||
QDEL_NULL(paddles)
|
||||
. = ..()
|
||||
update_icon()
|
||||
|
||||
/obj/item/defibrillator/proc/deductcharge(chrgdeductamt)
|
||||
if(cell)
|
||||
if(cell.charge < (paddles.revivecost+chrgdeductamt))
|
||||
powered = FALSE
|
||||
update_icon()
|
||||
if(cell.use(chrgdeductamt))
|
||||
update_icon()
|
||||
return TRUE
|
||||
else
|
||||
update_icon()
|
||||
return FALSE
|
||||
|
||||
/obj/item/defibrillator/proc/cooldowncheck(mob/user)
|
||||
spawn(50)
|
||||
if(cell)
|
||||
if(cell.charge >= paddles.revivecost)
|
||||
user.visible_message("<span class='notice'>[src] beeps: Unit ready.</span>")
|
||||
playsound(src, 'sound/machines/defib_ready.ogg', 50, 0)
|
||||
else
|
||||
user.visible_message("<span class='notice'>[src] beeps: Charge depleted.</span>")
|
||||
playsound(src, 'sound/machines/defib_failed.ogg', 50, 0)
|
||||
paddles.cooldown = FALSE
|
||||
paddles.update_icon()
|
||||
update_icon()
|
||||
|
||||
/obj/item/defibrillator/compact
|
||||
name = "compact defibrillator"
|
||||
desc = "A belt-equipped defibrillator that can be rapidly deployed."
|
||||
icon_state = "defibcompact"
|
||||
item_state = "defibcompact"
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
slot_flags = ITEM_SLOT_BELT
|
||||
|
||||
/obj/item/defibrillator/compact/item_action_slot_check(slot, mob/user)
|
||||
if(slot == user.getBeltSlot())
|
||||
return TRUE
|
||||
|
||||
/obj/item/defibrillator/compact/loaded/Initialize()
|
||||
. = ..()
|
||||
paddles = make_paddles()
|
||||
cell = new(src)
|
||||
update_icon()
|
||||
|
||||
/obj/item/defibrillator/compact/combat
|
||||
name = "combat defibrillator"
|
||||
desc = "A belt-equipped blood-red defibrillator that can be rapidly deployed. Does not have the restrictions or safeties of conventional defibrillators and can revive through space suits."
|
||||
combat = TRUE
|
||||
safety = FALSE
|
||||
|
||||
/obj/item/defibrillator/compact/combat/loaded/Initialize()
|
||||
. = ..()
|
||||
paddles = make_paddles()
|
||||
cell = new /obj/item/stock_parts/cell/infinite(src)
|
||||
update_icon()
|
||||
|
||||
/obj/item/defibrillator/compact/combat/loaded/attackby(obj/item/W, mob/user, params)
|
||||
if(W == paddles)
|
||||
paddles.unwield()
|
||||
toggle_paddles()
|
||||
update_icon()
|
||||
return
|
||||
|
||||
//paddles
|
||||
|
||||
/obj/item/twohanded/shockpaddles
|
||||
name = "defibrillator paddles"
|
||||
desc = "A pair of plastic-gripped paddles with flat metal surfaces that are used to deliver powerful electric shocks."
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "defibpaddles0"
|
||||
item_state = "defibpaddles0"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
|
||||
|
||||
force = 0
|
||||
throwforce = 6
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
|
||||
var/revivecost = 1000
|
||||
var/cooldown = FALSE
|
||||
var/busy = FALSE
|
||||
var/obj/item/defibrillator/defib
|
||||
var/req_defib = TRUE
|
||||
var/combat = FALSE //If it penetrates armor and gives additional functionality
|
||||
var/grab_ghost = FALSE
|
||||
var/tlimit = DEFIB_TIME_LIMIT * 10
|
||||
|
||||
var/datum/component/mobhook
|
||||
|
||||
/obj/item/twohanded/shockpaddles/equipped(mob/user, slot)
|
||||
. = ..()
|
||||
if(req_defib)
|
||||
if (mobhook && mobhook.parent != user)
|
||||
QDEL_NULL(mobhook)
|
||||
if (!mobhook)
|
||||
mobhook = user.AddComponent(/datum/component/redirect, list(COMSIG_MOVABLE_MOVED = CALLBACK(src, .proc/check_range)))
|
||||
|
||||
/obj/item/twohanded/shockpaddles/Moved()
|
||||
. = ..()
|
||||
check_range()
|
||||
|
||||
/obj/item/twohanded/shockpaddles/proc/check_range()
|
||||
if(!req_defib)
|
||||
return
|
||||
if(!in_range(src,defib))
|
||||
var/mob/living/L = loc
|
||||
if(istype(L))
|
||||
to_chat(L, "<span class='warning'>[defib]'s paddles overextend and come out of your hands!</span>")
|
||||
L.temporarilyRemoveItemFromInventory(src,TRUE)
|
||||
else
|
||||
visible_message("<span class='notice'>[src] snap back into [defib].</span>")
|
||||
snap_back()
|
||||
|
||||
/obj/item/twohanded/shockpaddles/proc/recharge(var/time)
|
||||
if(req_defib || !time)
|
||||
return
|
||||
cooldown = TRUE
|
||||
update_icon()
|
||||
sleep(time)
|
||||
var/turf/T = get_turf(src)
|
||||
T.audible_message("<span class='notice'>[src] beeps: Unit is recharged.</span>")
|
||||
playsound(src, 'sound/machines/defib_ready.ogg', 50, 0)
|
||||
cooldown = FALSE
|
||||
update_icon()
|
||||
|
||||
/obj/item/twohanded/shockpaddles/New(mainunit)
|
||||
..()
|
||||
if(check_defib_exists(mainunit, src) && req_defib)
|
||||
defib = mainunit
|
||||
forceMove(defib)
|
||||
busy = FALSE
|
||||
update_icon()
|
||||
|
||||
/obj/item/twohanded/shockpaddles/update_icon()
|
||||
icon_state = "defibpaddles[wielded]"
|
||||
item_state = "defibpaddles[wielded]"
|
||||
if(cooldown)
|
||||
icon_state = "defibpaddles[wielded]_cooldown"
|
||||
if(iscarbon(loc))
|
||||
var/mob/living/carbon/C = loc
|
||||
C.update_inv_hands()
|
||||
|
||||
/obj/item/twohanded/shockpaddles/suicide_act(mob/user)
|
||||
user.visible_message("<span class='danger'>[user] is putting the live paddles on [user.p_their()] chest! It looks like [user.p_theyre()] trying to commit suicide!</span>")
|
||||
if(req_defib)
|
||||
defib.deductcharge(revivecost)
|
||||
playsound(src, 'sound/machines/defib_zap.ogg', 50, 1, -1)
|
||||
return (OXYLOSS)
|
||||
|
||||
/obj/item/twohanded/shockpaddles/dropped(mob/user)
|
||||
if(!req_defib)
|
||||
return ..()
|
||||
if (mobhook)
|
||||
QDEL_NULL(mobhook)
|
||||
if(user)
|
||||
var/obj/item/twohanded/offhand/O = user.get_inactive_held_item()
|
||||
if(istype(O))
|
||||
O.unwield()
|
||||
to_chat(user, "<span class='notice'>The paddles snap back into the main unit.</span>")
|
||||
snap_back()
|
||||
return unwield(user)
|
||||
|
||||
/obj/item/twohanded/shockpaddles/proc/snap_back()
|
||||
if(!defib)
|
||||
return
|
||||
defib.on = FALSE
|
||||
forceMove(defib)
|
||||
defib.update_icon()
|
||||
|
||||
/obj/item/twohanded/shockpaddles/proc/check_defib_exists(mainunit, mob/living/carbon/M, obj/O)
|
||||
if(!req_defib)
|
||||
return TRUE //If it doesn't need a defib, just say it exists
|
||||
if (!mainunit || !istype(mainunit, /obj/item/defibrillator)) //To avoid weird issues from admin spawns
|
||||
qdel(O)
|
||||
return FALSE
|
||||
else
|
||||
return TRUE
|
||||
|
||||
/obj/item/twohanded/shockpaddles/attack(mob/M, mob/user)
|
||||
|
||||
if(busy)
|
||||
return
|
||||
if(req_defib && !defib.powered)
|
||||
user.visible_message("<span class='notice'>[defib] beeps: Unit is unpowered.</span>")
|
||||
playsound(src, 'sound/machines/defib_failed.ogg', 50, 0)
|
||||
return
|
||||
if(!wielded)
|
||||
if(iscyborg(user))
|
||||
to_chat(user, "<span class='warning'>You must activate the paddles in your active module before you can use them on someone!</span>")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You need to wield the paddles in both hands before you can use them on someone!</span>")
|
||||
return
|
||||
if(cooldown)
|
||||
if(req_defib)
|
||||
to_chat(user, "<span class='warning'>[defib] is recharging!</span>")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>[src] are recharging!</span>")
|
||||
return
|
||||
|
||||
user.stop_pulling() //User has hands full, and we don't care about anyone else pulling on it, their problem. CLEAR!!
|
||||
|
||||
if(user.a_intent == INTENT_DISARM)
|
||||
do_disarm(M, user)
|
||||
return
|
||||
|
||||
if(!iscarbon(M))
|
||||
if(req_defib)
|
||||
to_chat(user, "<span class='warning'>The instructions on [defib] don't mention how to revive that...</span>")
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You aren't sure how to revive that...</span>")
|
||||
return
|
||||
var/mob/living/carbon/H = M
|
||||
|
||||
|
||||
if(user.zone_selected != BODY_ZONE_CHEST)
|
||||
to_chat(user, "<span class='warning'>You need to target your patient's chest with [src]!</span>")
|
||||
return
|
||||
|
||||
if(user.a_intent == INTENT_HARM)
|
||||
do_harm(H, user)
|
||||
return
|
||||
|
||||
if((!req_defib && grab_ghost) || (req_defib && defib.grab_ghost))
|
||||
H.notify_ghost_cloning("Your heart is being defibrillated!")
|
||||
H.grab_ghost() // Shove them back in their body.
|
||||
else if(can_defib(H))
|
||||
H.notify_ghost_cloning("Your heart is being defibrillated. Re-enter your corpse if you want to be revived!", source = src)
|
||||
|
||||
do_help(H, user)
|
||||
|
||||
/obj/item/twohanded/shockpaddles/proc/can_defib(mob/living/carbon/H)
|
||||
var/obj/item/organ/brain/BR = H.getorgan(/obj/item/organ/brain)
|
||||
return (!H.suiciding && !(HAS_TRAIT(H, TRAIT_NOCLONE)) && !H.hellbound && ((world.time - H.timeofdeath) < tlimit) && (H.getBruteLoss() < 180) && (H.getFireLoss() < 180) && H.getorgan(/obj/item/organ/heart) && BR && !BR.damaged_brain)
|
||||
|
||||
/obj/item/twohanded/shockpaddles/proc/shock_touching(dmg, mob/H)
|
||||
if(req_defib)
|
||||
if(defib.pullshocksafely && isliving(H.pulledby))
|
||||
H.visible_message("<span class='danger'>The defibrillator safely discharges the excessive charge into the floor!</span>")
|
||||
else
|
||||
var/mob/living/M = H.pulledby
|
||||
if(M.electrocute_act(30, src))
|
||||
M.visible_message("<span class='danger'>[M] is electrocuted by [M.p_their()] contact with [H]!</span>")
|
||||
M.emote("scream")
|
||||
|
||||
/obj/item/twohanded/shockpaddles/proc/do_disarm(mob/living/M, mob/living/user)
|
||||
if(req_defib && defib.safety)
|
||||
return
|
||||
if(!req_defib && !combat)
|
||||
return
|
||||
M.visible_message("<span class='danger'>[user] hastily places [src] on [M]'s chest!</span>", \
|
||||
"<span class='userdanger'>[user] hastily places [src] on [M]'s chest!</span>")
|
||||
busy = TRUE
|
||||
if(do_after(user, 10, target = M))
|
||||
M.visible_message("<span class='danger'>[user] zaps [M] with [src]!</span>", \
|
||||
"<span class='userdanger'>[user] zaps [M] with [src]!</span>")
|
||||
M.adjustStaminaLoss(50)
|
||||
M.Knockdown(100)
|
||||
M.updatehealth() //forces health update before next life tick
|
||||
playsound(src, 'sound/machines/defib_zap.ogg', 50, 1, -1)
|
||||
M.emote("gasp")
|
||||
log_combat(user, M, "stunned", src)
|
||||
busy = FALSE
|
||||
if(req_defib)
|
||||
defib.deductcharge(revivecost)
|
||||
cooldown = TRUE
|
||||
busy = FALSE
|
||||
update_icon()
|
||||
if(req_defib)
|
||||
defib.cooldowncheck(user)
|
||||
else
|
||||
recharge(60)
|
||||
|
||||
/obj/item/twohanded/shockpaddles/proc/do_harm(mob/living/carbon/H, mob/living/user)
|
||||
if(req_defib && defib.safety)
|
||||
return
|
||||
if(!req_defib && !combat)
|
||||
return
|
||||
user.visible_message("<span class='warning'>[user] begins to place [src] on [H]'s chest.</span>",
|
||||
"<span class='warning'>You overcharge the paddles and begin to place them onto [H]'s chest...</span>")
|
||||
busy = TRUE
|
||||
update_icon()
|
||||
if(do_after(user, 30, target = H))
|
||||
user.visible_message("<span class='notice'>[user] places [src] on [H]'s chest.</span>",
|
||||
"<span class='warning'>You place [src] on [H]'s chest and begin to charge them.</span>")
|
||||
var/turf/T = get_turf(defib)
|
||||
playsound(src, 'sound/machines/defib_charge.ogg', 50, 0)
|
||||
if(req_defib)
|
||||
T.audible_message("<span class='warning'>\The [defib] lets out an urgent beep and lets out a steadily rising hum...</span>")
|
||||
else
|
||||
user.audible_message("<span class='warning'>[src] let out an urgent beep.</span>")
|
||||
if(do_after(user, 30, target = H)) //Takes longer due to overcharging
|
||||
if(!H)
|
||||
busy = FALSE
|
||||
update_icon()
|
||||
return
|
||||
if(H && H.stat == DEAD)
|
||||
to_chat(user, "<span class='warning'>[H] is dead.</span>")
|
||||
playsound(src, 'sound/machines/defib_failed.ogg', 50, 0)
|
||||
busy = FALSE
|
||||
update_icon()
|
||||
return
|
||||
user.visible_message("<span class='boldannounce'><i>[user] shocks [H] with \the [src]!</span>", "<span class='warning'>You shock [H] with \the [src]!</span>")
|
||||
playsound(src, 'sound/machines/defib_zap.ogg', 100, 1, -1)
|
||||
playsound(src, 'sound/weapons/egloves.ogg', 100, 1, -1)
|
||||
H.emote("scream")
|
||||
shock_touching(45, H)
|
||||
if(H.can_heartattack() && !H.undergoing_cardiac_arrest())
|
||||
if(!H.stat)
|
||||
H.visible_message("<span class='warning'>[H] thrashes wildly, clutching at [H.p_their()] chest!</span>",
|
||||
"<span class='userdanger'>You feel a horrible agony in your chest!</span>")
|
||||
H.set_heartattack(TRUE)
|
||||
H.apply_damage(50, BURN, BODY_ZONE_CHEST)
|
||||
log_combat(user, H, "overloaded the heart of", defib)
|
||||
H.Knockdown(100)
|
||||
H.Jitter(100)
|
||||
if(req_defib)
|
||||
defib.deductcharge(revivecost)
|
||||
cooldown = TRUE
|
||||
busy = FALSE
|
||||
update_icon()
|
||||
if(!req_defib)
|
||||
recharge(60)
|
||||
if(req_defib && (defib.cooldowncheck(user)))
|
||||
return
|
||||
busy = FALSE
|
||||
update_icon()
|
||||
|
||||
/obj/item/twohanded/shockpaddles/proc/do_help(mob/living/carbon/H, mob/living/user)
|
||||
user.visible_message("<span class='warning'>[user] begins to place [src] on [H]'s chest.</span>", "<span class='warning'>You begin to place [src] on [H]'s chest...</span>")
|
||||
busy = TRUE
|
||||
update_icon()
|
||||
|
||||
var/primetimer
|
||||
var/primetimer2
|
||||
var/deathtimer
|
||||
if(req_defib)
|
||||
primetimer = 30 - defib.primetime //I swear to god if I find shit like this elsewhere
|
||||
primetimer2 = 20 - defib.primetime
|
||||
deathtimer = DEFIB_TIME_LOSS * defib.timedeath
|
||||
else
|
||||
primetimer = 30
|
||||
primetimer2 = 20
|
||||
deathtimer = DEFIB_TIME_LOSS * 10
|
||||
|
||||
if(do_after(user, primetimer, target = H)) //beginning to place the paddles on patient's chest to allow some time for people to move away to stop the process
|
||||
user.visible_message("<span class='notice'>[user] places [src] on [H]'s chest.</span>", "<span class='warning'>You place [src] on [H]'s chest.</span>")
|
||||
playsound(src, 'sound/machines/defib_charge.ogg', 75, 0)
|
||||
var/tplus = world.time - H.timeofdeath
|
||||
// past this much time the patient is unrecoverable
|
||||
// (in deciseconds)
|
||||
// brain damage starts setting in on the patient after
|
||||
// some time left rotting
|
||||
var/tloss = deathtimer
|
||||
var/total_burn = 0
|
||||
var/total_brute = 0
|
||||
if(do_after(user, primetimer2, target = H)) //placed on chest and short delay to shock for dramatic effect, revive time is 5sec total
|
||||
for(var/obj/item/carried_item in H.contents)
|
||||
if(istype(carried_item, /obj/item/clothing/suit/space))
|
||||
if((!combat && !req_defib) || (req_defib && !defib.combat))
|
||||
user.audible_message("<span class='warning'>[req_defib ? "[defib]" : "[src]"] buzzes: Patient's chest is obscured. Operation aborted.</span>")
|
||||
playsound(src, 'sound/machines/defib_failed.ogg', 50, 0)
|
||||
busy = FALSE
|
||||
update_icon()
|
||||
return
|
||||
if(H.stat == DEAD)
|
||||
H.visible_message("<span class='warning'>[H]'s body convulses a bit.</span>")
|
||||
playsound(src, "bodyfall", 50, 1)
|
||||
playsound(src, 'sound/machines/defib_zap.ogg', 75, 1, -1)
|
||||
total_brute = H.getBruteLoss()
|
||||
total_burn = H.getFireLoss()
|
||||
shock_touching(30, H)
|
||||
var/failed
|
||||
|
||||
if (H.suiciding || (HAS_TRAIT(H, TRAIT_NOCLONE)))
|
||||
failed = "<span class='warning'>[req_defib ? "[defib]" : "[src]"] buzzes: Resuscitation failed - Recovery of patient impossible. Further attempts futile.</span>"
|
||||
else if (H.hellbound)
|
||||
failed = "<span class='warning'>[req_defib ? "[defib]" : "[src]"] buzzes: Resuscitation failed - Patient's soul appears to be on another plane of existence. Further attempts futile.</span>"
|
||||
else if (tplus > tlimit)
|
||||
failed = "<span class='warning'>[req_defib ? "[defib]" : "[src]"] buzzes: Resuscitation failed - Body has decayed for too long. Further attempts futile.</span>"
|
||||
else if (!H.getorgan(/obj/item/organ/heart))
|
||||
failed = "<span class='warning'>[req_defib ? "[defib]" : "[src]"] buzzes: Resuscitation failed - Patient's heart is missing.</span>"
|
||||
else if(total_burn >= 180 || total_brute >= 180)
|
||||
failed = "<span class='warning'>[req_defib ? "[defib]" : "[src]"] buzzes: Resuscitation failed - Severe tissue damage makes recovery of patient impossible via defibrillator. Further attempts futile.</span>"
|
||||
else if(H.get_ghost())
|
||||
failed = "<span class='warning'>[req_defib ? "[defib]" : "[src]"] buzzes: Resuscitation failed - No activity in patient's brain. Further attempts may be successful.</span>"
|
||||
else
|
||||
var/obj/item/organ/brain/BR = H.getorgan(/obj/item/organ/brain)
|
||||
if(!BR || BR.damaged_brain)
|
||||
failed = "<span class='warning'>[req_defib ? "[defib]" : "[src]"] buzzes: Resuscitation failed - Patient's brain is missing or damaged beyond point of no return. Further attempts futile.</span>"
|
||||
|
||||
if(failed)
|
||||
user.visible_message(failed)
|
||||
playsound(src, 'sound/machines/defib_failed.ogg', 50, 0)
|
||||
else
|
||||
//If the body has been fixed so that they would not be in crit when defibbed, give them oxyloss to put them back into crit
|
||||
if (H.health > HALFWAYCRITDEATH)
|
||||
H.adjustOxyLoss(H.health - HALFWAYCRITDEATH, 0)
|
||||
else
|
||||
var/overall_damage = total_brute + total_burn + H.getToxLoss() + H.getOxyLoss()
|
||||
var/mobhealth = H.health
|
||||
H.adjustOxyLoss((mobhealth - HALFWAYCRITDEATH) * (H.getOxyLoss() / overall_damage), 0)
|
||||
H.adjustToxLoss((mobhealth - HALFWAYCRITDEATH) * (H.getToxLoss() / overall_damage), 0)
|
||||
H.adjustFireLoss((mobhealth - HALFWAYCRITDEATH) * (total_burn / overall_damage), 0)
|
||||
H.adjustBruteLoss((mobhealth - HALFWAYCRITDEATH) * (total_brute / overall_damage), 0)
|
||||
H.updatehealth() // Previous "adjust" procs don't update health, so we do it manually.
|
||||
user.visible_message("<span class='notice'>[req_defib ? "[defib]" : "[src]"] pings: Resuscitation successful.</span>")
|
||||
playsound(src, 'sound/machines/defib_success.ogg', 50, 0)
|
||||
H.set_heartattack(FALSE)
|
||||
H.revive()
|
||||
H.emote("gasp")
|
||||
H.Jitter(100)
|
||||
SEND_SIGNAL(H, COMSIG_LIVING_MINOR_SHOCK)
|
||||
if(tplus > tloss)
|
||||
H.adjustBrainLoss( max(0, min(99, ((tlimit - tplus) / tlimit * 100))), 150)
|
||||
log_combat(user, H, "revived", defib)
|
||||
if(req_defib)
|
||||
if(defib.healdisk)
|
||||
H.heal_overall_damage(25, 25)
|
||||
if(req_defib)
|
||||
defib.deductcharge(revivecost)
|
||||
cooldown = 1
|
||||
update_icon()
|
||||
if(req_defib)
|
||||
defib.cooldowncheck(user)
|
||||
else
|
||||
recharge(60)
|
||||
else if (!H.getorgan(/obj/item/organ/heart))
|
||||
user.visible_message("<span class='warning'>[req_defib ? "[defib]" : "[src]"] buzzes: Patient's heart is missing. Operation aborted.</span>")
|
||||
playsound(src, 'sound/machines/defib_failed.ogg', 50, 0)
|
||||
else if(H.undergoing_cardiac_arrest())
|
||||
H.set_heartattack(FALSE)
|
||||
user.visible_message("<span class='notice'>[req_defib ? "[defib]" : "[src]"] pings: Patient's heart is now beating again.</span>")
|
||||
playsound(src, 'sound/machines/defib_zap.ogg', 50, 1, -1)
|
||||
|
||||
|
||||
else
|
||||
user.visible_message("<span class='warning'>[req_defib ? "[defib]" : "[src]"] buzzes: Patient is not in a valid state. Operation aborted.</span>")
|
||||
playsound(src, 'sound/machines/defib_failed.ogg', 50, 0)
|
||||
busy = FALSE
|
||||
update_icon()
|
||||
|
||||
/obj/item/defibrillator/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/disk/medical/defib_heal))
|
||||
if(healdisk)
|
||||
to_chat(user, "<span class='notice'>This unit is already upgraded with this disk!</span>")
|
||||
return TRUE
|
||||
to_chat(user, "<span class='notice'>You upgrade the unit with Heal upgrade disk!</span>")
|
||||
healdisk = TRUE
|
||||
return TRUE
|
||||
if(istype(I, /obj/item/disk/medical/defib_shock))
|
||||
if(pullshocksafely)
|
||||
to_chat(user, "<span class='notice'>This unit is already upgraded with this disk!</span>")
|
||||
return TRUE
|
||||
to_chat(user, "<span class='notice'>You upgrade the unit with Shock Safety upgrade disk!</span>")
|
||||
pullshocksafely = TRUE
|
||||
return TRUE
|
||||
if(istype(I, /obj/item/disk/medical/defib_speed))
|
||||
if(!primetime == initial(primetime))
|
||||
to_chat(user, "<span class='notice'>This unit is already upgraded with this disk!</span>")
|
||||
return TRUE
|
||||
to_chat(user, "<span class='notice'>You upgrade the unit with Speed upgrade disk!</span>")
|
||||
primetime = 10
|
||||
return TRUE
|
||||
if(istype(I, /obj/item/disk/medical/defib_decay))
|
||||
if(!timedeath == initial(timedeath))
|
||||
to_chat(user, "<span class='notice'>This unit is already upgraded with this disk!</span>")
|
||||
return TRUE
|
||||
to_chat(user, "<span class='notice'>You upgrade the unit with Longer Decay upgrade disk!</span>")
|
||||
timedeath = 20
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/obj/item/twohanded/shockpaddles/cyborg
|
||||
name = "cyborg defibrillator paddles"
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "defibpaddles0"
|
||||
item_state = "defibpaddles0"
|
||||
req_defib = FALSE
|
||||
|
||||
/obj/item/twohanded/shockpaddles/cyborg/attack(mob/M, mob/user)
|
||||
if(iscyborg(user))
|
||||
var/mob/living/silicon/robot/R = user
|
||||
if(R.emagged)
|
||||
combat = TRUE
|
||||
else
|
||||
combat = FALSE
|
||||
else
|
||||
combat = FALSE
|
||||
|
||||
. = ..()
|
||||
|
||||
/obj/item/twohanded/shockpaddles/syndicate
|
||||
name = "syndicate defibrillator paddles"
|
||||
desc = "A pair of paddles used to revive deceased operatives. It possesses both the ability to penetrate armor and to deliver powerful shocks offensively."
|
||||
combat = TRUE
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "defibpaddles0"
|
||||
item_state = "defibpaddles0"
|
||||
req_defib = FALSE
|
||||
|
||||
///////////////////////////////////////////
|
||||
/////////Defibrillator Disks//////////////
|
||||
///////////////////////////////////////////
|
||||
|
||||
/obj/item/disk/medical
|
||||
name = "Defibrillator Upgrade Disk"
|
||||
desc = "A blank upgrade disk, made for a defibrillator"
|
||||
icon = 'modular_citadel/icons/obj/defib_disks.dmi'
|
||||
icon_state = "upgrade_disk"
|
||||
item_state = "heal_disk"
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
|
||||
/obj/item/disk/medical/defib_heal
|
||||
name = "Defibrillator Healing Disk"
|
||||
desc = "An upgrade which increases the healing power of the defibrillator"
|
||||
icon_state = "heal_disk"
|
||||
materials = list(MAT_METAL=16000, MAT_GLASS = 18000, MAT_GOLD = 6000, MAT_SILVER = 6000)
|
||||
|
||||
/obj/item/disk/medical/defib_shock
|
||||
name = "Defibrillator Anti-Shock Disk"
|
||||
desc = "A safety upgrade that guarantees only the patient will get shocked"
|
||||
icon_state = "zap_disk"
|
||||
materials = list(MAT_METAL=16000, MAT_GLASS = 18000, MAT_GOLD = 6000, MAT_SILVER = 6000)
|
||||
|
||||
/obj/item/disk/medical/defib_decay
|
||||
name = "Defibrillator Body-Decay Extender Disk"
|
||||
desc = "An upgrade allowing the defibrillator to work on more decayed bodies"
|
||||
icon_state = "body_disk"
|
||||
materials = list(MAT_METAL=16000, MAT_GLASS = 18000, MAT_GOLD = 16000, MAT_SILVER = 6000, MAT_TITANIUM = 2000)
|
||||
|
||||
/obj/item/disk/medical/defib_speed
|
||||
name = "Defibrillator Fast Charge Disk"
|
||||
desc = "An upgrade to the defibrillator capacitors, which let it charge faster"
|
||||
icon_state = "fast_disk"
|
||||
materials = list(MAT_METAL=16000, MAT_GLASS = 8000, MAT_GOLD = 26000, MAT_SILVER = 26000)
|
||||
|
||||
#undef HALFWAYCRITDEATH
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Dehydrated Carp
|
||||
* Instant carp, just add water
|
||||
*/
|
||||
|
||||
//Child of carpplushie because this should do everything the toy does and more
|
||||
/obj/item/toy/plush/carpplushie/dehy_carp
|
||||
var/mob/owner = null //Carp doesn't attack owner, set when using in hand
|
||||
var/owned = 0 //Boolean, no owner to begin with
|
||||
var/mobtype = /mob/living/simple_animal/hostile/carp //So admins can change what mob spawns via var fuckery
|
||||
|
||||
//Attack self
|
||||
/obj/item/toy/plush/carpplushie/dehy_carp/attack_self(mob/user)
|
||||
src.add_fingerprint(user) //Anyone can add their fingerprints to it with this
|
||||
if(!owned)
|
||||
to_chat(user, "<span class='notice'>You pet [src]. You swear it looks up at you.</span>")
|
||||
owner = user
|
||||
owned = 1
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/toy/plush/carpplushie/dehy_carp/plop(obj/item/toy/plush/Daddy)
|
||||
return FALSE
|
||||
|
||||
/obj/item/toy/plush/carpplushie/dehy_carp/proc/Swell()
|
||||
desc = "It's growing!"
|
||||
visible_message("<span class='notice'>[src] swells up!</span>")
|
||||
|
||||
//Animation
|
||||
icon = 'icons/mob/animal.dmi'
|
||||
flick("carp_swell", src)
|
||||
//Wait for animation to end
|
||||
sleep(6)
|
||||
if(!src || QDELETED(src))//we got toasted while animating
|
||||
return
|
||||
//Make space carp
|
||||
var/mob/living/M = new mobtype(get_turf(src))
|
||||
//Make carp non-hostile to user, and their allies
|
||||
if(owner)
|
||||
var/list/factions = owner.faction.Copy()
|
||||
for(var/F in factions)
|
||||
if(F == "neutral")
|
||||
factions -= F
|
||||
M.faction = factions
|
||||
if (!owner || owner.faction != M.faction)
|
||||
visible_message("<span class='warning'>You have a bad feeling about this.</span>") //welcome to the hostile carp enjoy your die
|
||||
else
|
||||
visible_message("<span class='notice'>The newly grown [M.name] looks up at you with friendly eyes.</span>")
|
||||
qdel(src)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,230 @@
|
||||
//Clown PDA is slippery.
|
||||
/obj/item/pda/clown
|
||||
name = "clown PDA"
|
||||
default_cartridge = /obj/item/cartridge/virus/clown
|
||||
inserted_item = /obj/item/toy/crayon/rainbow
|
||||
icon_state = "pda-clown"
|
||||
desc = "A portable microcomputer by Thinktronic Systems, LTD. The surface is coated with polytetrafluoroethylene and banana drippings."
|
||||
ttone = "honk"
|
||||
var/slipvictims = list() //CIT CHANGE - makes clown PDAs track unique people slipped
|
||||
|
||||
/obj/item/pda/clown/Initialize()
|
||||
. = ..()
|
||||
AddComponent(/datum/component/slippery, 120, NO_SLIP_WHEN_WALKING, CALLBACK(src, .proc/AfterSlip))
|
||||
|
||||
/obj/item/pda/clown/proc/AfterSlip(mob/living/carbon/human/M)
|
||||
if (istype(M) && (M.real_name != owner))
|
||||
slipvictims |= M //CIT CHANGE - makes clown PDAs track unique people slipped
|
||||
var/obj/item/cartridge/virus/clown/cart = cartridge
|
||||
if(istype(cart) && cart.charges < 5)
|
||||
cart.charges++
|
||||
|
||||
// Special AI/pAI PDAs that cannot explode.
|
||||
/obj/item/pda/ai
|
||||
icon = null
|
||||
ttone = "data"
|
||||
fon = FALSE
|
||||
detonatable = FALSE
|
||||
|
||||
/obj/item/pda/ai/attack_self(mob/user)
|
||||
if ((honkamt > 0) && (prob(60)))//For clown virus.
|
||||
honkamt--
|
||||
playsound(loc, 'sound/items/bikehorn.ogg', 30, 1)
|
||||
return
|
||||
|
||||
/obj/item/pda/ai/pai
|
||||
ttone = "assist"
|
||||
|
||||
|
||||
|
||||
/obj/item/pda/medical
|
||||
name = "medical PDA"
|
||||
default_cartridge = /obj/item/cartridge/medical
|
||||
icon_state = "pda-medical"
|
||||
|
||||
/obj/item/pda/viro
|
||||
name = "virology PDA"
|
||||
default_cartridge = /obj/item/cartridge/medical
|
||||
icon_state = "pda-virology"
|
||||
|
||||
/obj/item/pda/engineering
|
||||
name = "engineering PDA"
|
||||
default_cartridge = /obj/item/cartridge/engineering
|
||||
icon_state = "pda-engineer"
|
||||
|
||||
/obj/item/pda/security
|
||||
name = "security PDA"
|
||||
default_cartridge = /obj/item/cartridge/security
|
||||
icon_state = "pda-security"
|
||||
|
||||
/obj/item/pda/detective
|
||||
name = "detective PDA"
|
||||
default_cartridge = /obj/item/cartridge/detective
|
||||
icon_state = "pda-detective"
|
||||
|
||||
/obj/item/pda/warden
|
||||
name = "warden PDA"
|
||||
default_cartridge = /obj/item/cartridge/security
|
||||
icon_state = "pda-warden"
|
||||
|
||||
/obj/item/pda/janitor
|
||||
name = "janitor PDA"
|
||||
default_cartridge = /obj/item/cartridge/janitor
|
||||
icon_state = "pda-janitor"
|
||||
ttone = "slip"
|
||||
|
||||
/obj/item/pda/toxins
|
||||
name = "scientist PDA"
|
||||
default_cartridge = /obj/item/cartridge/signal/toxins
|
||||
icon_state = "pda-science"
|
||||
ttone = "boom"
|
||||
|
||||
/obj/item/pda/mime
|
||||
name = "mime PDA"
|
||||
default_cartridge = /obj/item/cartridge/virus/mime
|
||||
inserted_item = /obj/item/toy/crayon/mime
|
||||
icon_state = "pda-mime"
|
||||
silent = TRUE
|
||||
ttone = "silence"
|
||||
|
||||
/obj/item/pda/heads
|
||||
default_cartridge = /obj/item/cartridge/head
|
||||
icon_state = "pda-hop"
|
||||
|
||||
/obj/item/pda/heads/hop
|
||||
name = "head of personnel PDA"
|
||||
default_cartridge = /obj/item/cartridge/hop
|
||||
icon_state = "pda-hop"
|
||||
|
||||
/obj/item/pda/heads/hos
|
||||
name = "head of security PDA"
|
||||
default_cartridge = /obj/item/cartridge/hos
|
||||
icon_state = "pda-hos"
|
||||
|
||||
/obj/item/pda/heads/ce
|
||||
name = "chief engineer PDA"
|
||||
default_cartridge = /obj/item/cartridge/ce
|
||||
icon_state = "pda-ce"
|
||||
|
||||
/obj/item/pda/heads/cmo
|
||||
name = "chief medical officer PDA"
|
||||
default_cartridge = /obj/item/cartridge/cmo
|
||||
icon_state = "pda-cmo"
|
||||
|
||||
/obj/item/pda/heads/rd
|
||||
name = "research director PDA"
|
||||
default_cartridge = /obj/item/cartridge/rd
|
||||
inserted_item = /obj/item/pen/fourcolor
|
||||
icon_state = "pda-rd"
|
||||
|
||||
/obj/item/pda/captain
|
||||
name = "captain PDA"
|
||||
default_cartridge = /obj/item/cartridge/captain
|
||||
inserted_item = /obj/item/pen/fountain/captain
|
||||
icon_state = "pda-captain"
|
||||
detonatable = FALSE
|
||||
|
||||
/obj/item/pda/lieutenant
|
||||
name = "lieutenant PDA"
|
||||
default_cartridge = /obj/item/cartridge/captain
|
||||
inserted_item = /obj/item/pen/fountain/captain
|
||||
icon_state = "pda-lieutenant"
|
||||
ttone = "bwoink"
|
||||
detonatable = FALSE
|
||||
hidden = TRUE
|
||||
note = "Congratulations, you have chosen the Thinktronic 5230-2 Personal Data Assistant Prestige Edition! To help with navigation, we have provided the following definitions. North: Fore. South: Aft. West: Port. East: Starboard. Quarter is either side of aft."
|
||||
|
||||
/obj/item/pda/cargo
|
||||
name = "cargo technician PDA"
|
||||
default_cartridge = /obj/item/cartridge/quartermaster
|
||||
icon_state = "pda-cargo"
|
||||
|
||||
/obj/item/pda/quartermaster
|
||||
name = "quartermaster PDA"
|
||||
default_cartridge = /obj/item/cartridge/quartermaster
|
||||
inserted_item = /obj/item/pen/fountain
|
||||
icon_state = "pda-qm"
|
||||
|
||||
/obj/item/pda/shaftminer
|
||||
name = "shaft miner PDA"
|
||||
icon_state = "pda-miner"
|
||||
|
||||
/obj/item/pda/syndicate
|
||||
default_cartridge = /obj/item/cartridge/virus/syndicate
|
||||
icon_state = "pda-syndi"
|
||||
name = "military PDA"
|
||||
owner = "John Doe"
|
||||
hidden = 1
|
||||
|
||||
/obj/item/pda/chaplain
|
||||
name = "chaplain PDA"
|
||||
icon_state = "pda-chaplain"
|
||||
ttone = "holy"
|
||||
|
||||
/obj/item/pda/lawyer
|
||||
name = "lawyer PDA"
|
||||
default_cartridge = /obj/item/cartridge/lawyer
|
||||
inserted_item = /obj/item/pen/fountain
|
||||
icon_state = "pda-lawyer"
|
||||
ttone = "objection"
|
||||
|
||||
/obj/item/pda/botanist
|
||||
name = "botanist PDA"
|
||||
//default_cartridge = /obj/item/cartridge/botanist
|
||||
icon_state = "pda-hydro"
|
||||
|
||||
/obj/item/pda/roboticist
|
||||
name = "roboticist PDA"
|
||||
icon_state = "pda-roboticist"
|
||||
default_cartridge = /obj/item/cartridge/roboticist
|
||||
|
||||
/obj/item/pda/curator
|
||||
name = "curator PDA"
|
||||
icon_state = "pda-library"
|
||||
overlays_icons = list('icons/obj/pda.dmi' = list("pda-r-library","blank","id_overlay","insert_overlay", "light_overlay", "pai_overlay"),
|
||||
'icons/obj/pda_alt.dmi' = list("pda-r","screen_default","id_overlay","insert_overlay", "light_overlay", "pai_overlay"))
|
||||
current_overlays = list("pda-r-library","blank","id_overlay","insert_overlay", "light_overlay", "pai_overlay")
|
||||
default_cartridge = /obj/item/cartridge/curator
|
||||
inserted_item = /obj/item/pen/fountain
|
||||
desc = "A portable microcomputer by Thinktronic Systems, LTD. This model is a WGW-11 series e-reader."
|
||||
note = "Congratulations, your station has chosen the Thinktronic 5290 WGW-11 Series E-reader and Personal Data Assistant! To help with navigation, we have provided the following definitions. North: Fore. South: Aft. West: Port. East: Starboard. Quarter is either side of aft."
|
||||
silent = TRUE //Quiet in the library!
|
||||
overlays_offsets = list('icons/obj/pda.dmi' = list(-3,0))
|
||||
overlays_x_offset = -3
|
||||
|
||||
/obj/item/pda/clear
|
||||
name = "clear PDA"
|
||||
icon_state = "pda-clear"
|
||||
desc = "A portable microcomputer by Thinktronic Systems, LTD. This model is a special edition with a transparent case."
|
||||
note = "Congratulations, you have chosen the Thinktronic 5230 Personal Data Assistant Deluxe Special Max Turbo Limited Edition! To help with navigation, we have provided the following definitions. North: Fore. South: Aft. West: Port. East: Starboard. Quarter is either side of aft."
|
||||
|
||||
/obj/item/pda/neko
|
||||
name = "neko PDA"
|
||||
icon_state = "pda-neko"
|
||||
overlays_icons = list('icons/obj/pda_alt.dmi' = list("pda-r", "screen_neko", "id_overlay", "insert_overlay", "light_overlay", "pai_overlay"))
|
||||
desc = "A portable microcomputer by Thinktronic Systems, LTD. This model is a special feline edition."
|
||||
note = "Congratulations, you have chosen the Thinktronic 5230 Personal Data Assistant Deluxe Special Mew Turbo Limited Edition NYA~! To help with navigation, we have provided the following definitions. North: Fore. South: Aft. West: Port. East: Starboard. Quarter is either side of aft."
|
||||
|
||||
/obj/item/pda/cook
|
||||
name = "cook PDA"
|
||||
icon_state = "pda-cook"
|
||||
|
||||
/obj/item/pda/bar
|
||||
name = "bartender PDA"
|
||||
icon_state = "pda-bartender"
|
||||
inserted_item = /obj/item/pen/fountain
|
||||
|
||||
/obj/item/pda/atmos
|
||||
name = "atmospherics PDA"
|
||||
default_cartridge = /obj/item/cartridge/atmos
|
||||
icon_state = "pda-atmos"
|
||||
|
||||
/obj/item/pda/chemist
|
||||
name = "chemist PDA"
|
||||
default_cartridge = /obj/item/cartridge/chemistry
|
||||
icon_state = "pda-chemistry"
|
||||
|
||||
/obj/item/pda/geneticist
|
||||
name = "geneticist PDA"
|
||||
default_cartridge = /obj/item/cartridge/medical
|
||||
icon_state = "pda-genetics"
|
||||
@@ -0,0 +1,775 @@
|
||||
#define CART_SECURITY (1<<0)
|
||||
#define CART_ENGINE (1<<1)
|
||||
#define CART_ATMOS (1<<2)
|
||||
#define CART_MEDICAL (1<<3)
|
||||
#define CART_MANIFEST (1<<4)
|
||||
#define CART_CLOWN (1<<5)
|
||||
#define CART_MIME (1<<6)
|
||||
#define CART_JANITOR (1<<7)
|
||||
#define CART_REAGENT_SCANNER (1<<8)
|
||||
#define CART_NEWSCASTER (1<<9)
|
||||
#define CART_REMOTE_DOOR (1<<10)
|
||||
#define CART_STATUS_DISPLAY (1<<11)
|
||||
#define CART_QUARTERMASTER (1<<12)
|
||||
#define CART_HYDROPONICS (1<<13)
|
||||
#define CART_DRONEPHONE (1<<14)
|
||||
|
||||
|
||||
/obj/item/cartridge
|
||||
name = "generic cartridge"
|
||||
desc = "A data cartridge for portable microcomputers."
|
||||
icon = 'icons/obj/pda.dmi'
|
||||
icon_state = "cart"
|
||||
item_state = "electronic"
|
||||
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
|
||||
var/obj/item/integrated_signaler/radio = null
|
||||
|
||||
var/access = 0 //Bit flags for cartridge access
|
||||
|
||||
var/remote_door_id = ""
|
||||
|
||||
var/bot_access_flags = 0 //Bit flags. Selection: SEC_BOT | MULE_BOT | FLOOR_BOT | CLEAN_BOT | MED_BOT | FIRE_BOT
|
||||
var/spam_enabled = 0 //Enables "Send to All" Option
|
||||
|
||||
var/obj/item/pda/host_pda = null
|
||||
var/menu
|
||||
var/datum/data/record/active1 = null //General
|
||||
var/datum/data/record/active2 = null //Medical
|
||||
var/datum/data/record/active3 = null //Security
|
||||
var/obj/machinery/computer/monitor/powmonitor = null // Power Monitor
|
||||
var/list/powermonitors = list()
|
||||
var/message1 // used for status_displays
|
||||
var/message2
|
||||
var/list/stored_data = list()
|
||||
var/current_channel
|
||||
|
||||
var/mob/living/simple_animal/bot/active_bot
|
||||
var/list/botlist = list()
|
||||
|
||||
/obj/item/cartridge/Initialize()
|
||||
. = ..()
|
||||
var/obj/item/pda/pda = loc
|
||||
if(istype(pda))
|
||||
host_pda = pda
|
||||
|
||||
/obj/item/cartridge/engineering
|
||||
name = "\improper Power-ON cartridge"
|
||||
icon_state = "cart-e"
|
||||
access = CART_ENGINE | CART_DRONEPHONE
|
||||
bot_access_flags = FLOOR_BOT
|
||||
|
||||
/obj/item/cartridge/atmos
|
||||
name = "\improper BreatheDeep cartridge"
|
||||
icon_state = "cart-a"
|
||||
access = CART_ATMOS | CART_DRONEPHONE
|
||||
bot_access_flags = FLOOR_BOT | FIRE_BOT
|
||||
|
||||
/obj/item/cartridge/medical
|
||||
name = "\improper Med-U cartridge"
|
||||
icon_state = "cart-m"
|
||||
access = CART_MEDICAL
|
||||
bot_access_flags = MED_BOT
|
||||
|
||||
/obj/item/cartridge/chemistry
|
||||
name = "\improper ChemWhiz cartridge"
|
||||
icon_state = "cart-chem"
|
||||
access = CART_REAGENT_SCANNER
|
||||
bot_access_flags = MED_BOT
|
||||
|
||||
/obj/item/cartridge/security
|
||||
name = "\improper R.O.B.U.S.T. cartridge"
|
||||
icon_state = "cart-s"
|
||||
access = CART_SECURITY
|
||||
bot_access_flags = SEC_BOT
|
||||
|
||||
/obj/item/cartridge/detective
|
||||
name = "\improper D.E.T.E.C.T. cartridge"
|
||||
icon_state = "cart-eye"
|
||||
access = CART_SECURITY | CART_MEDICAL | CART_MANIFEST
|
||||
bot_access_flags = SEC_BOT
|
||||
|
||||
/obj/item/cartridge/janitor
|
||||
name = "\improper CustodiPRO cartridge"
|
||||
desc = "The ultimate in clean-room design."
|
||||
icon_state = "cart-j"
|
||||
access = CART_JANITOR | CART_DRONEPHONE
|
||||
bot_access_flags = CLEAN_BOT
|
||||
|
||||
/obj/item/cartridge/lawyer
|
||||
name = "\improper P.R.O.V.E. cartridge"
|
||||
icon_state = "cart-law"
|
||||
access = CART_SECURITY
|
||||
spam_enabled = 1
|
||||
|
||||
/obj/item/cartridge/curator
|
||||
name = "\improper Lib-Tweet cartridge"
|
||||
icon_state = "cart-lib"
|
||||
access = CART_NEWSCASTER
|
||||
|
||||
/obj/item/cartridge/roboticist
|
||||
name = "\improper B.O.O.P. Remote Control cartridge"
|
||||
desc = "Packed with heavy duty triple-bot interlink!"
|
||||
icon_state = "cart-robo"
|
||||
bot_access_flags = FLOOR_BOT | CLEAN_BOT | MED_BOT | FIRE_BOT
|
||||
access = CART_DRONEPHONE
|
||||
|
||||
/obj/item/cartridge/signal
|
||||
name = "generic signaler cartridge"
|
||||
icon_state = "cart-sig"
|
||||
desc = "A data cartridge with an integrated radio signaler module."
|
||||
|
||||
/obj/item/cartridge/signal/toxins
|
||||
name = "\improper Signal Ace 2 cartridge"
|
||||
desc = "Complete with integrated radio signaler!"
|
||||
icon_state = "cart-tox"
|
||||
access = CART_REAGENT_SCANNER | CART_ATMOS
|
||||
|
||||
/obj/item/cartridge/signal/Initialize()
|
||||
. = ..()
|
||||
radio = new(src)
|
||||
|
||||
|
||||
|
||||
/obj/item/cartridge/quartermaster
|
||||
name = "space parts & space vendors cartridge"
|
||||
desc = "Perfect for the Quartermaster on the go!"
|
||||
icon_state = "cart-q"
|
||||
access = CART_QUARTERMASTER
|
||||
bot_access_flags = MULE_BOT
|
||||
|
||||
/obj/item/cartridge/head
|
||||
name = "\improper Easy-Record DELUXE cartridge"
|
||||
icon_state = "cart-h"
|
||||
access = CART_MANIFEST | CART_STATUS_DISPLAY
|
||||
|
||||
/obj/item/cartridge/hop
|
||||
name = "\improper HumanResources9001 cartridge"
|
||||
icon_state = "cart-h"
|
||||
access = CART_MANIFEST | CART_STATUS_DISPLAY | CART_JANITOR | CART_SECURITY | CART_NEWSCASTER | CART_QUARTERMASTER | CART_DRONEPHONE
|
||||
bot_access_flags = MULE_BOT | CLEAN_BOT
|
||||
|
||||
/obj/item/cartridge/hos
|
||||
name = "\improper R.O.B.U.S.T. DELUXE cartridge"
|
||||
icon_state = "cart-hos"
|
||||
access = CART_MANIFEST | CART_STATUS_DISPLAY | CART_SECURITY
|
||||
bot_access_flags = SEC_BOT
|
||||
|
||||
|
||||
/obj/item/cartridge/ce
|
||||
name = "\improper Power-On DELUXE cartridge"
|
||||
icon_state = "cart-ce"
|
||||
access = CART_MANIFEST | CART_STATUS_DISPLAY | CART_ENGINE | CART_ATMOS | CART_DRONEPHONE
|
||||
bot_access_flags = FLOOR_BOT | FIRE_BOT
|
||||
|
||||
/obj/item/cartridge/cmo
|
||||
name = "\improper Med-U DELUXE cartridge"
|
||||
icon_state = "cart-cmo"
|
||||
access = CART_MANIFEST | CART_STATUS_DISPLAY | CART_REAGENT_SCANNER | CART_MEDICAL
|
||||
bot_access_flags = MED_BOT
|
||||
|
||||
/obj/item/cartridge/rd
|
||||
name = "\improper Signal Ace DELUXE cartridge"
|
||||
icon_state = "cart-rd"
|
||||
access = CART_MANIFEST | CART_STATUS_DISPLAY | CART_REAGENT_SCANNER | CART_ATMOS | CART_DRONEPHONE
|
||||
bot_access_flags = FLOOR_BOT | CLEAN_BOT | MED_BOT | FIRE_BOT
|
||||
|
||||
/obj/item/cartridge/rd/Initialize()
|
||||
. = ..()
|
||||
radio = new(src)
|
||||
|
||||
/obj/item/cartridge/captain
|
||||
name = "\improper Value-PAK cartridge"
|
||||
desc = "Now with 350% more value!" //Give the Captain...EVERYTHING! (Except Mime, Clown, and Syndie)
|
||||
icon_state = "cart-c"
|
||||
access = ~(CART_CLOWN | CART_MIME | CART_REMOTE_DOOR)
|
||||
bot_access_flags = SEC_BOT | MULE_BOT | FLOOR_BOT | CLEAN_BOT | MED_BOT | FIRE_BOT
|
||||
spam_enabled = 1
|
||||
|
||||
/obj/item/cartridge/captain/New()
|
||||
..()
|
||||
radio = new(src)
|
||||
|
||||
/obj/item/cartridge/proc/post_status(command, data1, data2)
|
||||
|
||||
var/datum/radio_frequency/frequency = SSradio.return_frequency(FREQ_STATUS_DISPLAYS)
|
||||
|
||||
if(!frequency)
|
||||
return
|
||||
|
||||
var/datum/signal/status_signal = new(list("command" = command))
|
||||
switch(command)
|
||||
if("message")
|
||||
status_signal.data["msg1"] = data1
|
||||
status_signal.data["msg2"] = data2
|
||||
if("alert")
|
||||
status_signal.data["picture_state"] = data1
|
||||
|
||||
frequency.post_signal(src, status_signal)
|
||||
|
||||
/obj/item/cartridge/proc/generate_menu(mob/user)
|
||||
if(!host_pda)
|
||||
return
|
||||
switch(host_pda.mode)
|
||||
if(40) //signaller
|
||||
menu = "<h4>[PDAIMG(signaler)] Remote Signaling System</h4>"
|
||||
|
||||
menu += {"
|
||||
<a href='byond://?src=[REF(src)];choice=Send Signal'>Send Signal</A><BR>
|
||||
Frequency:
|
||||
<a href='byond://?src=[REF(src)];choice=Signal Frequency;sfreq=-10'>-</a>
|
||||
<a href='byond://?src=[REF(src)];choice=Signal Frequency;sfreq=-2'>-</a>
|
||||
[format_frequency(radio.frequency)]
|
||||
<a href='byond://?src=[REF(src)];choice=Signal Frequency;sfreq=2'>+</a>
|
||||
<a href='byond://?src=[REF(src)];choice=Signal Frequency;sfreq=10'>+</a><br>
|
||||
<br>
|
||||
Code:
|
||||
<a href='byond://?src=[REF(src)];choice=Signal Code;scode=-5'>-</a>
|
||||
<a href='byond://?src=[REF(src)];choice=Signal Code;scode=-1'>-</a>
|
||||
[radio.code]
|
||||
<a href='byond://?src=[REF(src)];choice=Signal Code;scode=1'>+</a>
|
||||
<a href='byond://?src=[REF(src)];choice=Signal Code;scode=5'>+</a><br>"}
|
||||
if (41) //crew manifest
|
||||
|
||||
menu = "<h4>[PDAIMG(notes)] Crew Manifest</h4>"
|
||||
menu += "Entries cannot be modified from this terminal.<br><br>"
|
||||
if(GLOB.data_core.general)
|
||||
for (var/datum/data/record/t in sortRecord(GLOB.data_core.general))
|
||||
menu += "[t.fields["name"]] - [t.fields["rank"]]<br>"
|
||||
menu += "<br>"
|
||||
|
||||
|
||||
if (42) //status displays
|
||||
menu = "<h4>[PDAIMG(status)] Station Status Display Interlink</h4>"
|
||||
|
||||
menu += "\[ <A HREF='?src=[REF(src)];choice=Status;statdisp=blank'>Clear</A> \]<BR>"
|
||||
menu += "\[ <A HREF='?src=[REF(src)];choice=Status;statdisp=shuttle'>Shuttle ETA</A> \]<BR>"
|
||||
menu += "\[ <A HREF='?src=[REF(src)];choice=Status;statdisp=message'>Message</A> \]"
|
||||
menu += "<ul><li> Line 1: <A HREF='?src=[REF(src)];choice=Status;statdisp=setmsg1'>[ message1 ? message1 : "(none)"]</A>"
|
||||
menu += "<li> Line 2: <A HREF='?src=[REF(src)];choice=Status;statdisp=setmsg2'>[ message2 ? message2 : "(none)"]</A></ul><br>"
|
||||
menu += "\[ Alert: <A HREF='?src=[REF(src)];choice=Status;statdisp=alert;alert=default'>None</A> |"
|
||||
menu += " <A HREF='?src=[REF(src)];choice=Status;statdisp=alert;alert=redalert'>Red Alert</A> |"
|
||||
menu += " <A HREF='?src=[REF(src)];choice=Status;statdisp=alert;alert=lockdown'>Lockdown</A> |"
|
||||
menu += " <A HREF='?src=[REF(src)];choice=Status;statdisp=alert;alert=biohazard'>Biohazard</A> \]<BR>"
|
||||
|
||||
if (43)
|
||||
menu = "<h4>[PDAIMG(power)] Power Monitors - Please select one</h4><BR>"
|
||||
powmonitor = null
|
||||
powermonitors = list()
|
||||
var/powercount = 0
|
||||
|
||||
|
||||
|
||||
var/turf/pda_turf = get_turf(src)
|
||||
for(var/obj/machinery/computer/monitor/pMon in GLOB.machines)
|
||||
if(pMon.stat & (NOPOWER | BROKEN)) //check to make sure the computer is functional
|
||||
continue
|
||||
if(pda_turf.z != pMon.z) //and that we're on the same zlevel as the computer (lore: limited signal strength)
|
||||
continue
|
||||
if(pMon.is_secret_monitor) //make sure it isn't a secret one (ie located on a ruin), allowing people to metagame that the location exists
|
||||
continue
|
||||
powercount++
|
||||
powermonitors += pMon
|
||||
|
||||
|
||||
if(!powercount)
|
||||
menu += "<span class='danger'>No connection<BR></span>"
|
||||
else
|
||||
|
||||
menu += "<FONT SIZE=-1>"
|
||||
var/count = 0
|
||||
for(var/obj/machinery/computer/monitor/pMon in powermonitors)
|
||||
count++
|
||||
menu += "<a href='byond://?src=[REF(src)];choice=Power Select;target=[count]'>[pMon] - [get_area_name(pMon, TRUE)] </a><BR>"
|
||||
|
||||
menu += "</FONT>"
|
||||
|
||||
if (433)
|
||||
menu = "<h4>[PDAIMG(power)] Power Monitor </h4><BR>"
|
||||
if(!powmonitor || !powmonitor.get_powernet())
|
||||
menu += "<span class='danger'>No connection<BR></span>"
|
||||
else
|
||||
var/list/L = list()
|
||||
var/datum/powernet/connected_powernet = powmonitor.get_powernet()
|
||||
for(var/obj/machinery/power/terminal/term in connected_powernet.nodes)
|
||||
if(istype(term.master, /obj/machinery/power/apc))
|
||||
var/obj/machinery/power/apc/A = term.master
|
||||
L += A
|
||||
|
||||
menu += "<PRE>Location: [get_area_name(powmonitor, TRUE)]<BR>Total power: [DisplayPower(connected_powernet.viewavail)]<BR>Total load: [DisplayPower(connected_powernet.viewload)]<BR>"
|
||||
|
||||
menu += "<FONT SIZE=-1>"
|
||||
|
||||
if(L.len > 0)
|
||||
menu += "Area Eqp./Lgt./Env. Load Cell<HR>"
|
||||
|
||||
var/list/S = list(" Off","AOff"," On", " AOn")
|
||||
var/list/chg = list("N","C","F")
|
||||
|
||||
for(var/obj/machinery/power/apc/A in L)
|
||||
menu += copytext(add_tspace(A.area.name, 30), 1, 30)
|
||||
menu += " [S[A.equipment+1]] [S[A.lighting+1]] [S[A.environ+1]] [add_lspace(DisplayPower(A.lastused_total), 6)] [A.cell ? "[add_lspace(round(A.cell.percent()), 3)]% [chg[A.charging+1]]" : " N/C"]<BR>"
|
||||
|
||||
menu += "</FONT></PRE>"
|
||||
|
||||
if (44) //medical records //This thing only displays a single screen so it's hard to really get the sub-menu stuff working.
|
||||
menu = "<h4>[PDAIMG(medical)] Medical Record List</h4>"
|
||||
if(GLOB.data_core.general)
|
||||
for(var/datum/data/record/R in sortRecord(GLOB.data_core.general))
|
||||
menu += "<a href='byond://?src=[REF(src)];choice=Medical Records;target=[R.fields["id"]]'>[R.fields["id"]]: [R.fields["name"]]<br>"
|
||||
menu += "<br>"
|
||||
if(441)
|
||||
menu = "<h4>[PDAIMG(medical)] Medical Record</h4>"
|
||||
|
||||
if(active1 in GLOB.data_core.general)
|
||||
menu += "Name: [active1.fields["name"]] ID: [active1.fields["id"]]<br>"
|
||||
menu += "Sex: [active1.fields["sex"]]<br>"
|
||||
menu += "Age: [active1.fields["age"]]<br>"
|
||||
menu += "Rank: [active1.fields["rank"]]<br>"
|
||||
menu += "Fingerprint: [active1.fields["fingerprint"]]<br>"
|
||||
menu += "Physical Status: [active1.fields["p_stat"]]<br>"
|
||||
menu += "Mental Status: [active1.fields["m_stat"]]<br>"
|
||||
else
|
||||
menu += "<b>Record Lost!</b><br>"
|
||||
|
||||
menu += "<br>"
|
||||
|
||||
menu += "<h4>[PDAIMG(medical)] Medical Data</h4>"
|
||||
if(active2 in GLOB.data_core.medical)
|
||||
menu += "Blood Type: [active2.fields["blood_type"]]<br><br>"
|
||||
|
||||
menu += "Minor Disabilities: [active2.fields["mi_dis"]]<br>"
|
||||
menu += "Details: [active2.fields["mi_dis_d"]]<br><br>"
|
||||
|
||||
menu += "Major Disabilities: [active2.fields["ma_dis"]]<br>"
|
||||
menu += "Details: [active2.fields["ma_dis_d"]]<br><br>"
|
||||
|
||||
menu += "Allergies: [active2.fields["alg"]]<br>"
|
||||
menu += "Details: [active2.fields["alg_d"]]<br><br>"
|
||||
|
||||
menu += "Current Diseases: [active2.fields["cdi"]]<br>"
|
||||
menu += "Details: [active2.fields["cdi_d"]]<br><br>"
|
||||
|
||||
menu += "Important Notes: [active2.fields["notes"]]<br>"
|
||||
else
|
||||
menu += "<b>Record Lost!</b><br>"
|
||||
|
||||
menu += "<br>"
|
||||
if (45) //security records
|
||||
menu = "<h4>[PDAIMG(cuffs)] Security Record List</h4>"
|
||||
if(GLOB.data_core.general)
|
||||
for (var/datum/data/record/R in sortRecord(GLOB.data_core.general))
|
||||
menu += "<a href='byond://?src=[REF(src)];choice=Security Records;target=[R.fields["id"]]'>[R.fields["id"]]: [R.fields["name"]]<br>"
|
||||
|
||||
menu += "<br>"
|
||||
if(451)
|
||||
menu = "<h4>[PDAIMG(cuffs)] Security Record</h4>"
|
||||
|
||||
if(active1 in GLOB.data_core.general)
|
||||
menu += "Name: [active1.fields["name"]] ID: [active1.fields["id"]]<br>"
|
||||
menu += "Sex: [active1.fields["sex"]]<br>"
|
||||
menu += "Age: [active1.fields["age"]]<br>"
|
||||
menu += "Rank: [active1.fields["rank"]]<br>"
|
||||
menu += "Fingerprint: [active1.fields["fingerprint"]]<br>"
|
||||
menu += "Physical Status: [active1.fields["p_stat"]]<br>"
|
||||
menu += "Mental Status: [active1.fields["m_stat"]]<br>"
|
||||
else
|
||||
menu += "<b>Record Lost!</b><br>"
|
||||
|
||||
menu += "<br>"
|
||||
|
||||
menu += "<h4>[PDAIMG(cuffs)] Security Data</h4>"
|
||||
if(active3 in GLOB.data_core.security)
|
||||
menu += "Criminal Status: [active3.fields["criminal"]]<br>"
|
||||
|
||||
menu += text("<BR>\nMinor Crimes:")
|
||||
|
||||
menu +={"<table style="text-align:center;" border="1" cellspacing="0" width="100%">
|
||||
<tr>
|
||||
<th>Crime</th>
|
||||
<th>Details</th>
|
||||
<th>Author</th>
|
||||
<th>Time Added</th>
|
||||
</tr>"}
|
||||
for(var/datum/data/crime/c in active3.fields["mi_crim"])
|
||||
menu += "<tr><td>[c.crimeName]</td>"
|
||||
menu += "<td>[c.crimeDetails]</td>"
|
||||
menu += "<td>[c.author]</td>"
|
||||
menu += "<td>[c.time]</td>"
|
||||
menu += "</tr>"
|
||||
menu += "</table>"
|
||||
|
||||
menu += text("<BR>\nMajor Crimes:")
|
||||
|
||||
menu +={"<table style="text-align:center;" border="1" cellspacing="0" width="100%">
|
||||
<tr>
|
||||
<th>Crime</th>
|
||||
<th>Details</th>
|
||||
<th>Author</th>
|
||||
<th>Time Added</th>
|
||||
</tr>"}
|
||||
for(var/datum/data/crime/c in active3.fields["ma_crim"])
|
||||
menu += "<tr><td>[c.crimeName]</td>"
|
||||
menu += "<td>[c.crimeDetails]</td>"
|
||||
menu += "<td>[c.author]</td>"
|
||||
menu += "<td>[c.time]</td>"
|
||||
menu += "</tr>"
|
||||
menu += "</table>"
|
||||
|
||||
menu += "<BR>\nImportant Notes:<br>"
|
||||
menu += "[active3.fields["notes"]]"
|
||||
else
|
||||
menu += "<b>Record Lost!</b><br>"
|
||||
|
||||
menu += "<br>"
|
||||
|
||||
if (47) //quartermaster order records
|
||||
menu = "<h4>[PDAIMG(crate)] Supply Record Interlink</h4>"
|
||||
|
||||
menu += "<BR><B>Supply shuttle</B><BR>"
|
||||
menu += "Location: "
|
||||
switch(SSshuttle.supply.mode)
|
||||
if(SHUTTLE_CALL)
|
||||
menu += "Moving to "
|
||||
if(!is_station_level(SSshuttle.supply.z))
|
||||
menu += "station"
|
||||
else
|
||||
menu += "CentCom"
|
||||
menu += " ([SSshuttle.supply.timeLeft(600)] Mins)"
|
||||
else
|
||||
menu += "At "
|
||||
if(!is_station_level(SSshuttle.supply.z))
|
||||
menu += "CentCom"
|
||||
else
|
||||
menu += "station"
|
||||
menu += "<BR>Current approved orders: <BR><ol>"
|
||||
for(var/S in SSshuttle.shoppinglist)
|
||||
var/datum/supply_order/SO = S
|
||||
menu += "<li>#[SO.id] - [SO.pack.name] approved by [SO.orderer] [SO.reason ? "([SO.reason])":""]</li>"
|
||||
menu += "</ol>"
|
||||
|
||||
menu += "Current requests: <BR><ol>"
|
||||
for(var/S in SSshuttle.requestlist)
|
||||
var/datum/supply_order/SO = S
|
||||
menu += "<li>#[SO.id] - [SO.pack.name] requested by [SO.orderer]</li>"
|
||||
menu += "</ol><font size=\"-3\">Upgrade NOW to Space Parts & Space Vendors PLUS for full remote order control and inventory management."
|
||||
|
||||
if (48) // quartermaster ore logs
|
||||
menu = list("<h4>[PDAIMG(crate)] Ore Silo Logs</h4>")
|
||||
if (GLOB.ore_silo_default)
|
||||
var/list/logs = GLOB.silo_access_logs[REF(GLOB.ore_silo_default)]
|
||||
var/len = LAZYLEN(logs)
|
||||
var/i = 0
|
||||
for(var/M in logs)
|
||||
if (++i > 30)
|
||||
menu += "(... older logs not shown ...)"
|
||||
break
|
||||
var/datum/ore_silo_log/entry = M
|
||||
menu += "[len - i]. [entry.formatted]<br><br>"
|
||||
if(i == 0)
|
||||
menu += "Nothing!"
|
||||
else
|
||||
menu += "<b>No ore silo detected!</b>"
|
||||
menu = jointext(menu, "")
|
||||
|
||||
if (49) //janitorial locator
|
||||
menu = "<h4>[PDAIMG(bucket)] Persistent Custodial Object Locator</h4>"
|
||||
|
||||
var/turf/cl = get_turf(src)
|
||||
if (cl)
|
||||
menu += "Current Orbital Location: <b>\[[cl.x],[cl.y]\]</b>"
|
||||
|
||||
menu += "<h4>Located Mops:</h4>"
|
||||
|
||||
var/ldat
|
||||
for (var/obj/item/mop/M in world)
|
||||
var/turf/ml = get_turf(M)
|
||||
|
||||
if(ml)
|
||||
if (ml.z != cl.z)
|
||||
continue
|
||||
var/direction = get_dir(src, M)
|
||||
ldat += "Mop - <b>\[[ml.x],[ml.y] ([uppertext(dir2text(direction))])\]</b> - [M.reagents.total_volume ? "Wet" : "Dry"]<br>"
|
||||
|
||||
if (!ldat)
|
||||
menu += "None"
|
||||
else
|
||||
menu += "[ldat]"
|
||||
|
||||
menu += "<h4>Pimpin' Ride:</h4>"
|
||||
|
||||
ldat = null
|
||||
for (var/obj/vehicle/ridden/janicart/M in world)
|
||||
var/turf/ml = get_turf(M)
|
||||
|
||||
if(ml)
|
||||
if (ml.z != cl.z)
|
||||
continue
|
||||
var/direction = get_dir(src, M)
|
||||
ldat += "Ride - <b>\[[ml.x],[ml.y] ([uppertext(dir2text(direction))])\]</b><br>"
|
||||
|
||||
if (!ldat)
|
||||
menu += "None"
|
||||
else
|
||||
menu += "[ldat]"
|
||||
|
||||
menu += "<h4>Located Janitorial Cart:</h4>"
|
||||
|
||||
ldat = null
|
||||
for (var/obj/structure/janitorialcart/B in world)
|
||||
var/turf/bl = get_turf(B)
|
||||
|
||||
if(bl)
|
||||
if (bl.z != cl.z)
|
||||
continue
|
||||
var/direction = get_dir(src, B)
|
||||
ldat += "Cart - <b>\[[bl.x],[bl.y] ([uppertext(dir2text(direction))])\]</b> - Water level: [B.reagents.total_volume]/100<br>"
|
||||
|
||||
if (!ldat)
|
||||
menu += "None"
|
||||
else
|
||||
menu += "[ldat]"
|
||||
|
||||
menu += "<h4>Located Cleanbots:</h4>"
|
||||
|
||||
ldat = null
|
||||
for (var/mob/living/simple_animal/bot/cleanbot/B in GLOB.alive_mob_list)
|
||||
var/turf/bl = get_turf(B)
|
||||
|
||||
if(bl)
|
||||
if (bl.z != cl.z)
|
||||
continue
|
||||
var/direction = get_dir(src, B)
|
||||
ldat += "Cleanbot - <b>\[[bl.x],[bl.y] ([uppertext(dir2text(direction))])\]</b> - [B.on ? "Online" : "Offline"]<br>"
|
||||
|
||||
if (!ldat)
|
||||
menu += "None"
|
||||
else
|
||||
menu += "[ldat]"
|
||||
|
||||
else
|
||||
menu += "ERROR: Unable to determine current location."
|
||||
menu += "<br><br><A href='byond://?src=[REF(src)];choice=49'>Refresh GPS Locator</a>"
|
||||
|
||||
if (53) // Newscaster
|
||||
menu = "<h4>[PDAIMG(notes)] Newscaster Access</h4>"
|
||||
menu += "<br> Current Newsfeed: <A href='byond://?src=[REF(src)];choice=Newscaster Switch Channel'>[current_channel ? current_channel : "None"]</a> <br>"
|
||||
var/datum/newscaster/feed_channel/current
|
||||
for(var/datum/newscaster/feed_channel/chan in GLOB.news_network.network_channels)
|
||||
if (chan.channel_name == current_channel)
|
||||
current = chan
|
||||
if(!current)
|
||||
menu += "<h5> ERROR : NO CHANNEL FOUND </h5>"
|
||||
return
|
||||
var/i = 1
|
||||
for(var/datum/newscaster/feed_message/msg in current.messages)
|
||||
menu +="-[msg.returnBody(-1)] <BR><FONT SIZE=1>\[Story by <FONT COLOR='maroon'>[msg.returnAuthor(-1)]</FONT>\]</FONT><BR>"
|
||||
menu +="<b><font size=1>[msg.comments.len] comment[msg.comments.len > 1 ? "s" : ""]</font></b><br>"
|
||||
if(msg.img)
|
||||
user << browse_rsc(msg.img, "tmp_photo[i].png")
|
||||
menu +="<img src='tmp_photo[i].png' width = '180'><BR>"
|
||||
i++
|
||||
for(var/datum/newscaster/feed_comment/comment in msg.comments)
|
||||
menu +="<font size=1><small>[comment.body]</font><br><font size=1><small><small><small>[comment.author] [comment.time_stamp]</small></small></small></small></font><br>"
|
||||
menu += "<br> <A href='byond://?src=[REF(src)];choice=Newscaster Message'>Post Message</a>"
|
||||
|
||||
if (54) // Beepsky, Medibot, Floorbot, and Cleanbot access
|
||||
menu = "<h4>[PDAIMG(medbot)] Bots Interlink</h4>"
|
||||
bot_control()
|
||||
if (99) //Newscaster message permission error
|
||||
menu = "<h5> ERROR : NOT AUTHORIZED [host_pda.id ? "" : "- ID SLOT EMPTY"] </h5>"
|
||||
|
||||
return menu
|
||||
|
||||
/obj/item/cartridge/Topic(href, href_list)
|
||||
..()
|
||||
|
||||
if(!usr.canUseTopic(src, !issilicon(usr)))
|
||||
usr.unset_machine()
|
||||
usr << browse(null, "window=pda")
|
||||
return
|
||||
|
||||
switch(href_list["choice"])
|
||||
if("Medical Records")
|
||||
active1 = find_record("id", href_list["target"], GLOB.data_core.general)
|
||||
if(active1)
|
||||
active2 = find_record("id", href_list["target"], GLOB.data_core.medical)
|
||||
host_pda.mode = 441
|
||||
if(!active2)
|
||||
active1 = null
|
||||
playsound(src, 'sound/machines/terminal_select.ogg', 50, 1)
|
||||
|
||||
if("Security Records")
|
||||
active1 = find_record("id", href_list["target"], GLOB.data_core.general)
|
||||
if(active1)
|
||||
active3 = find_record("id", href_list["target"], GLOB.data_core.security)
|
||||
host_pda.mode = 451
|
||||
if(!active3)
|
||||
active1 = null
|
||||
playsound(src, 'sound/machines/terminal_select.ogg', 50, 1)
|
||||
|
||||
if("Send Signal")
|
||||
INVOKE_ASYNC(radio, /obj/item/integrated_signaler.proc/send_activation)
|
||||
playsound(src, 'sound/machines/terminal_select.ogg', 50, 1)
|
||||
|
||||
if("Signal Frequency")
|
||||
var/new_frequency = sanitize_frequency(radio.frequency + text2num(href_list["sfreq"]))
|
||||
radio.set_frequency(new_frequency)
|
||||
playsound(src, 'sound/machines/terminal_select.ogg', 50, 1)
|
||||
|
||||
if("Signal Code")
|
||||
radio.code += text2num(href_list["scode"])
|
||||
radio.code = round(radio.code)
|
||||
radio.code = min(100, radio.code)
|
||||
radio.code = max(1, radio.code)
|
||||
playsound(src, 'sound/machines/terminal_select.ogg', 50, 1)
|
||||
|
||||
if("Status")
|
||||
switch(href_list["statdisp"])
|
||||
if("message")
|
||||
post_status("message", message1, message2)
|
||||
if("alert")
|
||||
post_status("alert", href_list["alert"])
|
||||
if("setmsg1")
|
||||
message1 = reject_bad_text(input("Line 1", "Enter Message Text", message1) as text|null, 40)
|
||||
updateSelfDialog()
|
||||
if("setmsg2")
|
||||
message2 = reject_bad_text(input("Line 2", "Enter Message Text", message2) as text|null, 40)
|
||||
updateSelfDialog()
|
||||
else
|
||||
post_status(href_list["statdisp"])
|
||||
playsound(src, 'sound/machines/terminal_select.ogg', 50, 1)
|
||||
|
||||
if("Power Select")
|
||||
var/pnum = text2num(href_list["target"])
|
||||
powmonitor = powermonitors[pnum]
|
||||
host_pda.mode = 433
|
||||
playsound(src, 'sound/machines/terminal_select.ogg', 50, 1)
|
||||
|
||||
if("Supply Orders")
|
||||
host_pda.mode =47
|
||||
playsound(src, 'sound/machines/terminal_select.ogg', 50, 1)
|
||||
|
||||
if("Newscaster Access")
|
||||
host_pda.mode = 53
|
||||
playsound(src, 'sound/machines/terminal_select.ogg', 50, 1)
|
||||
|
||||
if("Newscaster Message")
|
||||
var/host_pda_owner_name = host_pda.id ? "[host_pda.id.registered_name] ([host_pda.id.assignment])" : "Unknown"
|
||||
var/message = host_pda.msg_input()
|
||||
var/datum/newscaster/feed_channel/current
|
||||
for(var/datum/newscaster/feed_channel/chan in GLOB.news_network.network_channels)
|
||||
if (chan.channel_name == current_channel)
|
||||
current = chan
|
||||
if(current.locked && current.author != host_pda_owner_name)
|
||||
host_pda.mode = 99
|
||||
host_pda.Topic(null,list("choice"="Refresh"))
|
||||
return
|
||||
GLOB.news_network.SubmitArticle(message,host_pda.owner,current_channel)
|
||||
host_pda.Topic(null,list("choice"=num2text(host_pda.mode)))
|
||||
return
|
||||
playsound(src, 'sound/machines/terminal_select.ogg', 50, 1)
|
||||
|
||||
if("Newscaster Switch Channel")
|
||||
current_channel = host_pda.msg_input()
|
||||
host_pda.Topic(null,list("choice"=num2text(host_pda.mode)))
|
||||
return
|
||||
playsound(src, 'sound/machines/terminal_select.ogg', 50, 1)
|
||||
|
||||
//Bot control section! Viciously ripped from radios for being laggy and terrible.
|
||||
if(href_list["op"])
|
||||
switch(href_list["op"])
|
||||
|
||||
if("control")
|
||||
active_bot = locate(href_list["bot"])
|
||||
|
||||
if("botlist")
|
||||
active_bot = null
|
||||
|
||||
if("summon") //Args are in the correct order, they are stated here just as an easy reminder.
|
||||
active_bot.bot_control(command= "summon", user_turf= get_turf(usr), user_access= host_pda.GetAccess())
|
||||
|
||||
else //Forward all other bot commands to the bot itself!
|
||||
active_bot.bot_control(command= href_list["op"], user= usr)
|
||||
playsound(src, 'sound/machines/terminal_select.ogg', 50, 1)
|
||||
|
||||
if(href_list["mule"]) //MULEbots are special snowflakes, and need different args due to how they work.
|
||||
|
||||
active_bot.bot_control(command= href_list["mule"], user= usr, pda= 1)
|
||||
|
||||
if(!host_pda)
|
||||
return
|
||||
host_pda.attack_self(usr)
|
||||
|
||||
|
||||
/obj/item/cartridge/proc/bot_control()
|
||||
|
||||
|
||||
var/mob/living/simple_animal/bot/Bot
|
||||
|
||||
if(active_bot)
|
||||
menu += "<B>[active_bot]</B><BR> Status: (<A href='byond://?src=[REF(src)];op=control;bot=[REF(active_bot)]'>[PDAIMG(refresh)]<i>refresh</i></A>)<BR>"
|
||||
menu += "Model: [active_bot.model]<BR>"
|
||||
menu += "Location: [get_area(active_bot)]<BR>"
|
||||
menu += "Mode: [active_bot.get_mode()]"
|
||||
if(active_bot.allow_pai)
|
||||
menu += "<BR>pAI: "
|
||||
if(active_bot.paicard && active_bot.paicard.pai)
|
||||
menu += "[active_bot.paicard.pai.name]"
|
||||
if(active_bot.bot_core.allowed(usr))
|
||||
menu += " (<A href='byond://?src=[REF(src)];op=ejectpai'><i>eject</i></A>)"
|
||||
else
|
||||
menu += "<i>none</i>"
|
||||
|
||||
//MULEs!
|
||||
if(active_bot.bot_type == MULE_BOT)
|
||||
var/mob/living/simple_animal/bot/mulebot/MULE = active_bot
|
||||
var/atom/Load = MULE.load
|
||||
menu += "<BR>Current Load: [ !Load ? "<i>none</i>" : "[Load.name] (<A href='byond://?src=[REF(src)];mule=unload'><i>unload</i></A>)" ]<BR>"
|
||||
menu += "Destination: [MULE.destination ? MULE.destination : "<i>None</i>"] (<A href='byond://?src=[REF(src)];mule=destination'><i>set</i></A>)<BR>"
|
||||
menu += "Set ID: [MULE.suffix] <A href='byond://?src=[REF(src)];mule=setid'><i> Modify</i></A><BR>"
|
||||
menu += "Power: [MULE.cell ? MULE.cell.percent() : 0]%<BR>"
|
||||
menu += "Home: [!MULE.home_destination ? "<i>none</i>" : MULE.home_destination ]<BR>"
|
||||
menu += "Delivery Reporting: <A href='byond://?src=[REF(src)];mule=report'>[MULE.report_delivery ? "(<B>On</B>)": "(<B>Off</B>)"]</A><BR>"
|
||||
menu += "Auto Return Home: <A href='byond://?src=[REF(src)];mule=autoret'>[MULE.auto_return ? "(<B>On</B>)": "(<B>Off</B>)"]</A><BR>"
|
||||
menu += "Auto Pickup Crate: <A href='byond://?src=[REF(src)];mule=autopick'>[MULE.auto_pickup ? "(<B>On</B>)": "(<B>Off</B>)"]</A><BR><BR>" //Hue.
|
||||
|
||||
menu += "\[<A href='byond://?src=[REF(src)];mule=stop'>Stop</A>\] "
|
||||
menu += "\[<A href='byond://?src=[REF(src)];mule=go'>Proceed</A>\] "
|
||||
menu += "\[<A href='byond://?src=[REF(src)];mule=home'>Return Home</A>\]<BR>"
|
||||
|
||||
else
|
||||
menu += "<BR>\[<A href='byond://?src=[REF(src)];op=patroloff'>Stop Patrol</A>\] " //patrolon
|
||||
menu += "\[<A href='byond://?src=[REF(src)];op=patrolon'>Start Patrol</A>\] " //patroloff
|
||||
menu += "\[<A href='byond://?src=[REF(src)];op=summon'>Summon Bot</A>\]<BR>" //summon
|
||||
menu += "Keep an ID inserted to upload access codes upon summoning."
|
||||
|
||||
menu += "<HR><A href='byond://?src=[REF(src)];op=botlist'>[PDAIMG(back)]Return to bot list</A>"
|
||||
else
|
||||
menu += "<BR><A href='byond://?src=[REF(src)];op=botlist'>[PDAIMG(refresh)]Scan for active bots</A><BR><BR>"
|
||||
var/turf/current_turf = get_turf(src)
|
||||
var/zlevel = current_turf.z
|
||||
var/botcount = 0
|
||||
for(Bot in GLOB.alive_mob_list) //Git da botz
|
||||
if(!Bot.on || Bot.z != zlevel || Bot.remote_disabled || !(bot_access_flags & Bot.bot_type)) //Only non-emagged bots on the same Z-level are detected!
|
||||
continue //Also, the PDA must have access to the bot type.
|
||||
menu += "<A href='byond://?src=[REF(src)];op=control;bot=[REF(Bot)]'><b>[Bot.name]</b> ([Bot.get_mode()])<BR>"
|
||||
botcount++
|
||||
if(!botcount) //No bots at all? Lame.
|
||||
menu += "No bots found.<BR>"
|
||||
return
|
||||
|
||||
return menu
|
||||
|
||||
//If the cartridge adds a special line to the top of the messaging app
|
||||
/obj/item/cartridge/proc/message_header()
|
||||
return ""
|
||||
|
||||
//If the cartridge adds something to each potetial messaging target
|
||||
/obj/item/cartridge/proc/message_special(obj/item/pda/target)
|
||||
return ""
|
||||
|
||||
//This is called for special abilities of cartridges
|
||||
/obj/item/cartridge/proc/special(mov/living/user, list/params)
|
||||
@@ -0,0 +1,38 @@
|
||||
// Radio Cartridge, essentially a remote signaler with limited spectrum.
|
||||
/obj/item/integrated_signaler
|
||||
name = "\improper PDA radio module"
|
||||
desc = "An electronic radio system of Nanotrasen origin."
|
||||
icon = 'icons/obj/module.dmi'
|
||||
icon_state = "power_mod"
|
||||
|
||||
/obj/item/integrated_signaler
|
||||
var/frequency = FREQ_SIGNALER
|
||||
var/code = DEFAULT_SIGNALER_CODE
|
||||
var/last_transmission
|
||||
var/datum/radio_frequency/radio_connection
|
||||
|
||||
/obj/item/integrated_signaler/Destroy()
|
||||
radio_connection = null
|
||||
return ..()
|
||||
|
||||
/obj/item/integrated_signaler/Initialize()
|
||||
. = ..()
|
||||
if (frequency < MIN_FREE_FREQ || frequency > MAX_FREE_FREQ)
|
||||
frequency = sanitize_frequency(frequency)
|
||||
set_frequency(frequency)
|
||||
|
||||
/obj/item/integrated_signaler/proc/set_frequency(new_frequency)
|
||||
frequency = new_frequency
|
||||
radio_connection = SSradio.return_frequency(frequency)
|
||||
|
||||
/obj/item/integrated_signaler/proc/send_activation()
|
||||
if(last_transmission && world.time < (last_transmission + 5))
|
||||
return
|
||||
last_transmission = world.time
|
||||
|
||||
var/time = time2text(world.realtime,"hh:mm:ss")
|
||||
var/turf/T = get_turf(src)
|
||||
GLOB.lastsignalers.Add("[time] <B>:</B> [usr.key] used [src] @ location [AREACOORD(T)] <B>:</B> [format_frequency(frequency)]/[code]")
|
||||
|
||||
var/datum/signal/signal = new(list("code" = code))
|
||||
radio_connection.post_signal(src, signal, filter = RADIO_SIGNALER)
|
||||
@@ -0,0 +1,108 @@
|
||||
/obj/item/cartridge/virus
|
||||
name = "Generic Virus PDA cart"
|
||||
var/charges = 5
|
||||
|
||||
/obj/item/cartridge/virus/proc/send_virus(obj/item/pda/target, mob/living/U)
|
||||
return
|
||||
|
||||
/obj/item/cartridge/virus/message_header()
|
||||
return "<b>[charges] viral files left.</b><HR>"
|
||||
|
||||
/obj/item/cartridge/virus/message_special(obj/item/pda/target)
|
||||
if (!istype(loc, /obj/item/pda))
|
||||
return "" //Sanity check, this shouldn't be possible.
|
||||
return " (<a href='byond://?src=[REF(loc)];choice=cart;special=virus;target=[REF(target)]'>*Send Virus*</a>)"
|
||||
|
||||
/obj/item/cartridge/virus/special(mob/living/user, list/params)
|
||||
var/obj/item/pda/P = locate(params["target"])//Leaving it alone in case it may do something useful, I guess.
|
||||
send_virus(P,user)
|
||||
|
||||
/obj/item/cartridge/virus/clown
|
||||
name = "\improper Honkworks 5.0 cartridge"
|
||||
icon_state = "cart-clown"
|
||||
desc = "A data cartridge for portable microcomputers. It smells vaguely of bananas."
|
||||
access = CART_CLOWN
|
||||
|
||||
/obj/item/cartridge/virus/clown/send_virus(obj/item/pda/target, mob/living/U)
|
||||
if(charges <= 0)
|
||||
to_chat(U, "<span class='notice'>Out of charges.</span>")
|
||||
return
|
||||
if(!isnull(target) && !target.toff)
|
||||
charges--
|
||||
to_chat(U, "<span class='notice'>Virus Sent!</span>")
|
||||
target.honkamt = (rand(15,20))
|
||||
else
|
||||
to_chat(U, "PDA not found.")
|
||||
|
||||
/obj/item/cartridge/virus/mime
|
||||
name = "\improper Gestur-O 1000 cartridge"
|
||||
icon_state = "cart-mi"
|
||||
access = CART_MIME
|
||||
|
||||
/obj/item/cartridge/virus/mime/send_virus(obj/item/pda/target, mob/living/U)
|
||||
if(charges <= 0)
|
||||
to_chat(U, "<span class='notice'>Out of charges.</span>")
|
||||
return
|
||||
if(!isnull(target) && !target.toff)
|
||||
charges--
|
||||
to_chat(U, "<span class='notice'>Virus Sent!</span>")
|
||||
target.silent = TRUE
|
||||
target.ttone = "silence"
|
||||
else
|
||||
to_chat(U, "PDA not found.")
|
||||
|
||||
/obj/item/cartridge/virus/syndicate
|
||||
name = "\improper Detomatix cartridge"
|
||||
access = CART_REMOTE_DOOR
|
||||
remote_door_id = "smindicate" //Make sure this matches the syndicate shuttle's shield/door id!! //don't ask about the name, testing.
|
||||
charges = 4
|
||||
|
||||
/obj/item/cartridge/virus/syndicate/send_virus(obj/item/pda/target, mob/living/U)
|
||||
if(charges <= 0)
|
||||
to_chat(U, "<span class='notice'>Out of charges.</span>")
|
||||
return
|
||||
if(!isnull(target) && !target.toff)
|
||||
charges--
|
||||
var/difficulty = 0
|
||||
if(target.cartridge)
|
||||
difficulty += BitCount(target.cartridge.access&(CART_MEDICAL | CART_SECURITY | CART_ENGINE | CART_CLOWN | CART_JANITOR | CART_MANIFEST))
|
||||
if(target.cartridge.access & CART_MANIFEST)
|
||||
difficulty++ //if cartridge has manifest access it has extra snowflake difficulty
|
||||
else
|
||||
difficulty += 2
|
||||
GET_COMPONENT_FROM(hidden_uplink, /datum/component/uplink, target)
|
||||
if(!target.detonatable || prob(difficulty * 15) || (hidden_uplink))
|
||||
U.show_message("<span class='danger'>An error flashes on your [src].</span>", 1)
|
||||
else
|
||||
message_admins("[!is_special_character(U) ? "Non-antag " : ""][ADMIN_LOOKUPFLW(U)] triggered a PDA explosion on [target.name] at [ADMIN_VERBOSEJMP(target)].")
|
||||
var/message_log = "triggered a PDA explosion on [target.name] at [AREACOORD(target)]."
|
||||
U.log_message(message_log, LOG_ATTACK)
|
||||
U.show_message("<span class='notice'>Success!</span>", 1)
|
||||
target.explode()
|
||||
else
|
||||
to_chat(U, "PDA not found.")
|
||||
|
||||
/obj/item/cartridge/virus/frame
|
||||
name = "\improper F.R.A.M.E. cartridge"
|
||||
icon_state = "cart-f"
|
||||
var/telecrystals = 0
|
||||
|
||||
/obj/item/cartridge/virus/frame/send_virus(obj/item/pda/target, mob/living/U)
|
||||
if(charges <= 0)
|
||||
to_chat(U, "<span class='notice'>Out of charges.</span>")
|
||||
return
|
||||
if(!isnull(target) && !target.toff)
|
||||
charges--
|
||||
var/lock_code = "[rand(100,999)] [pick(GLOB.phonetic_alphabet)]"
|
||||
to_chat(U, "<span class='notice'>Virus Sent! The unlock code to the target is: [lock_code]</span>")
|
||||
GET_COMPONENT_FROM(hidden_uplink, /datum/component/uplink, target)
|
||||
if(!hidden_uplink)
|
||||
hidden_uplink = target.AddComponent(/datum/component/uplink)
|
||||
hidden_uplink.unlock_code = lock_code
|
||||
else
|
||||
hidden_uplink.hidden_crystals += hidden_uplink.telecrystals //Temporarially hide the PDA's crystals, so you can't steal telecrystals.
|
||||
hidden_uplink.telecrystals = telecrystals
|
||||
telecrystals = 0
|
||||
hidden_uplink.active = TRUE
|
||||
else
|
||||
to_chat(U, "PDA not found.")
|
||||
@@ -0,0 +1,97 @@
|
||||
/obj/item/aicard
|
||||
name = "intelliCard"
|
||||
desc = "A storage device for AIs. Patent pending."
|
||||
icon = 'icons/obj/aicards.dmi'
|
||||
icon_state = "aicard" // aicard-full
|
||||
item_state = "electronic"
|
||||
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
slot_flags = ITEM_SLOT_BELT
|
||||
item_flags = NOBLUDGEON
|
||||
var/flush = FALSE
|
||||
var/mob/living/silicon/ai/AI
|
||||
|
||||
/obj/item/aicard/aitater
|
||||
name = "intelliTater"
|
||||
desc = "A stylish upgrade (?) to the intelliCard."
|
||||
icon_state = "aitater"
|
||||
|
||||
/obj/item/aicard/suicide_act(mob/living/user)
|
||||
user.visible_message("<span class='suicide'>[user] is trying to upload [user.p_them()]self into [src]! That's not going to work out well!</span>")
|
||||
return BRUTELOSS
|
||||
|
||||
/obj/item/aicard/afterattack(atom/target, mob/user, proximity)
|
||||
. = ..()
|
||||
if(!proximity || !target)
|
||||
return
|
||||
if(AI) //AI is on the card, implies user wants to upload it.
|
||||
target.transfer_ai(AI_TRANS_FROM_CARD, user, AI, src)
|
||||
log_combat(user, AI, "carded", src)
|
||||
else //No AI on the card, therefore the user wants to download one.
|
||||
target.transfer_ai(AI_TRANS_TO_CARD, user, null, src)
|
||||
update_icon() //Whatever happened, update the card's state (icon, name) to match.
|
||||
|
||||
/obj/item/aicard/update_icon()
|
||||
cut_overlays()
|
||||
if(AI)
|
||||
name = "[initial(name)]- [AI.name]"
|
||||
if(AI.stat == DEAD)
|
||||
icon_state = "[initial(icon_state)]-404"
|
||||
else
|
||||
icon_state = "[initial(icon_state)]-full"
|
||||
if(!AI.control_disabled)
|
||||
add_overlay("[initial(icon_state)]-on")
|
||||
AI.cancel_camera()
|
||||
else
|
||||
name = initial(name)
|
||||
icon_state = initial(icon_state)
|
||||
|
||||
/obj/item/aicard/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)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "intellicard", name, 500, 500, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/item/aicard/ui_data()
|
||||
var/list/data = list()
|
||||
if(AI)
|
||||
data["name"] = AI.name
|
||||
data["laws"] = AI.laws.get_law_list(include_zeroth = 1)
|
||||
data["health"] = (AI.health + 100) / 2
|
||||
data["wireless"] = !AI.control_disabled //todo disabled->enabled
|
||||
data["radio"] = AI.radio_enabled
|
||||
data["isDead"] = AI.stat == DEAD
|
||||
data["isBraindead"] = AI.client ? FALSE : TRUE
|
||||
data["wiping"] = flush
|
||||
return data
|
||||
|
||||
/obj/item/aicard/ui_act(action,params)
|
||||
if(..())
|
||||
return
|
||||
switch(action)
|
||||
if("wipe")
|
||||
if(flush)
|
||||
flush = FALSE
|
||||
else
|
||||
var/confirm = alert("Are you sure you want to wipe this card's memory?", name, "Yes", "No")
|
||||
if(confirm == "Yes" && !..())
|
||||
flush = TRUE
|
||||
if(AI && AI.loc == src)
|
||||
to_chat(AI, "Your core files are being wiped!")
|
||||
while(AI.stat != DEAD && flush)
|
||||
AI.adjustOxyLoss(1)
|
||||
AI.updatehealth()
|
||||
sleep(5)
|
||||
flush = FALSE
|
||||
. = TRUE
|
||||
if("wireless")
|
||||
AI.control_disabled = !AI.control_disabled
|
||||
to_chat(AI, "[src]'s wireless port has been [AI.control_disabled ? "disabled" : "enabled"]!")
|
||||
. = TRUE
|
||||
if("radio")
|
||||
AI.radio_enabled = !AI.radio_enabled
|
||||
to_chat(AI, "Your Subspace Transceiver has been [AI.radio_enabled ? "enabled" : "disabled"]!")
|
||||
. = TRUE
|
||||
update_icon()
|
||||
@@ -0,0 +1,21 @@
|
||||
/obj/item/anomaly_neutralizer
|
||||
name = "anomaly neutralizer"
|
||||
desc = "A one-use device capable of instantly neutralizing anomalies."
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "memorizer2"
|
||||
item_state = "electronic"
|
||||
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
slot_flags = ITEM_SLOT_BELT
|
||||
item_flags = NOBLUDGEON
|
||||
|
||||
/obj/item/anomaly_neutralizer/afterattack(atom/target, mob/user, proximity)
|
||||
..()
|
||||
if(!proximity || !target)
|
||||
return
|
||||
if(istype(target, /obj/effect/anomaly))
|
||||
var/obj/effect/anomaly/A = target
|
||||
to_chat(user, "<span class='notice'>The circuitry of [src] fries from the strain of neutralizing [A]!</span>")
|
||||
A.anomalyNeutralize()
|
||||
qdel(src)
|
||||
@@ -0,0 +1,44 @@
|
||||
/obj/item/beacon
|
||||
name = "\improper tracking beacon"
|
||||
desc = "A beacon used by a teleporter."
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "beacon"
|
||||
item_state = "beacon"
|
||||
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
|
||||
var/enabled = TRUE
|
||||
var/renamed = FALSE
|
||||
|
||||
/obj/item/beacon/Initialize()
|
||||
. = ..()
|
||||
if (enabled)
|
||||
GLOB.teleportbeacons += src
|
||||
else
|
||||
icon_state = "beacon-off"
|
||||
|
||||
/obj/item/beacon/Destroy()
|
||||
GLOB.teleportbeacons.Remove(src)
|
||||
return ..()
|
||||
|
||||
/obj/item/beacon/attack_self(mob/user)
|
||||
enabled = !enabled
|
||||
if (enabled)
|
||||
icon_state = "beacon"
|
||||
GLOB.teleportbeacons += src
|
||||
else
|
||||
icon_state = "beacon-off"
|
||||
GLOB.teleportbeacons.Remove(src)
|
||||
to_chat(user, "<span class='notice'>You [enabled ? "enable" : "disable"] the beacon.</span>")
|
||||
return
|
||||
|
||||
/obj/item/beacon/attackby(obj/item/W, mob/user)
|
||||
if(istype(W, /obj/item/pen)) // needed for things that use custom names like the locator
|
||||
var/new_name = stripped_input(user, "What would you like the name to be?")
|
||||
if(!user.canUseTopic(src, BE_CLOSE))
|
||||
return
|
||||
if(new_name)
|
||||
name = new_name
|
||||
renamed = TRUE
|
||||
return
|
||||
else
|
||||
return ..()
|
||||
@@ -0,0 +1,308 @@
|
||||
|
||||
#define BUGMODE_LIST 0
|
||||
#define BUGMODE_MONITOR 1
|
||||
#define BUGMODE_TRACK 2
|
||||
|
||||
|
||||
|
||||
/obj/item/camera_bug
|
||||
name = "camera bug"
|
||||
desc = "For illicit snooping through the camera network."
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "camera_bug"
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
item_state = "camera_bug"
|
||||
throw_speed = 4
|
||||
throw_range = 20
|
||||
item_flags = NOBLUDGEON
|
||||
|
||||
var/obj/machinery/camera/current = null
|
||||
|
||||
var/last_net_update = 0
|
||||
var/list/bugged_cameras = list()
|
||||
|
||||
var/track_mode = BUGMODE_LIST
|
||||
var/last_tracked = 0
|
||||
var/refresh_interval = 50
|
||||
|
||||
var/tracked_name = null
|
||||
var/atom/tracking = null
|
||||
|
||||
var/last_found = null
|
||||
var/last_seen = null
|
||||
|
||||
/obj/item/camera_bug/New()
|
||||
..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/camera_bug/Destroy()
|
||||
get_cameras()
|
||||
for(var/cam_tag in bugged_cameras)
|
||||
var/obj/machinery/camera/camera = bugged_cameras[cam_tag]
|
||||
if(camera.bug == src)
|
||||
camera.bug = null
|
||||
bugged_cameras = list()
|
||||
if(tracking)
|
||||
tracking = null
|
||||
return ..()
|
||||
|
||||
/obj/item/camera_bug/interact(mob/user)
|
||||
ui_interact(user)
|
||||
|
||||
/obj/item/camera_bug/ui_interact(mob/user = usr)
|
||||
. = ..()
|
||||
var/datum/browser/popup = new(user, "camerabug","Camera Bug",nref=src)
|
||||
popup.set_content(menu(get_cameras()))
|
||||
popup.open()
|
||||
|
||||
/obj/item/camera_bug/attack_self(mob/user)
|
||||
user.set_machine(src)
|
||||
interact(user)
|
||||
|
||||
/obj/item/camera_bug/check_eye(mob/user)
|
||||
if ( loc != user || user.incapacitated() || user.eye_blind || !current )
|
||||
user.unset_machine()
|
||||
return 0
|
||||
var/turf/T_user = get_turf(user.loc)
|
||||
var/turf/T_current = get_turf(current)
|
||||
if(T_user.z != T_current.z || !current.can_use())
|
||||
to_chat(user, "<span class='danger'>[src] has lost the signal.</span>")
|
||||
current = null
|
||||
user.unset_machine()
|
||||
return 0
|
||||
return 1
|
||||
/obj/item/camera_bug/on_unset_machine(mob/user)
|
||||
user.reset_perspective(null)
|
||||
|
||||
/obj/item/camera_bug/proc/get_cameras()
|
||||
if( world.time > (last_net_update + 100))
|
||||
bugged_cameras = list()
|
||||
for(var/obj/machinery/camera/camera in GLOB.cameranet.cameras)
|
||||
if(camera.stat || !camera.can_use())
|
||||
continue
|
||||
if(length(list("ss13","mine", "rd", "labor", "toxins", "minisat")&camera.network))
|
||||
bugged_cameras[camera.c_tag] = camera
|
||||
return sortList(bugged_cameras)
|
||||
|
||||
|
||||
/obj/item/camera_bug/proc/menu(list/cameras)
|
||||
if(!cameras || !cameras.len)
|
||||
return "No bugged cameras found."
|
||||
|
||||
var/html
|
||||
switch(track_mode)
|
||||
if(BUGMODE_LIST)
|
||||
html = "<h3>Select a camera:</h3> <a href='?src=[REF(src)];view'>\[Cancel camera view\]</a><hr><table>"
|
||||
for(var/entry in cameras)
|
||||
var/obj/machinery/camera/C = cameras[entry]
|
||||
var/functions = ""
|
||||
if(C.bug == src)
|
||||
functions = " - <a href='?src=[REF(src)];monitor=[REF(C)]'>\[Monitor\]</a> <a href='?src=[REF(src)];emp=[REF(C)]'>\[Disable\]</a>"
|
||||
else
|
||||
functions = " - <a href='?src=[REF(src)];monitor=[REF(C)]'>\[Monitor\]</a>"
|
||||
html += "<tr><td><a href='?src=[REF(src)];view=[REF(C)]'>[entry]</a></td><td>[functions]</td></tr>"
|
||||
|
||||
if(BUGMODE_MONITOR)
|
||||
if(current)
|
||||
html = "Analyzing Camera '[current.c_tag]' <a href='?[REF(src)];mode=0'>\[Select Camera\]</a><br>"
|
||||
html += camera_report()
|
||||
else
|
||||
track_mode = BUGMODE_LIST
|
||||
return .(cameras)
|
||||
if(BUGMODE_TRACK)
|
||||
if(tracking)
|
||||
html = "Tracking '[tracked_name]' <a href='?[REF(src)];mode=0'>\[Cancel Tracking\]</a> <a href='?src=[REF(src)];view'>\[Cancel camera view\]</a><br>"
|
||||
if(last_found)
|
||||
var/time_diff = round((world.time - last_seen) / 150)
|
||||
var/obj/machinery/camera/C = bugged_cameras[last_found]
|
||||
var/outstring
|
||||
if(C)
|
||||
outstring = "<a href='?[REF(src)];view=[REF(C)]'>[last_found]</a>"
|
||||
else
|
||||
outstring = last_found
|
||||
if(!time_diff)
|
||||
html += "Last seen near [outstring] (now)<br>"
|
||||
else
|
||||
// 15 second intervals ~ 1/4 minute
|
||||
var/m = round(time_diff/4)
|
||||
var/s = (time_diff - 4*m) * 15
|
||||
if(!s)
|
||||
s = "00"
|
||||
html += "Last seen near [outstring] ([m]:[s] minute\s ago)<br>"
|
||||
if( C && (C.bug == src)) //Checks to see if the camera has a bug
|
||||
html += "<a href='?src=[REF(src)];emp=[REF(C)]'>\[Disable\]</a>"
|
||||
|
||||
else
|
||||
html += "Not yet seen."
|
||||
else
|
||||
track_mode = BUGMODE_LIST
|
||||
return .(cameras)
|
||||
return html
|
||||
|
||||
/obj/item/camera_bug/proc/get_seens()
|
||||
if(current && current.can_use())
|
||||
var/list/seen = current.can_see()
|
||||
return seen
|
||||
|
||||
/obj/item/camera_bug/proc/camera_report()
|
||||
// this should only be called if current exists
|
||||
var/dat = ""
|
||||
var/list/seen = get_seens()
|
||||
if(seen && seen.len >= 1)
|
||||
var/list/names = list()
|
||||
for(var/obj/singularity/S in seen) // god help you if you see more than one
|
||||
if(S.name in names)
|
||||
names[S.name]++
|
||||
dat += "[S.name] ([names[S.name]])"
|
||||
else
|
||||
names[S.name] = 1
|
||||
dat += "[S.name]"
|
||||
var/stage = round(S.current_size / 2)+1
|
||||
dat += " (Stage [stage])"
|
||||
dat += " <a href='?[REF(src)];track=[REF(S)]'>\[Track\]</a><br>"
|
||||
|
||||
for(var/obj/mecha/M in seen)
|
||||
if(M.name in names)
|
||||
names[M.name]++
|
||||
dat += "[M.name] ([names[M.name]])"
|
||||
else
|
||||
names[M.name] = 1
|
||||
dat += "[M.name]"
|
||||
dat += " <a href='?[REF(src)];track=[REF(M)]'>\[Track\]</a><br>"
|
||||
|
||||
|
||||
for(var/mob/living/M in seen)
|
||||
if(M.name in names)
|
||||
names[M.name]++
|
||||
dat += "[M.name] ([names[M.name]])"
|
||||
else
|
||||
names[M.name] = 1
|
||||
dat += "[M.name]"
|
||||
if(M.buckled && !M.lying)
|
||||
dat += " (Sitting)"
|
||||
if(M.lying)
|
||||
dat += " (Laying down)"
|
||||
dat += " <a href='?[REF(src)];track=[REF(M)]'>\[Track\]</a><br>"
|
||||
if(length(dat) == 0)
|
||||
dat += "No motion detected."
|
||||
return dat
|
||||
else
|
||||
return "Camera Offline<br>"
|
||||
|
||||
/obj/item/camera_bug/Topic(href,list/href_list)
|
||||
if(usr != loc)
|
||||
usr.unset_machine()
|
||||
usr << browse(null, "window=camerabug")
|
||||
return
|
||||
usr.set_machine(src)
|
||||
if("mode" in href_list)
|
||||
track_mode = text2num(href_list["mode"])
|
||||
if("monitor" in href_list)
|
||||
//You can't locate on a list with keys
|
||||
var/list/cameras = flatten_list(bugged_cameras)
|
||||
var/obj/machinery/camera/C = locate(href_list["monitor"]) in cameras
|
||||
if(C && istype(C))
|
||||
if(!same_z_level(C))
|
||||
return
|
||||
track_mode = BUGMODE_MONITOR
|
||||
current = C
|
||||
usr.reset_perspective(null)
|
||||
interact()
|
||||
if("track" in href_list)
|
||||
var/list/seen = get_seens()
|
||||
if(seen && seen.len >= 1)
|
||||
var/atom/A = locate(href_list["track"]) in seen
|
||||
if(A && istype(A))
|
||||
tracking = A
|
||||
tracked_name = A.name
|
||||
last_found = current.c_tag
|
||||
last_seen = world.time
|
||||
track_mode = BUGMODE_TRACK
|
||||
if("emp" in href_list)
|
||||
//You can't locate on a list with keys
|
||||
var/list/cameras = flatten_list(bugged_cameras)
|
||||
var/obj/machinery/camera/C = locate(href_list["emp"]) in cameras
|
||||
if(C && istype(C) && C.bug == src)
|
||||
if(!same_z_level(C))
|
||||
return
|
||||
C.emp_act(EMP_HEAVY)
|
||||
C.bug = null
|
||||
bugged_cameras -= C.c_tag
|
||||
interact()
|
||||
return
|
||||
if("close" in href_list)
|
||||
usr.unset_machine()
|
||||
current = null
|
||||
return
|
||||
if("view" in href_list)
|
||||
//You can't locate on a list with keys
|
||||
var/list/cameras = flatten_list(bugged_cameras)
|
||||
var/obj/machinery/camera/C = locate(href_list["view"]) in cameras
|
||||
if(C && istype(C))
|
||||
if(!same_z_level(C))
|
||||
return
|
||||
if(!C.can_use())
|
||||
to_chat(usr, "<span class='warning'>Something's wrong with that camera! You can't get a feed.</span>")
|
||||
return
|
||||
current = C
|
||||
spawn(6)
|
||||
if(src.check_eye(usr))
|
||||
usr.reset_perspective(C)
|
||||
interact()
|
||||
else
|
||||
usr.unset_machine()
|
||||
usr << browse(null, "window=camerabug")
|
||||
return
|
||||
else
|
||||
usr.unset_machine()
|
||||
|
||||
interact()
|
||||
|
||||
/obj/item/camera_bug/process()
|
||||
if(track_mode == BUGMODE_LIST || (world.time < (last_tracked + refresh_interval)))
|
||||
return
|
||||
last_tracked = world.time
|
||||
if(track_mode == BUGMODE_TRACK ) // search for user
|
||||
// Note that it will be tricked if your name appears to change.
|
||||
// This is not optimal but it is better than tracking you relentlessly despite everything.
|
||||
if(!tracking)
|
||||
src.updateSelfDialog()
|
||||
return
|
||||
|
||||
if(tracking.name != tracked_name) // Hiding their identity, tricksy
|
||||
var/mob/M = tracking
|
||||
if(istype(M))
|
||||
if(!(tracked_name == "Unknown" && findtext(tracking.name,"Unknown"))) // we saw then disguised before
|
||||
if(!(tracked_name == M.real_name && findtext(tracking.name,M.real_name))) // or they're still ID'd
|
||||
src.updateSelfDialog()//But if it's neither of those cases
|
||||
return // you won't find em on the cameras
|
||||
else
|
||||
src.updateSelfDialog()
|
||||
return
|
||||
|
||||
var/list/tracking_cams = list()
|
||||
var/list/b_cams = get_cameras()
|
||||
for(var/entry in b_cams)
|
||||
tracking_cams += b_cams[entry]
|
||||
var/list/target_region = view(tracking)
|
||||
|
||||
for(var/obj/machinery/camera/C in (target_region & tracking_cams))
|
||||
if(!can_see(C,tracking)) // target may have xray, that doesn't make them visible to cameras
|
||||
continue
|
||||
if(C.can_use())
|
||||
last_found = C.c_tag
|
||||
last_seen = world.time
|
||||
break
|
||||
src.updateSelfDialog()
|
||||
|
||||
/obj/item/camera_bug/proc/same_z_level(var/obj/machinery/camera/C)
|
||||
var/turf/T_cam = get_turf(C)
|
||||
var/turf/T_bug = get_turf(loc)
|
||||
if(!T_bug || T_cam.z != T_bug.z)
|
||||
to_chat(usr, "<span class='warning'>You can't get a signal!</span>")
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
#undef BUGMODE_LIST
|
||||
#undef BUGMODE_MONITOR
|
||||
#undef BUGMODE_TRACK
|
||||
@@ -0,0 +1,176 @@
|
||||
/obj/item/chameleon
|
||||
name = "chameleon-projector"
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "shield0"
|
||||
flags_1 = CONDUCT_1
|
||||
item_flags = NOBLUDGEON
|
||||
slot_flags = ITEM_SLOT_BELT
|
||||
item_state = "electronic"
|
||||
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
|
||||
throwforce = 5
|
||||
throw_speed = 3
|
||||
throw_range = 5
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
var/can_use = 1
|
||||
var/obj/effect/dummy/chameleon/active_dummy = null
|
||||
var/saved_appearance = null
|
||||
|
||||
/obj/item/chameleon/New()
|
||||
..()
|
||||
var/obj/item/cigbutt/butt = /obj/item/cigbutt
|
||||
saved_appearance = initial(butt.appearance)
|
||||
|
||||
/obj/item/chameleon/dropped()
|
||||
..()
|
||||
disrupt()
|
||||
|
||||
/obj/item/chameleon/equipped()
|
||||
..()
|
||||
disrupt()
|
||||
|
||||
/obj/item/chameleon/attack_self(mob/user)
|
||||
if (isturf(user.loc) || istype(user.loc, /obj/structure) || active_dummy)
|
||||
toggle(user)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>You can't use [src] while inside something!</span>")
|
||||
|
||||
/obj/item/chameleon/afterattack(atom/target, mob/user , proximity)
|
||||
. = ..()
|
||||
if(!proximity)
|
||||
return
|
||||
if(!check_sprite(target))
|
||||
return
|
||||
if(active_dummy)//I now present you the blackli(f)st
|
||||
return
|
||||
if(isturf(target))
|
||||
return
|
||||
if(ismob(target))
|
||||
return
|
||||
if(istype(target, /obj/structure/falsewall))
|
||||
return
|
||||
if(iseffect(target))
|
||||
if(!(istype(target, /obj/effect/decal))) //be a footprint
|
||||
return
|
||||
playsound(get_turf(src), 'sound/weapons/flash.ogg', 100, 1, -6)
|
||||
to_chat(user, "<span class='notice'>Scanned [target].</span>")
|
||||
var/obj/temp = new/obj()
|
||||
temp.appearance = target.appearance
|
||||
temp.layer = initial(target.layer) // scanning things in your inventory
|
||||
temp.plane = initial(target.plane)
|
||||
saved_appearance = temp.appearance
|
||||
|
||||
/obj/item/chameleon/proc/check_sprite(atom/target)
|
||||
if(target.icon_state in icon_states(target.icon))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/item/chameleon/proc/toggle(mob/user)
|
||||
if(!can_use || !saved_appearance)
|
||||
return
|
||||
if(active_dummy)
|
||||
eject_all()
|
||||
playsound(get_turf(src), 'sound/effects/pop.ogg', 100, 1, -6)
|
||||
qdel(active_dummy)
|
||||
active_dummy = null
|
||||
to_chat(user, "<span class='notice'>You deactivate \the [src].</span>")
|
||||
new /obj/effect/temp_visual/emp/pulse(get_turf(src))
|
||||
else
|
||||
playsound(get_turf(src), 'sound/effects/pop.ogg', 100, 1, -6)
|
||||
var/obj/effect/dummy/chameleon/C = new/obj/effect/dummy/chameleon(user.drop_location())
|
||||
C.activate(user, saved_appearance, src)
|
||||
to_chat(user, "<span class='notice'>You activate \the [src].</span>")
|
||||
new /obj/effect/temp_visual/emp/pulse(get_turf(src))
|
||||
user.cancel_camera()
|
||||
|
||||
/obj/item/chameleon/proc/disrupt(delete_dummy = 1)
|
||||
if(active_dummy)
|
||||
for(var/mob/M in active_dummy)
|
||||
to_chat(M, "<span class='danger'>Your chameleon-projector deactivates.</span>")
|
||||
var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread
|
||||
spark_system.set_up(5, 0, src)
|
||||
spark_system.attach(src)
|
||||
spark_system.start()
|
||||
eject_all()
|
||||
if(delete_dummy)
|
||||
qdel(active_dummy)
|
||||
active_dummy = null
|
||||
can_use = 0
|
||||
spawn(50) can_use = 1
|
||||
|
||||
/obj/item/chameleon/proc/eject_all()
|
||||
for(var/atom/movable/A in active_dummy)
|
||||
A.forceMove(active_dummy.loc)
|
||||
if(ismob(A))
|
||||
var/mob/M = A
|
||||
M.reset_perspective(null)
|
||||
|
||||
/obj/effect/dummy/chameleon
|
||||
name = ""
|
||||
desc = ""
|
||||
density = FALSE
|
||||
var/can_move = 0
|
||||
var/obj/item/chameleon/master = null
|
||||
|
||||
/obj/effect/dummy/chameleon/proc/activate(mob/M, saved_appearance, obj/item/chameleon/C)
|
||||
appearance = saved_appearance
|
||||
if(istype(M.buckled, /obj/vehicle))
|
||||
var/obj/vehicle/V = M.buckled
|
||||
GET_COMPONENT_FROM(VRD, /datum/component/riding, V)
|
||||
if(VRD)
|
||||
VRD.force_dismount(M)
|
||||
else
|
||||
V.unbuckle_mob(M, force = TRUE)
|
||||
M.forceMove(src)
|
||||
master = C
|
||||
master.active_dummy = src
|
||||
|
||||
/obj/effect/dummy/chameleon/attackby()
|
||||
master.disrupt()
|
||||
|
||||
//ATTACK HAND IGNORING PARENT RETURN VALUE
|
||||
/obj/effect/dummy/chameleon/attack_hand()
|
||||
master.disrupt()
|
||||
|
||||
/obj/effect/dummy/chameleon/attack_animal()
|
||||
master.disrupt()
|
||||
|
||||
/obj/effect/dummy/chameleon/attack_slime()
|
||||
master.disrupt()
|
||||
|
||||
/obj/effect/dummy/chameleon/attack_alien()
|
||||
master.disrupt()
|
||||
|
||||
/obj/effect/dummy/chameleon/ex_act(S, T)
|
||||
contents_explosion(S, T)
|
||||
master.disrupt()
|
||||
|
||||
/obj/effect/dummy/chameleon/bullet_act()
|
||||
..()
|
||||
master.disrupt()
|
||||
|
||||
/obj/effect/dummy/chameleon/relaymove(mob/user, direction)
|
||||
if(isspaceturf(loc) || !direction)
|
||||
return //No magical space movement!
|
||||
|
||||
if(can_move < world.time)
|
||||
var/amount
|
||||
switch(user.bodytemperature)
|
||||
if(300 to INFINITY)
|
||||
amount = 10
|
||||
if(295 to 300)
|
||||
amount = 13
|
||||
if(280 to 295)
|
||||
amount = 16
|
||||
if(260 to 280)
|
||||
amount = 20
|
||||
else
|
||||
amount = 25
|
||||
|
||||
can_move = world.time + amount
|
||||
step(src, direction)
|
||||
return
|
||||
|
||||
/obj/effect/dummy/chameleon/Destroy()
|
||||
master.disrupt(0)
|
||||
return ..()
|
||||
@@ -0,0 +1,127 @@
|
||||
/obj/item/compressionkit
|
||||
name = "bluespace compression kit"
|
||||
desc = "An illegally modified BSRPED, capable of reducing the size of most items."
|
||||
icon = 'icons/obj/tools.dmi'
|
||||
icon_state = "compression_c"
|
||||
item_state = "RPED"
|
||||
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
var/charges = 5
|
||||
// var/damage_multiplier = 0.2 Not in use yet.
|
||||
var/mode = 0
|
||||
|
||||
/obj/item/compressionkit/examine(mob/user)
|
||||
..()
|
||||
to_chat(user, "<span class='notice'>It has [charges] charges left. Recharge with bluespace crystals.</span>")
|
||||
to_chat(user, "<span class='notice'>Use in-hand to swap toggle compress/expand mode (expand mode not yet implemented).</span>")
|
||||
|
||||
/obj/item/compressionkit/attack_self(mob/user)
|
||||
if(mode == 0)
|
||||
mode = 1
|
||||
icon_state = "compression_e"
|
||||
to_chat(user, "<span class='notice'>You switch the compressor to expand mode. This isn't implemented yet, so right now it wont do anything different!</span>")
|
||||
return
|
||||
if(mode == 1)
|
||||
mode = 0
|
||||
icon_state = "compression_c"
|
||||
to_chat(user, "<span class='notice'>You switch the compressor to compress mode. Usage will now reduce the size of objects.</span>")
|
||||
return
|
||||
else
|
||||
mode = 0
|
||||
icon_state = "compression_c"
|
||||
to_chat(user, "<span class='notice'>Some coder cocked up or an admin broke your compressor. It's been set back to compress mode..</span>")
|
||||
|
||||
/obj/item/compressionkit/proc/sparks()
|
||||
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
|
||||
s.set_up(5, 1, get_turf(src))
|
||||
s.start()
|
||||
|
||||
/obj/item/compressionkit/suicide_act(mob/living/carbon/M)
|
||||
M.visible_message("<span class='suicide'>[M] is sticking their head in [src] and turning it on! [M.p_theyre(TRUE)] going to compress their own skull!</span>")
|
||||
var/obj/item/bodypart/head = M.get_bodypart("head")
|
||||
if(!head)
|
||||
return
|
||||
var/turf/T = get_turf(M)
|
||||
var/list/organs = M.getorganszone("head") + M.getorganszone("eyes") + M.getorganszone("mouth")
|
||||
for(var/internal_organ in organs)
|
||||
var/obj/item/organ/I = internal_organ
|
||||
I.Remove(M)
|
||||
I.forceMove(T)
|
||||
head.drop_limb()
|
||||
qdel(head)
|
||||
new M.gib_type(T,1,M.get_static_viruses())
|
||||
M.add_splatter_floor(T)
|
||||
playsound(M, 'sound/weapons/flash.ogg', 50, 1)
|
||||
playsound(M, 'sound/effects/splat.ogg', 50, 1)
|
||||
|
||||
return OXYLOSS
|
||||
|
||||
/obj/item/compressionkit/afterattack(atom/target, mob/user, proximity)
|
||||
. = ..()
|
||||
if(!proximity || !target)
|
||||
return
|
||||
else
|
||||
if(charges == 0)
|
||||
playsound(get_turf(src), 'sound/machines/buzz-two.ogg', 50, 1)
|
||||
to_chat(user, "<span class='notice'>The bluespace compression kit is out of charges! Recharge it with bluespace crystals.</span>")
|
||||
return
|
||||
if(istype(target, /obj/item))
|
||||
var/obj/item/O = target
|
||||
if(O.w_class == 1)
|
||||
playsound(get_turf(src), 'sound/machines/buzz-two.ogg', 50, 1)
|
||||
to_chat(user, "<span class='notice'>[target] cannot be compressed smaller!.</span>")
|
||||
return
|
||||
if(O.GetComponent(/datum/component/storage))
|
||||
to_chat(user, "<span class='notice'>You feel like compressing an item that stores other items would be counterproductive.</span>")
|
||||
return
|
||||
if(O.w_class > 1)
|
||||
playsound(get_turf(src), 'sound/weapons/flash.ogg', 50, 1)
|
||||
user.visible_message("<span class='warning'>[user] is compressing [O] with their bluespace compression kit!</span>")
|
||||
if(do_mob(user, O, 40) && charges > 0 && O.w_class > 1)
|
||||
playsound(get_turf(src), 'sound/weapons/emitter2.ogg', 50, 1)
|
||||
sparks()
|
||||
flash_lighting_fx(3, 3, LIGHT_COLOR_CYAN)
|
||||
O.w_class -= 1
|
||||
// O.force_mult -= damage_multiplier
|
||||
charges -= 1
|
||||
to_chat(user, "<span class='notice'>You successfully compress [target]! The compressor now has [charges] charges.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>Anomalous error. Summon a coder.</span>")
|
||||
|
||||
if(istype(target, /mob/living))
|
||||
var/mob/living/victim = target
|
||||
if(istype(victim, /mob/living/carbon/human))
|
||||
if(user.zone_selected == "groin") // pp smol. There's probably a smarter way to do this but im retarded. If you have a simpler method let me know.
|
||||
var/list/organs = victim.getorganszone("groin")
|
||||
for(var/internal_organ in organs)
|
||||
if(istype(internal_organ, /obj/item/organ/genital/penis))
|
||||
var/obj/item/organ/genital/penis/O = internal_organ
|
||||
playsound(get_turf(src), 'sound/weapons/flash.ogg', 50, 1)
|
||||
victim.visible_message("<span class='warning'>[user] is preparing to shrink [victim]\'s [O.name] with their bluespace compression kit!</span>")
|
||||
if(do_mob(user, victim, 40) && charges > 0 && O.length > 0)
|
||||
victim.visible_message("<span class='warning'>[user] has shrunk [victim]\'s [O.name]!</span>")
|
||||
playsound(get_turf(src), 'sound/weapons/emitter2.ogg', 50, 1)
|
||||
sparks()
|
||||
flash_lighting_fx(3, 3, LIGHT_COLOR_CYAN)
|
||||
charges -= 1
|
||||
O.length -= 5
|
||||
if(O.length < 1)
|
||||
victim.visible_message("<span class='warning'>[user]\'s [O.name] vanishes!</span>")
|
||||
qdel(O) // no pp for you
|
||||
else
|
||||
O.update_size()
|
||||
O.update_appearance()
|
||||
|
||||
|
||||
|
||||
/obj/item/compressionkit/attackby(obj/item/I, mob/user, params)
|
||||
..()
|
||||
if(istype(I, /obj/item/stack/ore/bluespace_crystal))
|
||||
var/obj/item/stack/ore/bluespace_crystal/B = I
|
||||
charges += 2
|
||||
to_chat(user, "<span class='notice'>You insert [I] into [src]. It now has [charges] charges.</span>")
|
||||
if(B.amount > 1)
|
||||
B.amount -= 1
|
||||
else
|
||||
qdel(I)
|
||||
@@ -0,0 +1,547 @@
|
||||
// Dogborg Sleeper units
|
||||
|
||||
/obj/item/dogborg/sleeper
|
||||
name = "hound sleeper"
|
||||
desc = "nothing should see this."
|
||||
icon = 'icons/mob/dogborg.dmi'
|
||||
icon_state = "sleeper"
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
var/mob/living/carbon/patient = null
|
||||
var/mob/living/silicon/robot/hound = null
|
||||
var/inject_amount = 10
|
||||
var/min_health = -100
|
||||
var/cleaning = FALSE
|
||||
var/cleaning_cycles = 10
|
||||
var/patient_laststat = null
|
||||
var/list/injection_chems = list("antitoxin", "epinephrine", "salbutamol", "bicaridine", "kelotane")
|
||||
var/eject_port = "ingestion"
|
||||
var/escape_in_progress = FALSE
|
||||
var/message_cooldown
|
||||
var/breakout_time = 150
|
||||
var/tmp/last_hearcheck = 0
|
||||
var/tmp/list/hearing_mobs
|
||||
var/list/items_preserved = list()
|
||||
var/static/list/important_items = typecacheof(list(
|
||||
/obj/item/hand_tele,
|
||||
/obj/item/card/id,
|
||||
/obj/item/aicard,
|
||||
/obj/item/gun,
|
||||
/obj/item/pinpointer,
|
||||
/obj/item/clothing/shoes/magboots,
|
||||
/obj/item/clothing/head/helmet/space,
|
||||
/obj/item/clothing/suit/space,
|
||||
/obj/item/reagent_containers/hypospray/CMO,
|
||||
/obj/item/tank/jetpack/oxygen/captain,
|
||||
/obj/item/clothing/accessory/medal/gold/captain,
|
||||
/obj/item/clothing/suit/armor,
|
||||
/obj/item/documents,
|
||||
/obj/item/nuke_core,
|
||||
/obj/item/nuke_core_container,
|
||||
/obj/item/areaeditor/blueprints,
|
||||
/obj/item/documents/syndicate,
|
||||
/obj/item/disk/nuclear,
|
||||
/obj/item/bombcore,
|
||||
/obj/item/grenade,
|
||||
/obj/item/storage
|
||||
))
|
||||
|
||||
// Bags are prohibited from this due to the potential explotation of objects, same with brought
|
||||
|
||||
/obj/item/dogborg/sleeper/Initialize()
|
||||
. = ..()
|
||||
update_icon()
|
||||
item_flags |= NOBLUDGEON //No more attack messages
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/dogborg/sleeper/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
go_out() //just... sanity I guess, edge case shit
|
||||
return ..()
|
||||
|
||||
/obj/item/dogborg/sleeper/Exit(atom/movable/O)
|
||||
return 0
|
||||
|
||||
/obj/item/dogborg/sleeper/afterattack(mob/living/carbon/target, mob/living/silicon/user, proximity)
|
||||
hound = loc
|
||||
if(!proximity)
|
||||
return
|
||||
if(!iscarbon(target))
|
||||
return
|
||||
var/voracious = TRUE
|
||||
if(!target.client || !(target.client.prefs.cit_toggles & MEDIHOUND_SLEEPER) || !hound.client || !(hound.client.prefs.cit_toggles & MEDIHOUND_SLEEPER))
|
||||
voracious = FALSE
|
||||
if(target.buckled)
|
||||
to_chat(user, "<span class='warning'>The user is buckled and can not be put into your [src].</span>")
|
||||
return
|
||||
if(patient)
|
||||
to_chat(user, "<span class='warning'>Your [src] is already occupied.</span>")
|
||||
return
|
||||
user.visible_message("<span class='warning'>[hound.name] is carefully inserting [target.name] into their [src].</span>", "<span class='notice'>You start placing [target] into your [src]...</span>")
|
||||
if(!patient && iscarbon(target) && !target.buckled && do_after (user, 100, target = target))
|
||||
|
||||
if(!in_range(src, target)) //Proximity is probably old news by now, do a new check.
|
||||
return //If they moved away, you can't eat them.
|
||||
|
||||
if(patient) return //If you try to eat two people at once, you can only eat one.
|
||||
|
||||
else //If you don't have someone in you, proceed.
|
||||
if(!isjellyperson(target) && ("toxin" in injection_chems))
|
||||
injection_chems -= "toxin"
|
||||
injection_chems += "antitoxin"
|
||||
if(isjellyperson(target) && !("toxin" in injection_chems))
|
||||
injection_chems -= "antitoxin"
|
||||
injection_chems += "toxin"
|
||||
target.forceMove(src)
|
||||
target.reset_perspective(src)
|
||||
target.ExtinguishMob() //The tongue already puts out fire stacks but being put into the sleeper shouldn't allow you to keep burning.
|
||||
update_gut()
|
||||
user.visible_message("<span class='warning'>[voracious ? "[hound]'s [src.name] lights up and expands as [target] slips inside into their [src.name]." : "[hound]'s sleeper indicator lights up as [target] is scooped up into [hound.p_their()] [src]."]</span>", \
|
||||
"<span class='notice'>Your [voracious ? "[src.name] lights up as [target] slips into" : "sleeper indicator light shines brightly as [target] is scooped inside"] your [src]. Life support functions engaged.</span>")
|
||||
message_admins("[key_name(hound)] has sleeper'd [key_name(patient)] as a dogborg. [ADMIN_JMP(src)]")
|
||||
playsound(hound, 'sound/effects/bin_close.ogg', 100, 1)
|
||||
|
||||
/obj/item/dogborg/sleeper/container_resist(mob/living/user)
|
||||
hound = loc
|
||||
user.changeNext_move(CLICK_CD_BREAKOUT)
|
||||
user.last_special = world.time + CLICK_CD_BREAKOUT
|
||||
if(user.a_intent == INTENT_HELP)
|
||||
return
|
||||
var/voracious = TRUE
|
||||
if(!user.client || !(user.client.prefs.cit_toggles & MEDIHOUND_SLEEPER) || !hound.client || !(hound.client.prefs.cit_toggles & MEDIHOUND_SLEEPER))
|
||||
voracious = FALSE
|
||||
user.visible_message("<span class='notice'>You see [voracious ? "[user] struggling against the expanded material of [hound]'s gut!" : "and hear [user] pounding against something inside of [hound]'s [src.name]!"]</span>", \
|
||||
"<span class='notice'>[voracious ? "You start struggling inside of [src]'s tight, flexible confines," : "You start pounding against the metallic walls of [src],"] trying to trigger the release... (this will take about [DisplayTimeText(breakout_time)].)</span>", \
|
||||
"<span class='italics'>You hear a [voracious ? "couple of thumps" : "loud banging noise"] coming from within [hound].</span>")
|
||||
if(do_after(user, breakout_time, target = src))
|
||||
if(!user || user.stat != CONSCIOUS || user.loc != src )
|
||||
return
|
||||
user.visible_message("<span class='warning'>[user] successfully broke out of [hound.name]!</span>", \
|
||||
"<span class='notice'>You successfully break out of [hound.name]!</span>")
|
||||
go_out()
|
||||
|
||||
/obj/item/dogborg/sleeper/proc/go_out(var/target)
|
||||
hound = loc
|
||||
hound.setClickCooldown(50)
|
||||
var/voracious = TRUE
|
||||
if(!hound.client || !(hound.client.prefs.cit_toggles & MEDIHOUND_SLEEPER))
|
||||
voracious = FALSE
|
||||
else
|
||||
for(var/mob/M in contents)
|
||||
if(!M.client || !(M.client.prefs.cit_toggles & MEDIHOUND_SLEEPER))
|
||||
voracious = FALSE
|
||||
if(length(contents) > 0)
|
||||
hound.visible_message("<span class='warning'>[voracious ? "[hound] empties out [hound.p_their()] contents via [hound.p_their()] release port." : "[hound]'s underside slides open with an audible clunk before [hound.p_their()] [src] flips over, carelessly dumping its contents onto the ground below [hound.p_them()] before closing right back up again."]</span>", \
|
||||
"<span class='notice'>[voracious ? "You empty your contents via your release port." : "You open your sleeper hatch, quickly releasing all of the contents within before closing it again."]</span>")
|
||||
if(target)
|
||||
if(iscarbon(target))
|
||||
var/mob/living/carbon/person = target
|
||||
person.forceMove(get_turf(src))
|
||||
person.reset_perspective()
|
||||
else
|
||||
var/obj/T = target
|
||||
T.loc = hound.loc
|
||||
else
|
||||
for(var/C in contents)
|
||||
if(iscarbon(C))
|
||||
var/mob/living/carbon/person = C
|
||||
person.forceMove(get_turf(src))
|
||||
person.reset_perspective()
|
||||
else
|
||||
var/obj/T = C
|
||||
T.loc = hound.loc
|
||||
items_preserved.Cut()
|
||||
update_gut()
|
||||
cleaning = FALSE
|
||||
playsound(loc, voracious ? 'sound/effects/splat.ogg' : 'sound/effects/bin_close.ogg', 50, 1)
|
||||
|
||||
else //You clicked eject with nothing in you, let's just reset stuff to be sure.
|
||||
items_preserved.Cut()
|
||||
cleaning = FALSE
|
||||
update_gut()
|
||||
|
||||
|
||||
/obj/item/dogborg/sleeper/attack_self(mob/user)
|
||||
if(..())
|
||||
return
|
||||
ui_interact(user)
|
||||
|
||||
/obj/item/dogborg/sleeper/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
|
||||
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.notcontained_state)
|
||||
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
ui = new(user, src, ui_key, "dogborg_sleeper", name, 375, 550, master_ui, state)
|
||||
ui.open()
|
||||
|
||||
/obj/item/dogborg/sleeper/ui_data()
|
||||
var/list/data = list()
|
||||
data["occupied"] = patient ? 1 : 0
|
||||
|
||||
if(cleaning && length(contents - items_preserved))
|
||||
data["items"] = "Self-cleaning mode active: [length(contents - items_preserved)] object(s) remaining."
|
||||
data["cleaning"] = cleaning
|
||||
if(injection_chems != null)
|
||||
data["chem"] = list()
|
||||
for(var/chem in injection_chems)
|
||||
var/datum/reagent/R = GLOB.chemical_reagents_list[chem]
|
||||
data["chem"] += list(list("name" = R.name, "id" = R.id))
|
||||
|
||||
data["occupant"] = list()
|
||||
var/mob/living/mob_occupant = patient
|
||||
if(mob_occupant)
|
||||
data["occupant"]["name"] = mob_occupant.name
|
||||
switch(mob_occupant.stat)
|
||||
if(CONSCIOUS)
|
||||
data["occupant"]["stat"] = "Conscious"
|
||||
data["occupant"]["statstate"] = "good"
|
||||
if(SOFT_CRIT)
|
||||
data["occupant"]["stat"] = "Conscious"
|
||||
data["occupant"]["statstate"] = "average"
|
||||
if(UNCONSCIOUS)
|
||||
data["occupant"]["stat"] = "Unconscious"
|
||||
data["occupant"]["statstate"] = "average"
|
||||
if(DEAD)
|
||||
data["occupant"]["stat"] = "Dead"
|
||||
data["occupant"]["statstate"] = "bad"
|
||||
data["occupant"]["health"] = mob_occupant.health
|
||||
data["occupant"]["maxHealth"] = mob_occupant.maxHealth
|
||||
data["occupant"]["minHealth"] = HEALTH_THRESHOLD_DEAD
|
||||
data["occupant"]["bruteLoss"] = mob_occupant.getBruteLoss()
|
||||
data["occupant"]["oxyLoss"] = mob_occupant.getOxyLoss()
|
||||
data["occupant"]["toxLoss"] = mob_occupant.getToxLoss()
|
||||
data["occupant"]["fireLoss"] = mob_occupant.getFireLoss()
|
||||
data["occupant"]["cloneLoss"] = mob_occupant.getCloneLoss()
|
||||
data["occupant"]["brainLoss"] = mob_occupant.getBrainLoss()
|
||||
data["occupant"]["reagents"] = list()
|
||||
if(mob_occupant.reagents.reagent_list.len)
|
||||
for(var/datum/reagent/R in mob_occupant.reagents.reagent_list)
|
||||
data["occupant"]["reagents"] += list(list("name" = R.name, "volume" = R.volume))
|
||||
return data
|
||||
|
||||
/obj/item/dogborg/sleeper/ui_act(action, params)
|
||||
if(..())
|
||||
return
|
||||
|
||||
switch(action)
|
||||
if("eject")
|
||||
go_out()
|
||||
. = TRUE
|
||||
if("inject")
|
||||
var/chem = params["chem"]
|
||||
if(!patient)
|
||||
return
|
||||
inject_chem(chem)
|
||||
. = TRUE
|
||||
if("cleaning")
|
||||
if(!contents)
|
||||
to_chat(src, "Your [src] is already cleaned.")
|
||||
return
|
||||
if(patient)
|
||||
to_chat(patient, "<span class='danger'>[hound.name]'s [src] fills with caustic enzymes around you!</span>")
|
||||
to_chat(src, "<span class='danger'>Cleaning process enabled.</span>")
|
||||
clean_cycle()
|
||||
. = TRUE
|
||||
|
||||
/obj/item/dogborg/sleeper/proc/update_gut()
|
||||
//Well, we HAD one, what happened to them?
|
||||
var/prociconupdate = FALSE
|
||||
var/currentenvy = hound.sleeper_nv
|
||||
hound.sleeper_nv = FALSE
|
||||
if(patient in contents)
|
||||
if(patient_laststat != patient.stat)
|
||||
if(patient.stat & DEAD)
|
||||
hound.sleeper_r = 1
|
||||
hound.sleeper_g = 0
|
||||
patient_laststat = patient.stat
|
||||
else
|
||||
hound.sleeper_r = 0
|
||||
hound.sleeper_g = 1
|
||||
patient_laststat = patient.stat
|
||||
prociconupdate = TRUE
|
||||
|
||||
if(!patient.client || !(patient.client.prefs.cit_toggles & MEDIHOUND_SLEEPER) || !hound.client || !(hound.client.prefs.cit_toggles & MEDIHOUND_SLEEPER))
|
||||
hound.sleeper_nv = TRUE
|
||||
else
|
||||
hound.sleeper_nv = FALSE
|
||||
if(hound.sleeper_nv != currentenvy)
|
||||
prociconupdate = TRUE
|
||||
|
||||
//Update icon
|
||||
if(prociconupdate)
|
||||
hound.update_icons()
|
||||
//Return original patient
|
||||
return(patient)
|
||||
//Check for a new patient
|
||||
else
|
||||
for(var/mob/living/carbon/human/C in contents)
|
||||
patient = C
|
||||
if(patient.stat & DEAD)
|
||||
hound.sleeper_r = 1
|
||||
hound.sleeper_g = 0
|
||||
patient_laststat = patient.stat
|
||||
else
|
||||
hound.sleeper_r = 0
|
||||
hound.sleeper_g = 1
|
||||
patient_laststat = patient.stat
|
||||
|
||||
if(!patient.client || !(patient.client.prefs.cit_toggles & MEDIHOUND_SLEEPER) || !hound.client || !(hound.client.prefs.cit_toggles & MEDIHOUND_SLEEPER))
|
||||
hound.sleeper_nv = TRUE
|
||||
else
|
||||
hound.sleeper_nv = FALSE
|
||||
|
||||
//Update icon and return new patient
|
||||
hound.update_icons()
|
||||
return(C)
|
||||
|
||||
//Cleaning looks better with red on, even with nobody in it
|
||||
if(cleaning && !patient)
|
||||
hound.sleeper_r = 1
|
||||
hound.sleeper_g = 0
|
||||
//Couldn't find anyone, and not cleaning
|
||||
else if(!cleaning && !patient)
|
||||
hound.sleeper_r = 0
|
||||
hound.sleeper_g = 0
|
||||
|
||||
patient_laststat = null
|
||||
patient = null
|
||||
hound.update_icons()
|
||||
|
||||
//Gurgleborg process
|
||||
/obj/item/dogborg/sleeper/proc/clean_cycle()
|
||||
//Sanity
|
||||
for(var/I in items_preserved)
|
||||
if(!(I in contents))
|
||||
items_preserved -= I
|
||||
var/list/touchable_items = contents - items_preserved
|
||||
var/sound/prey_digest = sound(get_sfx("digest_prey"))
|
||||
var/sound/prey_death = sound(get_sfx("death_prey"))
|
||||
var/sound/pred_digest = sound(get_sfx("digest_pred"))
|
||||
var/sound/pred_death = sound(get_sfx("death_pred"))
|
||||
if(cleaning_cycles)
|
||||
cleaning_cycles--
|
||||
cleaning = TRUE
|
||||
for(var/mob/living/carbon/human/T in (touchable_items))
|
||||
if((T.status_flags & GODMODE) || !T.digestable)
|
||||
items_preserved += T
|
||||
else
|
||||
T.adjustBruteLoss(2)
|
||||
T.adjustFireLoss(3)
|
||||
update_gut()
|
||||
if(contents)
|
||||
var/atom/target = pick(touchable_items)
|
||||
if(iscarbon(target)) //Handle the target being a mob
|
||||
var/mob/living/carbon/T = target
|
||||
if(T.stat == DEAD && T.digestable) //Mob is now dead
|
||||
message_admins("[key_name(hound)] has digested [key_name(T)] as a dogborg. ([hound ? "<a href='?_src_=holder;adminplayerobservecoodjump=1;X=[hound.x];Y=[hound.y];Z=[hound.z]'>JMP</a>" : "null"])")
|
||||
to_chat(hound,"<span class='notice'>You feel your belly slowly churn around [T], breaking them down into a soft slurry to be used as power for your systems.</span>")
|
||||
to_chat(T,"<span class='notice'>You feel [hound]'s belly slowly churn around your form, breaking you down into a soft slurry to be used as power for [hound]'s systems.</span>")
|
||||
hound.cell.give(30000) //Fueeeeellll
|
||||
if((world.time - NORMIE_HEARCHECK) > last_hearcheck)
|
||||
var/turf/source = get_turf(hound)
|
||||
LAZYCLEARLIST(hearing_mobs)
|
||||
for(var/mob/H in get_hearers_in_view(3, source))
|
||||
if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES))
|
||||
continue
|
||||
LAZYADD(hearing_mobs, H)
|
||||
last_hearcheck = world.time
|
||||
for(var/mob/H in hearing_mobs)
|
||||
if(!istype(H.loc, /obj/item/dogborg/sleeper))
|
||||
H.playsound_local(source, null, 45, falloff = 0, S = pred_death)
|
||||
else if(H in contents)
|
||||
H.playsound_local(source, null, 65, falloff = 0, S = prey_death)
|
||||
for(var/belly in T.vore_organs)
|
||||
var/obj/belly/B = belly
|
||||
for(var/atom/movable/thing in B)
|
||||
thing.forceMove(src)
|
||||
if(ismob(thing))
|
||||
to_chat(thing, "As [T] melts away around you, you find yourself in [hound]'s [name]")
|
||||
for(var/obj/item/W in T)
|
||||
if(!T.dropItemToGround(W))
|
||||
qdel(W)
|
||||
qdel(T)
|
||||
update_gut()
|
||||
//Handle the target being anything but a mob
|
||||
else if(isobj(target))
|
||||
var/obj/T = target
|
||||
if(T.type in important_items) //If the object is in the items_preserved global list
|
||||
items_preserved += T
|
||||
//If the object is not one to preserve
|
||||
else
|
||||
qdel(T)
|
||||
update_gut()
|
||||
hound.cell.give(10)
|
||||
else
|
||||
cleaning_cycles = initial(cleaning_cycles)
|
||||
cleaning = FALSE
|
||||
to_chat(hound, "<span class='notice'>Your [src] chimes it ends its self-cleaning cycle.</span>")//Belly is entirely empty
|
||||
update_gut()
|
||||
|
||||
if(!length(contents))
|
||||
to_chat(hound, "<span class='notice'>Your [src] is now clean. Ending self-cleaning cycle.</span>")
|
||||
cleaning = FALSE
|
||||
update_gut()
|
||||
|
||||
//sound effects
|
||||
if(prob(50))
|
||||
if((world.time - NORMIE_HEARCHECK) > last_hearcheck)
|
||||
var/turf/source = get_turf(hound)
|
||||
LAZYCLEARLIST(hearing_mobs)
|
||||
for(var/mob/H in get_hearers_in_view(3, source))
|
||||
if(!H.client || !(H.client.prefs.cit_toggles & DIGESTION_NOISES))
|
||||
continue
|
||||
LAZYADD(hearing_mobs, H)
|
||||
last_hearcheck = world.time
|
||||
for(var/mob/H in hearing_mobs)
|
||||
if(!istype(H.loc, /obj/item/dogborg/sleeper))
|
||||
H.playsound_local(source, null, 45, falloff = 0, S = pred_digest)
|
||||
else if(H in contents)
|
||||
H.playsound_local(source, null, 65, falloff = 0, S = prey_digest)
|
||||
|
||||
if(cleaning)
|
||||
addtimer(CALLBACK(src, .proc/clean_cycle), 50)
|
||||
|
||||
/obj/item/dogborg/sleeper/proc/CheckAccepted(obj/item/I)
|
||||
return is_type_in_typecache(I, important_items)
|
||||
|
||||
/obj/item/dogborg/sleeper/proc/inject_chem(chem)
|
||||
if(hound.cell.charge <= 800) //This is so borgs don't kill themselves with it. Remember, 750 charge used every injection.
|
||||
to_chat(hound, "<span class='notice'>You don't have enough power to synthesize fluids.</span>")
|
||||
return
|
||||
if(patient.reagents.get_reagent_amount(chem) + 10 >= 20) //Preventing people from accidentally killing themselves by trying to inject too many chemicals!
|
||||
to_chat(hound, "<span class='notice'>Your stomach is currently too full of fluids to secrete more fluids of this kind.</span>")
|
||||
return
|
||||
patient.reagents.add_reagent(chem, 10)
|
||||
hound.cell.use(750) //-750 charge per injection
|
||||
var/units = round(patient.reagents.get_reagent_amount(chem))
|
||||
to_chat(hound, "<span class='notice'>Injecting [units] unit\s of [chem] into occupant.</span>") //If they were immersed, the reagents wouldn't leave with them.
|
||||
|
||||
/obj/item/dogborg/sleeper/medihound //Medihound sleeper
|
||||
name = "Mobile Sleeper"
|
||||
desc = "Equipment for medical hound. A mounted sleeper that stabilizes patients and can inject reagents in the borg's reserves."
|
||||
icon = 'icons/mob/dogborg.dmi'
|
||||
icon_state = "sleeper"
|
||||
breakout_time = 30 //Medical sleepers should be designed to be as easy as possible to get out of.
|
||||
|
||||
/obj/item/dogborg/sleeper/K9 //The K9 portabrig
|
||||
name = "Mobile Brig"
|
||||
desc = "Equipment for a K9 unit. A mounted portable-brig that holds criminals."
|
||||
icon = 'icons/mob/dogborg.dmi'
|
||||
icon_state = "sleeperb"
|
||||
inject_amount = 0
|
||||
min_health = -100
|
||||
injection_chems = null //So they don't have all the same chems as the medihound!
|
||||
breakout_time = 300
|
||||
|
||||
/obj/item/storage/attackby(obj/item/dogborg/sleeper/K9, mob/user, proximity)
|
||||
if(istype(K9))
|
||||
K9.afterattack(src, user ,1)
|
||||
else
|
||||
. = ..()
|
||||
|
||||
/obj/item/dogborg/sleeper/K9/afterattack(var/atom/movable/target, mob/living/silicon/user, proximity)
|
||||
hound = loc
|
||||
|
||||
if(!istype(target))
|
||||
return
|
||||
if(!proximity)
|
||||
return
|
||||
if(target.anchored)
|
||||
return
|
||||
if(isobj(target))
|
||||
to_chat(user, "You are above putting such trash inside of yourself.")
|
||||
return
|
||||
if(iscarbon(target))
|
||||
var/mob/living/carbon/brigman = target
|
||||
if (!brigman.devourable)
|
||||
to_chat(user, "The target registers an error code. Unable to insert into [src].")
|
||||
return
|
||||
if(patient)
|
||||
to_chat(user,"<span class='warning'>Your [src] is already occupied.</span>")
|
||||
return
|
||||
if(brigman.buckled)
|
||||
to_chat(user,"<span class='warning'>[brigman] is buckled and can not be put into your [src].</span>")
|
||||
return
|
||||
user.visible_message("<span class='warning'>[hound.name] is ingesting [brigman] into their [src].</span>", "<span class='notice'>You start ingesting [brigman] into your [src.name]...</span>")
|
||||
if(do_after(user, 30, target = brigman) && !patient && !brigman.buckled)
|
||||
if(!in_range(src, brigman)) //Proximity is probably old news by now, do a new check.
|
||||
return //If they moved away, you can't eat them.
|
||||
brigman.forceMove(src)
|
||||
brigman.reset_perspective(src)
|
||||
update_gut()
|
||||
user.visible_message("<span class='warning'>[hound.name]'s mobile brig clunks in series as [brigman] slips inside.</span>", "<span class='notice'>Your mobile brig groans lightly as [brigman] slips inside.</span>")
|
||||
playsound(hound, 'sound/effects/bin_close.ogg', 80, 1) // Really don't need ERP sound effects for robots
|
||||
return
|
||||
return
|
||||
|
||||
/obj/item/dogborg/sleeper/compactor //Janihound gut.
|
||||
name = "garbage processor"
|
||||
desc = "A mounted garbage compactor unit with fuel processor."
|
||||
icon = 'icons/mob/dogborg.dmi'
|
||||
icon_state = "compactor"
|
||||
inject_amount = 0
|
||||
min_health = -100
|
||||
injection_chems = null //So they don't have all the same chems as the medihound!
|
||||
var/max_item_count = 30
|
||||
|
||||
/obj/item/storage/attackby(obj/item/dogborg/sleeper/compactor, mob/user, proximity) //GIT CIRCUMVENTED YO!
|
||||
if(istype(compactor))
|
||||
compactor.afterattack(src, user ,1)
|
||||
else
|
||||
. = ..()
|
||||
|
||||
/obj/item/dogborg/sleeper/compactor/afterattack(var/atom/movable/target, mob/living/silicon/user, proximity)//GARBO NOMS
|
||||
hound = loc
|
||||
var/obj/item/target_obj = target
|
||||
if(!istype(target))
|
||||
return
|
||||
if(!proximity)
|
||||
return
|
||||
if(target.anchored)
|
||||
return
|
||||
if(length(contents) > (max_item_count - 1))
|
||||
to_chat(user,"<span class='warning'>Your [src] is full. Eject or process contents to continue.</span>")
|
||||
return
|
||||
if(isobj(target))
|
||||
if(CheckAccepted(target))
|
||||
to_chat(user,"<span class='warning'>\The [target] registers an error code to your [src]</span>")
|
||||
return
|
||||
if(target_obj.w_class > WEIGHT_CLASS_NORMAL)
|
||||
to_chat(user,"<span class='warning'>\The [target] is too large to fit into your [src]</span>")
|
||||
return
|
||||
user.visible_message("<span class='warning'>[hound.name] is ingesting [target.name] into their [src.name].</span>", "<span class='notice'>You start ingesting [target] into your [src.name]...</span>")
|
||||
if(do_after(user, 15, target = target) && length(contents) < max_item_count)
|
||||
if(!in_range(src, target)) //Proximity is probably old news by now, do a new check.
|
||||
return //If they moved away, you can't eat them. This still applies to items, don't magically eat things I picked up already.
|
||||
target.forceMove(src)
|
||||
user.visible_message("<span class='warning'>[hound.name]'s garbage processor groans lightly as [target.name] slips inside.</span>", "<span class='notice'>Your garbage compactor groans lightly as [target] slips inside.</span>")
|
||||
playsound(hound, 'sound/machines/disposalflush.ogg', 50, 1)
|
||||
if(length(contents) > 11) //grow that tum after a certain junk amount
|
||||
hound.sleeper_r = 1
|
||||
hound.update_icons()
|
||||
else
|
||||
hound.sleeper_r = 0
|
||||
hound.update_icons()
|
||||
return
|
||||
|
||||
else if(iscarbon(target))
|
||||
var/mob/living/carbon/trashman = target
|
||||
if (!trashman.devourable)
|
||||
to_chat(user, "<span class='warning'>[target] registers an error code to your [src]</span>")
|
||||
return
|
||||
if(patient)
|
||||
to_chat(user,"<span class='warning'>Your [src] is already occupied.</span>")
|
||||
return
|
||||
if(trashman.buckled)
|
||||
to_chat(user,"<span class='warning'>[trashman] is buckled and can not be put into your [src].</span>")
|
||||
return
|
||||
user.visible_message("<span class='warning'>[hound.name] is ingesting [trashman] into their [src].</span>", "<span class='notice'>You start ingesting [trashman] into your [src.name]...</span>")
|
||||
if(do_after(user, 30, target = trashman) && !patient && !trashman.buckled && length(contents) < max_item_count)
|
||||
if(!in_range(src, trashman)) //Proximity is probably old news by now, do a new check.
|
||||
return //If they moved away, you can't eat them.
|
||||
trashman.forceMove(src)
|
||||
trashman.reset_perspective(src)
|
||||
update_gut()
|
||||
user.visible_message("<span class='warning'>[hound.name]'s garbage processor groans lightly as [trashman] slips inside.</span>", "<span class='notice'>Your garbage compactor groans lightly as [trashman] slips inside.</span>")
|
||||
playsound(hound, 'sound/effects/bin_close.ogg', 80, 1)
|
||||
return
|
||||
return
|
||||
@@ -0,0 +1,42 @@
|
||||
/obj/item/doorCharge
|
||||
name = "airlock charge"
|
||||
desc = null //Different examine for traitors
|
||||
icon = 'icons/obj/device.dmi'
|
||||
item_state = "electronic"
|
||||
icon_state = "doorCharge"
|
||||
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
throw_range = 4
|
||||
throw_speed = 1
|
||||
item_flags = NOBLUDGEON
|
||||
force = 3
|
||||
attack_verb = list("blown up", "exploded", "detonated")
|
||||
materials = list(MAT_METAL=50, MAT_GLASS=30)
|
||||
|
||||
/obj/item/doorCharge/ex_act(severity, target)
|
||||
switch(severity)
|
||||
if(1)
|
||||
visible_message("<span class='warning'>[src] detonates!</span>")
|
||||
explosion(src.loc,0,2,1,flame_range = 4)
|
||||
qdel(src)
|
||||
if(2)
|
||||
if(prob(50))
|
||||
ex_act(EXPLODE_DEVASTATE)
|
||||
if(3)
|
||||
if(prob(25))
|
||||
ex_act(EXPLODE_DEVASTATE)
|
||||
|
||||
/obj/item/doorCharge/Destroy()
|
||||
if(istype(loc, /obj/machinery/door/airlock))
|
||||
var/obj/machinery/door/airlock/A = loc
|
||||
if(A.charge == src)
|
||||
A.charge = null
|
||||
return ..()
|
||||
|
||||
/obj/item/doorCharge/examine(mob/user)
|
||||
..()
|
||||
if(user.mind && user.mind.has_antag_datum(/datum/antagonist/traitor)) //No nuke ops because the device is excluded from nuclear
|
||||
to_chat(user, "A small explosive device that can be used to sabotage airlocks to cause an explosion upon opening. To apply, remove the airlock's maintenance panel and place it within.")
|
||||
else
|
||||
to_chat(user, "A small, suspicious object that feels lukewarm when held.")
|
||||
@@ -0,0 +1,65 @@
|
||||
//Used by engineering cyborgs in place of generic circuits.
|
||||
/obj/item/electroadaptive_pseudocircuit
|
||||
name = "electroadaptive pseudocircuit"
|
||||
desc = "An all-in-one circuit imprinter, designer, synthesizer, outfitter, creator, and chef. It can be used in place of any generic circuit board during construction."
|
||||
icon = 'icons/obj/module.dmi'
|
||||
icon_state = "boris"
|
||||
w_class = WEIGHT_CLASS_TINY
|
||||
materials = list(MAT_METAL = 50, MAT_GLASS = 300)
|
||||
var/recharging = FALSE
|
||||
var/circuits = 5 //How many circuits the pseudocircuit has left
|
||||
var/static/recycleable_circuits = typecacheof(list(/obj/item/electronics/firelock, /obj/item/electronics/airalarm, /obj/item/electronics/firealarm, \
|
||||
/obj/item/electronics/apc))//A typecache of circuits consumable for material
|
||||
|
||||
/obj/item/electroadaptive_pseudocircuit/Initialize()
|
||||
. = ..()
|
||||
maptext = "[circuits]"
|
||||
|
||||
/obj/item/electroadaptive_pseudocircuit/examine(mob/user)
|
||||
..()
|
||||
if(iscyborg(user))
|
||||
to_chat(user, "<span class='notice'>It has material for <b>[circuits]</b> circuit[circuits == 1 ? "" : "s"]. Use the pseudocircuit on existing circuits to gain material.</span>")
|
||||
to_chat(user, "<span class='notice'>Serves as a substitute for <b>fire/air alarm</b>, <b>firelock</b>, and <b>APC</b> electronics.</span>")
|
||||
to_chat(user, "<span class='notice'>It can also be used on an APC with no power cell to <b>fabricate a low-capacity cell</b> at a high power cost.</span>")
|
||||
|
||||
/obj/item/electroadaptive_pseudocircuit/proc/adapt_circuit(mob/living/silicon/robot/R, circuit_cost = 0)
|
||||
if(QDELETED(R) || !istype(R))
|
||||
return
|
||||
if(!R.cell)
|
||||
to_chat(R, "<span class='warning'>You need a power cell installed for that.</span>")
|
||||
return
|
||||
if(!R.cell.use(circuit_cost))
|
||||
to_chat(R, "<span class='warning'>You don't have the energy for that (you need [DisplayEnergy(circuit_cost)].)</span>")
|
||||
return
|
||||
if(recharging)
|
||||
to_chat(R, "<span class='warning'>[src] needs some time to recharge first.</span>")
|
||||
return
|
||||
if(!circuits)
|
||||
to_chat(R, "<span class='warning'>You need more material. Use [src] on existing simple circuits to break them down.</span>")
|
||||
return
|
||||
playsound(R, 'sound/items/rped.ogg', 50, TRUE)
|
||||
recharging = TRUE
|
||||
circuits--
|
||||
maptext = "[circuits]"
|
||||
icon_state = "[initial(icon_state)]_recharging"
|
||||
var/recharge_time = min(600, circuit_cost * 5) //40W of cost for one fabrication = 20 seconds of recharge time; this is to prevent spamming
|
||||
addtimer(CALLBACK(src, .proc/recharge), recharge_time)
|
||||
return TRUE //The actual circuit magic itself is done on a per-object basis
|
||||
|
||||
/obj/item/electroadaptive_pseudocircuit/afterattack(atom/target, mob/living/user, proximity)
|
||||
. = ..()
|
||||
if(!proximity)
|
||||
return
|
||||
if(!is_type_in_typecache(target, recycleable_circuits))
|
||||
return
|
||||
circuits++
|
||||
maptext = "[circuits]"
|
||||
user.visible_message("<span class='notice'>User breaks down [target] with [src].</span>", \
|
||||
"<span class='notice'>You recycle [target] into [src]. It now has material for <b>[circuits]</b> circuits.</span>")
|
||||
playsound(user, 'sound/items/deconstruct.ogg', 50, TRUE)
|
||||
qdel(target)
|
||||
|
||||
/obj/item/electroadaptive_pseudocircuit/proc/recharge()
|
||||
playsound(src, 'sound/machines/chime.ogg', 25, TRUE)
|
||||
recharging = FALSE
|
||||
icon_state = initial(icon_state)
|
||||
@@ -0,0 +1,545 @@
|
||||
/obj/item/flashlight
|
||||
name = "flashlight"
|
||||
desc = "A hand-held emergency light."
|
||||
icon = 'icons/obj/lighting.dmi'
|
||||
icon_state = "flashlight"
|
||||
item_state = "flashlight"
|
||||
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
flags_1 = CONDUCT_1
|
||||
slot_flags = ITEM_SLOT_BELT
|
||||
materials = list(MAT_METAL=50, MAT_GLASS=20)
|
||||
actions_types = list(/datum/action/item_action/toggle_light)
|
||||
var/on = FALSE
|
||||
var/brightness_on = 4 //range of light when on
|
||||
var/flashlight_power = 0.8 //strength of the light when on
|
||||
light_color = "#FFCC66"
|
||||
|
||||
/obj/item/flashlight/Initialize()
|
||||
. = ..()
|
||||
if(icon_state == "[initial(icon_state)]-on")
|
||||
on = TRUE
|
||||
update_brightness()
|
||||
|
||||
/obj/item/flashlight/proc/update_brightness(mob/user = null)
|
||||
if(on)
|
||||
icon_state = "[initial(icon_state)]-on"
|
||||
if(flashlight_power)
|
||||
set_light(l_range = brightness_on, l_power = flashlight_power)
|
||||
else
|
||||
set_light(brightness_on)
|
||||
else
|
||||
icon_state = initial(icon_state)
|
||||
set_light(0)
|
||||
|
||||
/obj/item/flashlight/attack_self(mob/user)
|
||||
on = !on
|
||||
update_brightness(user)
|
||||
playsound(user, on ? 'sound/weapons/magin.ogg' : 'sound/weapons/magout.ogg', 40, 1)
|
||||
for(var/X in actions)
|
||||
var/datum/action/A = X
|
||||
A.UpdateButtonIcon()
|
||||
return 1
|
||||
|
||||
/obj/item/flashlight/suicide_act(mob/living/carbon/human/user)
|
||||
if (user.eye_blind)
|
||||
user.visible_message("<span class='suicide'>[user] is putting [src] close to [user.p_their()] eyes and turning it on ... but [user.p_theyre()] blind!</span>")
|
||||
return SHAME
|
||||
user.visible_message("<span class='suicide'>[user] is putting [src] close to [user.p_their()] eyes and turning it on! It looks like [user.p_theyre()] trying to commit suicide!</span>")
|
||||
return (FIRELOSS)
|
||||
|
||||
/obj/item/flashlight/attack(mob/living/carbon/M, mob/living/carbon/human/user)
|
||||
add_fingerprint(user)
|
||||
if(istype(M) && on && user.zone_selected in list(BODY_ZONE_PRECISE_EYES, BODY_ZONE_PRECISE_MOUTH))
|
||||
|
||||
if((HAS_TRAIT(user, TRAIT_CLUMSY) || HAS_TRAIT(user, TRAIT_DUMB)) && prob(50)) //too dumb to use flashlight properly
|
||||
return ..() //just hit them in the head
|
||||
|
||||
if(!user.IsAdvancedToolUser())
|
||||
to_chat(user, "<span class='warning'>You don't have the dexterity to do this!</span>")
|
||||
return
|
||||
|
||||
if(!M.get_bodypart(BODY_ZONE_HEAD))
|
||||
to_chat(user, "<span class='warning'>[M] doesn't have a head!</span>")
|
||||
return
|
||||
|
||||
if(flashlight_power < 0.3)
|
||||
to_chat(user, "<span class='warning'>\The [src] isn't bright enough to see anything!</span> ")
|
||||
return
|
||||
|
||||
switch(user.zone_selected)
|
||||
if(BODY_ZONE_PRECISE_EYES)
|
||||
if((M.head && M.head.flags_cover & HEADCOVERSEYES) || (M.wear_mask && M.wear_mask.flags_cover & MASKCOVERSEYES) || (M.glasses && M.glasses.flags_cover & GLASSESCOVERSEYES))
|
||||
to_chat(user, "<span class='notice'>You're going to need to remove that [(M.head && M.head.flags_cover & HEADCOVERSEYES) ? "helmet" : (M.wear_mask && M.wear_mask.flags_cover & MASKCOVERSEYES) ? "mask": "glasses"] first.</span>")
|
||||
return
|
||||
|
||||
var/obj/item/organ/eyes/E = M.getorganslot(ORGAN_SLOT_EYES)
|
||||
if(!E)
|
||||
to_chat(user, "<span class='danger'>[M] doesn't have any eyes!</span>")
|
||||
return
|
||||
|
||||
if(M == user) //they're using it on themselves
|
||||
if(M.flash_act(visual = 1))
|
||||
M.visible_message("[M] directs [src] to [M.p_their()] eyes.", "<span class='notice'>You wave the light in front of your eyes! Trippy!</span>")
|
||||
else
|
||||
M.visible_message("[M] directs [src] to [M.p_their()] eyes.", "<span class='notice'>You wave the light in front of your eyes.</span>")
|
||||
else
|
||||
user.visible_message("<span class='warning'>[user] directs [src] to [M]'s eyes.</span>", \
|
||||
"<span class='danger'>You direct [src] to [M]'s eyes.</span>")
|
||||
if(M.stat == DEAD || (HAS_TRAIT(M, TRAIT_BLIND)) || !M.flash_act(visual = 1)) //mob is dead or fully blind
|
||||
to_chat(user, "<span class='warning'>[M]'s pupils don't react to the light!</span>")
|
||||
else if(M.dna && M.dna.check_mutation(XRAY)) //mob has X-ray vision
|
||||
to_chat(user, "<span class='danger'>[M]'s pupils give an eerie glow!</span>")
|
||||
else //they're okay!
|
||||
to_chat(user, "<span class='notice'>[M]'s pupils narrow.</span>")
|
||||
|
||||
if(BODY_ZONE_PRECISE_MOUTH)
|
||||
|
||||
if((M.head && M.head.flags_cover & HEADCOVERSMOUTH) || (M.wear_mask && M.wear_mask.flags_cover & MASKCOVERSMOUTH))
|
||||
to_chat(user, "<span class='notice'>You're going to need to remove that [(M.head && M.head.flags_cover & HEADCOVERSMOUTH) ? "helmet" : "mask"] first.</span>")
|
||||
return
|
||||
|
||||
var/their = M.p_their()
|
||||
|
||||
var/list/mouth_organs = new
|
||||
for(var/obj/item/organ/O in M.internal_organs)
|
||||
if(O.zone == BODY_ZONE_PRECISE_MOUTH)
|
||||
mouth_organs.Add(O)
|
||||
var/organ_list = ""
|
||||
var/organ_count = LAZYLEN(mouth_organs)
|
||||
if(organ_count)
|
||||
for(var/I in 1 to organ_count)
|
||||
if(I > 1)
|
||||
if(I == mouth_organs.len)
|
||||
organ_list += ", and "
|
||||
else
|
||||
organ_list += ", "
|
||||
var/obj/item/organ/O = mouth_organs[I]
|
||||
organ_list += (O.gender == "plural" ? O.name : "\an [O.name]")
|
||||
|
||||
var/pill_count = 0
|
||||
for(var/datum/action/item_action/hands_free/activate_pill/AP in M.actions)
|
||||
pill_count++
|
||||
|
||||
if(M == user)
|
||||
var/can_use_mirror = FALSE
|
||||
if(isturf(user.loc))
|
||||
var/obj/structure/mirror/mirror = locate(/obj/structure/mirror, user.loc)
|
||||
if(mirror)
|
||||
switch(user.dir)
|
||||
if(NORTH)
|
||||
can_use_mirror = mirror.pixel_y > 0
|
||||
if(SOUTH)
|
||||
can_use_mirror = mirror.pixel_y < 0
|
||||
if(EAST)
|
||||
can_use_mirror = mirror.pixel_x > 0
|
||||
if(WEST)
|
||||
can_use_mirror = mirror.pixel_x < 0
|
||||
|
||||
M.visible_message("[M] directs [src] to [their] mouth.", \
|
||||
"<span class='notice'>You point [src] into your mouth.</span>")
|
||||
if(!can_use_mirror)
|
||||
to_chat(user, "<span class='notice'>You can't see anything without a mirror.</span>")
|
||||
return
|
||||
if(organ_count)
|
||||
to_chat(user, "<span class='notice'>Inside your mouth [organ_count > 1 ? "are" : "is"] [organ_list].</span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>There's nothing inside your mouth.</span>")
|
||||
if(pill_count)
|
||||
to_chat(user, "<span class='notice'>You have [pill_count] implanted pill[pill_count > 1 ? "s" : ""].</span>")
|
||||
|
||||
else
|
||||
user.visible_message("<span class='notice'>[user] directs [src] to [M]'s mouth.</span>",\
|
||||
"<span class='notice'>You direct [src] to [M]'s mouth.</span>")
|
||||
if(organ_count)
|
||||
to_chat(user, "<span class='notice'>Inside [their] mouth [organ_count > 1 ? "are" : "is"] [organ_list].</span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>[M] doesn't have any organs in [their] mouth.</span>")
|
||||
if(pill_count)
|
||||
to_chat(user, "<span class='notice'>[M] has [pill_count] pill[pill_count > 1 ? "s" : ""] implanted in [their] teeth.</span>")
|
||||
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/flashlight/pen
|
||||
name = "penlight"
|
||||
desc = "A pen-sized light, used by medical staff. It can also be used to create a hologram to alert people of incoming medical assistance."
|
||||
icon_state = "penlight"
|
||||
item_state = ""
|
||||
flags_1 = CONDUCT_1
|
||||
brightness_on = 2
|
||||
light_color = "#FFDDCC"
|
||||
flashlight_power = 0.3
|
||||
var/holo_cooldown = 0
|
||||
|
||||
/obj/item/flashlight/pen/afterattack(atom/target, mob/user, proximity_flag)
|
||||
. = ..()
|
||||
if(!proximity_flag)
|
||||
if(holo_cooldown > world.time)
|
||||
to_chat(user, "<span class='warning'>[src] is not ready yet!</span>")
|
||||
return
|
||||
var/T = get_turf(target)
|
||||
if(locate(/mob/living) in T)
|
||||
new /obj/effect/temp_visual/medical_holosign(T,user) //produce a holographic glow
|
||||
holo_cooldown = world.time + 100
|
||||
return
|
||||
|
||||
/obj/effect/temp_visual/medical_holosign
|
||||
name = "medical holosign"
|
||||
desc = "A small holographic glow that indicates a medic is coming to treat a patient."
|
||||
icon_state = "medi_holo"
|
||||
duration = 30
|
||||
|
||||
/obj/effect/temp_visual/medical_holosign/Initialize(mapload, creator)
|
||||
. = ..()
|
||||
playsound(loc, 'sound/machines/ping.ogg', 50, 0) //make some noise!
|
||||
if(creator)
|
||||
visible_message("<span class='danger'>[creator] created a medical hologram!</span>")
|
||||
|
||||
|
||||
/obj/item/flashlight/seclite
|
||||
name = "seclite"
|
||||
desc = "A robust flashlight used by security."
|
||||
icon_state = "seclite"
|
||||
item_state = "seclite"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi'
|
||||
force = 9 // Not as good as a stun baton.
|
||||
brightness_on = 5 // A little better than the standard flashlight.
|
||||
light_color = "#CDDDFF"
|
||||
flashlight_power = 0.9
|
||||
hitsound = 'sound/weapons/genhit1.ogg'
|
||||
|
||||
// the desk lamps are a bit special
|
||||
/obj/item/flashlight/lamp
|
||||
name = "desk lamp"
|
||||
desc = "A desk lamp with an adjustable mount."
|
||||
icon_state = "lamp"
|
||||
item_state = "lamp"
|
||||
lefthand_file = 'icons/mob/inhands/items_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/items_righthand.dmi'
|
||||
force = 10
|
||||
brightness_on = 5
|
||||
light_color = "#FFDDBB"
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
flags_1 = CONDUCT_1
|
||||
materials = list()
|
||||
on = TRUE
|
||||
|
||||
|
||||
// green-shaded desk lamp
|
||||
/obj/item/flashlight/lamp/green
|
||||
desc = "A classic green-shaded desk lamp."
|
||||
icon_state = "lampgreen"
|
||||
item_state = "lampgreen"
|
||||
|
||||
|
||||
|
||||
/obj/item/flashlight/lamp/verb/toggle_light()
|
||||
set name = "Toggle light"
|
||||
set category = "Object"
|
||||
set src in oview(1)
|
||||
|
||||
if(!usr.stat)
|
||||
attack_self(usr)
|
||||
|
||||
//Bananalamp
|
||||
/obj/item/flashlight/lamp/bananalamp
|
||||
name = "banana lamp"
|
||||
desc = "Only a clown would think to make a ghetto banana-shaped lamp. Even has a goofy pullstring."
|
||||
icon_state = "bananalamp"
|
||||
item_state = "bananalamp"
|
||||
|
||||
// FLARES
|
||||
|
||||
/obj/item/flashlight/flare
|
||||
name = "flare"
|
||||
desc = "A red Nanotrasen issued flare. There are instructions on the side, it reads 'pull cord, make light'."
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
brightness_on = 7 // Pretty bright.
|
||||
light_color = "#FA421A"
|
||||
icon_state = "flare"
|
||||
item_state = "flare"
|
||||
actions_types = list()
|
||||
var/fuel = 0
|
||||
var/on_damage = 7
|
||||
var/produce_heat = 1500
|
||||
heat = 1000
|
||||
light_color = LIGHT_COLOR_FLARE
|
||||
grind_results = list("sulfur" = 15)
|
||||
|
||||
/obj/item/flashlight/flare/New()
|
||||
fuel = rand(800, 1000) // Sorry for changing this so much but I keep under-estimating how long X number of ticks last in seconds.
|
||||
..()
|
||||
|
||||
/obj/item/flashlight/flare/process()
|
||||
open_flame(heat)
|
||||
fuel = max(fuel - 1, 0)
|
||||
if(!fuel || !on)
|
||||
turn_off()
|
||||
if(!fuel)
|
||||
icon_state = "[initial(icon_state)]-empty"
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/flashlight/flare/ignition_effect(atom/A, mob/user)
|
||||
if(fuel && on)
|
||||
. = "<span class='notice'>[user] lights [A] with [src] like a real \
|
||||
badass.</span>"
|
||||
else
|
||||
. = ""
|
||||
|
||||
/obj/item/flashlight/flare/proc/turn_off()
|
||||
on = FALSE
|
||||
force = initial(src.force)
|
||||
damtype = initial(src.damtype)
|
||||
if(ismob(loc))
|
||||
var/mob/U = loc
|
||||
update_brightness(U)
|
||||
else
|
||||
update_brightness(null)
|
||||
|
||||
/obj/item/flashlight/flare/update_brightness(mob/user = null)
|
||||
..()
|
||||
if(on)
|
||||
item_state = "[initial(item_state)]-on"
|
||||
else
|
||||
item_state = "[initial(item_state)]"
|
||||
|
||||
/obj/item/flashlight/flare/attack_self(mob/user)
|
||||
|
||||
// Usual checks
|
||||
if(!fuel)
|
||||
to_chat(user, "<span class='warning'>[src] is out of fuel!</span>")
|
||||
return
|
||||
if(on)
|
||||
to_chat(user, "<span class='notice'>[src] is already on.</span>")
|
||||
return
|
||||
|
||||
. = ..()
|
||||
// All good, turn it on.
|
||||
if(.)
|
||||
user.visible_message("<span class='notice'>[user] lights \the [src].</span>", "<span class='notice'>You light \the [src]!</span>")
|
||||
force = on_damage
|
||||
damtype = "fire"
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/flashlight/flare/is_hot()
|
||||
return on * heat
|
||||
|
||||
/obj/item/flashlight/flare/torch
|
||||
name = "torch"
|
||||
desc = "A torch fashioned from some leaves and a log."
|
||||
w_class = WEIGHT_CLASS_BULKY
|
||||
brightness_on = 4
|
||||
light_color = "#FAA44B"
|
||||
icon_state = "torch"
|
||||
item_state = "torch"
|
||||
lefthand_file = 'icons/mob/inhands/items_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/items_righthand.dmi'
|
||||
light_color = LIGHT_COLOR_ORANGE
|
||||
on_damage = 10
|
||||
slot_flags = null
|
||||
|
||||
/obj/item/flashlight/lantern
|
||||
name = "lantern"
|
||||
icon_state = "lantern"
|
||||
item_state = "lantern"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/mining_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/mining_righthand.dmi'
|
||||
desc = "A mining lantern."
|
||||
brightness_on = 6 // luminosity when on
|
||||
light_color = "#FFAA44"
|
||||
flashlight_power = 0.75
|
||||
|
||||
|
||||
/obj/item/flashlight/slime
|
||||
gender = PLURAL
|
||||
name = "glowing slime extract"
|
||||
desc = "Extract from a yellow slime. It emits a strong light when squeezed."
|
||||
icon = 'icons/obj/lighting.dmi'
|
||||
icon_state = "slime"
|
||||
item_state = "slime"
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
slot_flags = ITEM_SLOT_BELT
|
||||
materials = list()
|
||||
brightness_on = 6 //luminosity when on
|
||||
light_color = "#FFEEAA"
|
||||
flashlight_power = 0.6
|
||||
|
||||
/obj/item/flashlight/emp
|
||||
var/emp_max_charges = 4
|
||||
var/emp_cur_charges = 4
|
||||
var/charge_tick = 0
|
||||
|
||||
|
||||
/obj/item/flashlight/emp/New()
|
||||
..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/flashlight/emp/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
. = ..()
|
||||
|
||||
/obj/item/flashlight/emp/process()
|
||||
charge_tick++
|
||||
if(charge_tick < 10)
|
||||
return FALSE
|
||||
charge_tick = 0
|
||||
emp_cur_charges = min(emp_cur_charges+1, emp_max_charges)
|
||||
return TRUE
|
||||
|
||||
/obj/item/flashlight/emp/attack(mob/living/M, mob/living/user)
|
||||
if(on && user.zone_selected in list(BODY_ZONE_PRECISE_EYES, BODY_ZONE_PRECISE_MOUTH)) // call original attack when examining organs
|
||||
..()
|
||||
return
|
||||
|
||||
/obj/item/flashlight/emp/afterattack(atom/movable/A, mob/user, proximity)
|
||||
. = ..()
|
||||
if(!proximity)
|
||||
return
|
||||
|
||||
if(emp_cur_charges > 0)
|
||||
emp_cur_charges -= 1
|
||||
|
||||
if(ismob(A))
|
||||
var/mob/M = A
|
||||
log_combat(user, M, "attacked", "EMP-light")
|
||||
M.visible_message("<span class='danger'>[user] blinks \the [src] at \the [A].", \
|
||||
"<span class='userdanger'>[user] blinks \the [src] at you.")
|
||||
else
|
||||
A.visible_message("<span class='danger'>[user] blinks \the [src] at \the [A].")
|
||||
to_chat(user, "\The [src] now has [emp_cur_charges] charge\s.")
|
||||
A.emp_act(EMP_HEAVY)
|
||||
else
|
||||
to_chat(user, "<span class='warning'>\The [src] needs time to recharge!</span>")
|
||||
return
|
||||
|
||||
/obj/item/flashlight/emp/debug //for testing emp_act()
|
||||
name = "debug EMP flashlight"
|
||||
emp_max_charges = 100
|
||||
emp_cur_charges = 100
|
||||
|
||||
// Glowsticks, in the uncomfortable range of similar to flares,
|
||||
// but not similar enough to make it worth a refactor
|
||||
/obj/item/flashlight/glowstick
|
||||
name = "glowstick"
|
||||
desc = "A military-grade glowstick."
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
brightness_on = 4
|
||||
color = LIGHT_COLOR_GREEN
|
||||
icon_state = "glowstick"
|
||||
item_state = "glowstick"
|
||||
grind_results = list("phenol" = 15, "hydrogen" = 10, "oxygen" = 5) //Meth-in-a-stick
|
||||
var/fuel = 0
|
||||
|
||||
/obj/item/flashlight/glowstick/Initialize()
|
||||
fuel = rand(1600, 2000)
|
||||
light_color = color
|
||||
. = ..()
|
||||
|
||||
/obj/item/flashlight/glowstick/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
. = ..()
|
||||
|
||||
/obj/item/flashlight/glowstick/process()
|
||||
fuel = max(fuel - 1, 0)
|
||||
if(!fuel)
|
||||
turn_off()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
update_icon()
|
||||
|
||||
/obj/item/flashlight/glowstick/proc/turn_off()
|
||||
on = FALSE
|
||||
update_icon()
|
||||
|
||||
/obj/item/flashlight/glowstick/update_icon()
|
||||
item_state = "glowstick"
|
||||
cut_overlays()
|
||||
if(!fuel)
|
||||
icon_state = "glowstick-empty"
|
||||
cut_overlays()
|
||||
set_light(0)
|
||||
else if(on)
|
||||
var/mutable_appearance/glowstick_overlay = mutable_appearance(icon, "glowstick-glow")
|
||||
glowstick_overlay.color = color
|
||||
add_overlay(glowstick_overlay)
|
||||
item_state = "glowstick-on"
|
||||
set_light(brightness_on)
|
||||
else
|
||||
icon_state = "glowstick"
|
||||
cut_overlays()
|
||||
|
||||
/obj/item/flashlight/glowstick/attack_self(mob/user)
|
||||
if(!fuel)
|
||||
to_chat(user, "<span class='notice'>[src] is spent.</span>")
|
||||
return
|
||||
if(on)
|
||||
to_chat(user, "<span class='notice'>[src] is already lit.</span>")
|
||||
return
|
||||
|
||||
. = ..()
|
||||
if(.)
|
||||
user.visible_message("<span class='notice'>[user] cracks and shakes [src].</span>", "<span class='notice'>You crack and shake [src], turning it on!</span>")
|
||||
activate()
|
||||
|
||||
/obj/item/flashlight/glowstick/proc/activate()
|
||||
if(!on)
|
||||
on = TRUE
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/flashlight/glowstick/red
|
||||
name = "red glowstick"
|
||||
color = LIGHT_COLOR_RED
|
||||
|
||||
/obj/item/flashlight/glowstick/blue
|
||||
name = "blue glowstick"
|
||||
color = LIGHT_COLOR_BLUE
|
||||
|
||||
/obj/item/flashlight/glowstick/cyan
|
||||
name = "cyan glowstick"
|
||||
color = LIGHT_COLOR_CYAN
|
||||
|
||||
/obj/item/flashlight/glowstick/orange
|
||||
name = "orange glowstick"
|
||||
color = LIGHT_COLOR_ORANGE
|
||||
|
||||
/obj/item/flashlight/glowstick/yellow
|
||||
name = "yellow glowstick"
|
||||
color = LIGHT_COLOR_YELLOW
|
||||
|
||||
/obj/item/flashlight/glowstick/pink
|
||||
name = "pink glowstick"
|
||||
color = LIGHT_COLOR_PINK
|
||||
|
||||
/obj/item/flashlight/spotlight //invisible lighting source
|
||||
name = "disco light"
|
||||
desc = "Groovy..."
|
||||
icon_state = null
|
||||
light_color = null
|
||||
brightness_on = 0
|
||||
flashlight_power = 1
|
||||
light_range = 0
|
||||
light_power = 10
|
||||
alpha = 0
|
||||
layer = 0
|
||||
on = TRUE
|
||||
anchored = TRUE
|
||||
var/range = null
|
||||
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
|
||||
|
||||
/obj/item/flashlight/flashdark
|
||||
name = "flashdark"
|
||||
desc = "A strange device manufactured with mysterious elements that somehow emits darkness. Or maybe it just sucks in light? Nobody knows for sure."
|
||||
icon_state = "flashdark"
|
||||
item_state = "flashdark"
|
||||
brightness_on = 2.5
|
||||
flashlight_power = -3
|
||||
|
||||
/obj/item/flashlight/eyelight
|
||||
name = "eyelight"
|
||||
desc = "This shouldn't exist outside of someone's head, how are you seeing this?"
|
||||
brightness_on = 15
|
||||
flags_1 = CONDUCT_1
|
||||
item_flags = DROPDEL
|
||||
actions_types = list()
|
||||
@@ -0,0 +1,115 @@
|
||||
/obj/item/forcefield_projector
|
||||
name = "forcefield projector"
|
||||
desc = "An experimental device that can create several forcefields at a distance."
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "signmaker_engi"
|
||||
slot_flags = ITEM_SLOT_BELT
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
item_flags = NOBLUDGEON
|
||||
item_state = "electronic"
|
||||
lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
|
||||
materials = list(MAT_METAL=250, MAT_GLASS=500)
|
||||
var/max_shield_integrity = 250
|
||||
var/shield_integrity = 250
|
||||
var/max_fields = 3
|
||||
var/list/current_fields
|
||||
var/field_distance_limit = 7
|
||||
|
||||
/obj/item/forcefield_projector/afterattack(atom/target, mob/user, proximity_flag)
|
||||
. = ..()
|
||||
if(!check_allowed_items(target, 1))
|
||||
return
|
||||
if(istype(target, /obj/structure/projected_forcefield))
|
||||
var/obj/structure/projected_forcefield/F = target
|
||||
if(F.generator == src)
|
||||
to_chat(user, "<span class='notice'>You deactivate [F].</span>")
|
||||
qdel(F)
|
||||
return
|
||||
var/turf/T = get_turf(target)
|
||||
if(T.density)
|
||||
return
|
||||
if(get_dist(T,src) > field_distance_limit)
|
||||
return
|
||||
if(LAZYLEN(current_fields) >= max_fields)
|
||||
to_chat(user, "<span class='notice'>[src] cannot sustain any more forcefields!</span>")
|
||||
return
|
||||
var/obj/structure/projected_forcefield/same = locate() in T
|
||||
if(same)
|
||||
to_chat(user, "<span class='notice'>There is already a forcefield on [T]!</span>")
|
||||
return
|
||||
|
||||
playsound(src,'sound/weapons/resonator_fire.ogg',50,1)
|
||||
user.visible_message("<span class='warning'>[user] projects a forcefield!</span>","<span class='notice'>You project a forcefield.</span>")
|
||||
var/obj/structure/projected_forcefield/F = new(T, src)
|
||||
current_fields += F
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
|
||||
/obj/item/forcefield_projector/attack_self(mob/user)
|
||||
if(LAZYLEN(current_fields))
|
||||
to_chat(user, "<span class='notice'>You deactivate [src], disabling all active forcefields.</span>")
|
||||
for(var/obj/structure/projected_forcefield/F in current_fields)
|
||||
qdel(F)
|
||||
|
||||
/obj/item/forcefield_projector/examine(mob/user)
|
||||
..()
|
||||
var/percent_charge = round((shield_integrity/max_shield_integrity)*100)
|
||||
to_chat(user, "<span class='notice'>It is currently sustaining [LAZYLEN(current_fields)]/[max_fields] fields, and it's [percent_charge]% charged.</span>")
|
||||
|
||||
/obj/item/forcefield_projector/Initialize(mapload)
|
||||
. = ..()
|
||||
current_fields = list()
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
/obj/item/forcefield_projector/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
for(var/i in current_fields)
|
||||
qdel(i)
|
||||
return ..()
|
||||
|
||||
/obj/item/forcefield_projector/process()
|
||||
if(!LAZYLEN(current_fields))
|
||||
shield_integrity = min(shield_integrity + 4, max_shield_integrity)
|
||||
else
|
||||
shield_integrity = max(shield_integrity - LAZYLEN(current_fields), 0) //fields degrade slowly over time
|
||||
for(var/obj/structure/projected_forcefield/F in current_fields)
|
||||
if(shield_integrity <= 0 || get_dist(F,src) > field_distance_limit)
|
||||
qdel(F)
|
||||
|
||||
/obj/structure/projected_forcefield
|
||||
name = "forcefield"
|
||||
desc = "A glowing barrier, generated by a projector nearby. It could be overloaded if hit enough times."
|
||||
icon = 'icons/effects/effects.dmi'
|
||||
icon_state = "forcefield"
|
||||
layer = ABOVE_ALL_MOB_LAYER
|
||||
anchored = TRUE
|
||||
density = TRUE
|
||||
mouse_opacity = MOUSE_OPACITY_OPAQUE
|
||||
resistance_flags = INDESTRUCTIBLE
|
||||
CanAtmosPass = ATMOS_PASS_DENSITY
|
||||
armor = list("melee" = 0, "bullet" = 25, "laser" = 50, "energy" = 50, "bomb" = 25, "bio" = 100, "rad" = 100, "fire" = 100, "acid" = 100)
|
||||
var/obj/item/forcefield_projector/generator
|
||||
|
||||
/obj/structure/projected_forcefield/Initialize(mapload, obj/item/forcefield_projector/origin)
|
||||
. = ..()
|
||||
generator = origin
|
||||
|
||||
/obj/structure/projected_forcefield/Destroy()
|
||||
visible_message("<span class='warning'>[src] flickers and disappears!</span>")
|
||||
playsound(src,'sound/weapons/resonator_blast.ogg',25,1)
|
||||
generator.current_fields -= src
|
||||
generator = null
|
||||
return ..()
|
||||
|
||||
/obj/structure/projected_forcefield/CanPass(atom/movable/mover, turf/target)
|
||||
if(istype(mover) && (mover.pass_flags & PASSGLASS))
|
||||
return 1
|
||||
return !density
|
||||
|
||||
/obj/structure/projected_forcefield/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
|
||||
playsound(loc, 'sound/weapons/egloves.ogg', 80, 1)
|
||||
|
||||
/obj/structure/projected_forcefield/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir)
|
||||
if(sound_effect)
|
||||
play_attack_sound(damage_amount, damage_type, damage_flag)
|
||||
generator.shield_integrity = max(generator.shield_integrity - damage_amount, 0)
|
||||
@@ -0,0 +1,224 @@
|
||||
#define RAD_LEVEL_NORMAL 9
|
||||
#define RAD_LEVEL_MODERATE 100
|
||||
#define RAD_LEVEL_HIGH 400
|
||||
#define RAD_LEVEL_VERY_HIGH 800
|
||||
#define RAD_LEVEL_CRITICAL 1500
|
||||
|
||||
#define RAD_MEASURE_SMOOTHING 5
|
||||
|
||||
#define RAD_GRACE_PERIOD 2
|
||||
|
||||
/obj/item/geiger_counter //DISCLAIMER: I know nothing about how real-life Geiger counters work. This will not be realistic. ~Xhuis
|
||||
name = "\improper Geiger counter"
|
||||
desc = "A handheld device used for detecting and measuring radiation pulses."
|
||||
icon = 'icons/obj/device.dmi'
|
||||
icon_state = "geiger_off"
|
||||
item_state = "multitool"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
|
||||
w_class = WEIGHT_CLASS_SMALL
|
||||
slot_flags = ITEM_SLOT_BELT
|
||||
materials = list(MAT_METAL = 150, MAT_GLASS = 150)
|
||||
|
||||
var/grace = RAD_GRACE_PERIOD
|
||||
var/datum/looping_sound/geiger/soundloop
|
||||
|
||||
var/scanning = FALSE
|
||||
var/radiation_count = 0
|
||||
var/current_tick_amount = 0
|
||||
var/last_tick_amount = 0
|
||||
var/fail_to_receive = 0
|
||||
var/current_warning = 1
|
||||
|
||||
/obj/item/geiger_counter/Initialize()
|
||||
. = ..()
|
||||
START_PROCESSING(SSobj, src)
|
||||
|
||||
soundloop = new(list(src), FALSE)
|
||||
|
||||
/obj/item/geiger_counter/Destroy()
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return ..()
|
||||
|
||||
/obj/item/geiger_counter/process()
|
||||
update_icon()
|
||||
update_sound()
|
||||
|
||||
if(!scanning)
|
||||
current_tick_amount = 0
|
||||
return
|
||||
|
||||
radiation_count -= radiation_count/RAD_MEASURE_SMOOTHING
|
||||
radiation_count += current_tick_amount/RAD_MEASURE_SMOOTHING
|
||||
|
||||
if(current_tick_amount)
|
||||
grace = RAD_GRACE_PERIOD
|
||||
last_tick_amount = current_tick_amount
|
||||
|
||||
else if(!(obj_flags & EMAGGED))
|
||||
grace--
|
||||
if(grace <= 0)
|
||||
radiation_count = 0
|
||||
|
||||
current_tick_amount = 0
|
||||
|
||||
/obj/item/geiger_counter/examine(mob/user)
|
||||
..()
|
||||
if(!scanning)
|
||||
return 1
|
||||
to_chat(user, "<span class='info'>Alt-click it to clear stored radiation levels.</span>")
|
||||
if(obj_flags & EMAGGED)
|
||||
to_chat(user, "<span class='warning'>The display seems to be incomprehensible.</span>")
|
||||
return 1
|
||||
switch(radiation_count)
|
||||
if(-INFINITY to RAD_LEVEL_NORMAL)
|
||||
to_chat(user, "<span class='notice'>Ambient radiation level count reports that all is well.</span>")
|
||||
if(RAD_LEVEL_NORMAL + 1 to RAD_LEVEL_MODERATE)
|
||||
to_chat(user, "<span class='disarm'>Ambient radiation levels slightly above average.</span>")
|
||||
if(RAD_LEVEL_MODERATE + 1 to RAD_LEVEL_HIGH)
|
||||
to_chat(user, "<span class='warning'>Ambient radiation levels above average.</span>")
|
||||
if(RAD_LEVEL_HIGH + 1 to RAD_LEVEL_VERY_HIGH)
|
||||
to_chat(user, "<span class='danger'>Ambient radiation levels highly above average.</span>")
|
||||
if(RAD_LEVEL_VERY_HIGH + 1 to RAD_LEVEL_CRITICAL)
|
||||
to_chat(user, "<span class='suicide'>Ambient radiation levels nearing critical level.</span>")
|
||||
if(RAD_LEVEL_CRITICAL + 1 to INFINITY)
|
||||
to_chat(user, "<span class='boldannounce'>Ambient radiation levels above critical level!</span>")
|
||||
|
||||
to_chat(user, "<span class='notice'>The last radiation amount detected was [last_tick_amount]</span>")
|
||||
|
||||
/obj/item/geiger_counter/update_icon()
|
||||
if(!scanning)
|
||||
icon_state = "geiger_off"
|
||||
return 1
|
||||
if(obj_flags & EMAGGED)
|
||||
icon_state = "geiger_on_emag"
|
||||
return 1
|
||||
switch(radiation_count)
|
||||
if(-INFINITY to RAD_LEVEL_NORMAL)
|
||||
icon_state = "geiger_on_1"
|
||||
if(RAD_LEVEL_NORMAL + 1 to RAD_LEVEL_MODERATE)
|
||||
icon_state = "geiger_on_2"
|
||||
if(RAD_LEVEL_MODERATE + 1 to RAD_LEVEL_HIGH)
|
||||
icon_state = "geiger_on_3"
|
||||
if(RAD_LEVEL_HIGH + 1 to RAD_LEVEL_VERY_HIGH)
|
||||
icon_state = "geiger_on_4"
|
||||
if(RAD_LEVEL_VERY_HIGH + 1 to RAD_LEVEL_CRITICAL)
|
||||
icon_state = "geiger_on_4"
|
||||
if(RAD_LEVEL_CRITICAL + 1 to INFINITY)
|
||||
icon_state = "geiger_on_5"
|
||||
..()
|
||||
|
||||
/obj/item/geiger_counter/proc/update_sound()
|
||||
var/datum/looping_sound/geiger/loop = soundloop
|
||||
if(!scanning)
|
||||
loop.stop()
|
||||
return
|
||||
if(!radiation_count)
|
||||
loop.stop()
|
||||
return
|
||||
loop.last_radiation = radiation_count
|
||||
loop.start()
|
||||
|
||||
/obj/item/geiger_counter/rad_act(amount)
|
||||
. = ..()
|
||||
if(amount <= RAD_BACKGROUND_RADIATION || !scanning)
|
||||
return
|
||||
current_tick_amount += amount
|
||||
update_icon()
|
||||
|
||||
/obj/item/geiger_counter/attack_self(mob/user)
|
||||
scanning = !scanning
|
||||
update_icon()
|
||||
to_chat(user, "<span class='notice'>[icon2html(src, user)] You switch [scanning ? "on" : "off"] [src].</span>")
|
||||
|
||||
/obj/item/geiger_counter/afterattack(atom/target, mob/user)
|
||||
. = ..()
|
||||
if(user.a_intent == INTENT_HELP)
|
||||
if(!(obj_flags & EMAGGED))
|
||||
user.visible_message("<span class='notice'>[user] scans [target] with [src].</span>", "<span class='notice'>You scan [target]'s radiation levels with [src]...</span>")
|
||||
addtimer(CALLBACK(src, .proc/scan, target, user), 20, TIMER_UNIQUE) // Let's not have spamming GetAllContents
|
||||
else
|
||||
user.visible_message("<span class='notice'>[user] scans [target] with [src].</span>", "<span class='danger'>You project [src]'s stored radiation into [target]!</span>")
|
||||
target.rad_act(radiation_count)
|
||||
radiation_count = 0
|
||||
return TRUE
|
||||
|
||||
/obj/item/geiger_counter/proc/scan(atom/A, mob/user)
|
||||
var/rad_strength = 0
|
||||
for(var/i in get_rad_contents(A)) // Yes it's intentional that you can't detect radioactive things under rad protection. Gives traitors a way to hide their glowing green rocks.
|
||||
var/atom/thing = i
|
||||
if(!thing)
|
||||
continue
|
||||
var/datum/component/radioactive/radiation = thing.GetComponent(/datum/component/radioactive)
|
||||
if(radiation)
|
||||
rad_strength += radiation.strength
|
||||
|
||||
if(isliving(A))
|
||||
var/mob/living/M = A
|
||||
if(!M.radiation)
|
||||
to_chat(user, "<span class='notice'>[icon2html(src, user)] Radiation levels within normal boundaries.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='boldannounce'>[icon2html(src, user)] Subject is irradiated. Radiation levels: [M.radiation].</span>")
|
||||
|
||||
if(rad_strength)
|
||||
to_chat(user, "<span class='boldannounce'>[icon2html(src, user)] Target contains radioactive contamination. Radioactive strength: [rad_strength]</span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>[icon2html(src, user)] Target is free of radioactive contamination.</span>")
|
||||
|
||||
/obj/item/geiger_counter/attackby(obj/item/I, mob/user, params)
|
||||
if(istype(I, /obj/item/screwdriver) && (obj_flags & EMAGGED))
|
||||
if(scanning)
|
||||
to_chat(user, "<span class='warning'>Turn off [src] before you perform this action!</span>")
|
||||
return 0
|
||||
user.visible_message("<span class='notice'>[user] unscrews [src]'s maintenance panel and begins fiddling with its innards...</span>", "<span class='notice'>You begin resetting [src]...</span>")
|
||||
if(!I.use_tool(src, user, 40, volume=50))
|
||||
return 0
|
||||
user.visible_message("<span class='notice'>[user] refastens [src]'s maintenance panel!</span>", "<span class='notice'>You reset [src] to its factory settings!</span>")
|
||||
obj_flags &= ~EMAGGED
|
||||
radiation_count = 0
|
||||
update_icon()
|
||||
return 1
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/item/geiger_counter/AltClick(mob/living/user)
|
||||
if(!istype(user) || !user.canUseTopic(src, BE_CLOSE))
|
||||
return ..()
|
||||
if(!scanning)
|
||||
to_chat(usr, "<span class='warning'>[src] must be on to reset its radiation level!</span>")
|
||||
return 0
|
||||
radiation_count = 0
|
||||
to_chat(usr, "<span class='notice'>You flush [src]'s radiation counts, resetting it to normal.</span>")
|
||||
update_icon()
|
||||
|
||||
/obj/item/geiger_counter/emag_act(mob/user)
|
||||
if(obj_flags & EMAGGED)
|
||||
return
|
||||
if(scanning)
|
||||
to_chat(user, "<span class='warning'>Turn off [src] before you perform this action!</span>")
|
||||
return 0
|
||||
to_chat(user, "<span class='warning'>You override [src]'s radiation storing protocols. It will now generate small doses of radiation, and stored rads are now projected into creatures you scan.</span>")
|
||||
obj_flags |= EMAGGED
|
||||
|
||||
/obj/item/geiger_counter/cyborg
|
||||
var/datum/component/mobhook
|
||||
|
||||
/obj/item/geiger_counter/cyborg/equipped(mob/user)
|
||||
. = ..()
|
||||
if (mobhook && mobhook.parent != user)
|
||||
QDEL_NULL(mobhook)
|
||||
if (!mobhook)
|
||||
mobhook = user.AddComponent(/datum/component/redirect, list(COMSIG_ATOM_RAD_ACT = CALLBACK(src, .proc/redirect_rad_act)))
|
||||
|
||||
/obj/item/geiger_counter/cyborg/proc/redirect_rad_act(datum/source, amount)
|
||||
rad_act(amount)
|
||||
|
||||
/obj/item/geiger_counter/cyborg/dropped()
|
||||
. = ..()
|
||||
QDEL_NULL(mobhook)
|
||||
|
||||
#undef RAD_LEVEL_NORMAL
|
||||
#undef RAD_LEVEL_MODERATE
|
||||
#undef RAD_LEVEL_HIGH
|
||||
#undef RAD_LEVEL_VERY_HIGH
|
||||
#undef RAD_LEVEL_CRITICAL
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user